Concepts

File operations

Write, read, move, delete, search, list, patch, and transfer files inside the sandbox container.

SandboxHandle exposes file operation methods that cover reading, writing, patching, searching, and transferring files. All paths are inside the container.

writeFile

Write a UTF-8 string to a path inside the container. Creates parent directories automatically.

await sb.writeFile("/workspace/src/index.ts", 'export const VERSION = "1.0.0";\n');
await sb.writeFile("/tmp/config.json", JSON.stringify({ debug: true }));

readFile

Read a file from the container as a UTF-8 string:

const source = await sb.readFile("/workspace/src/index.ts");
console.log(source);

// Use the content in subsequent steps
const config = JSON.parse(await sb.readFile("/tmp/config.json"));

moveFile

Move or rename a file inside the container:

await sb.exec("mkdir -p /workspace/dist");
await sb.moveFile("/workspace/src/index.ts", "/workspace/dist/index.ts");

deleteFile

Delete a file from the container:

await sb.deleteFile("/workspace/src/util.ts");

searchFiles

Search for files matching a glob pattern. Returns an array of matching paths:

const tsFiles = await sb.searchFiles("*.ts", "/workspace/src");
console.log(tsFiles);
// ["/workspace/src/index.ts", "/workspace/src/util.ts"]

The second argument is the base path to search from. Defaults to / if omitted.

listDirectory

List entries in a directory. Returns metadata for each entry:

const entries = await sb.listDirectory("/workspace/dist");
console.log(entries.map((e) => e.path));
// ["/workspace/dist/index.ts"]

// Control recursion depth
const all = await sb.listDirectory("/workspace", { depth: 3 });

createDirectory

Create a directory (and all parents) inside the container without running exec:

await sb.createDirectory("/workspace/src");
await sb.createDirectory("/workspace/dist");

deleteDirectory

Delete a directory from the container:

await sb.deleteDirectory("/workspace/tmp");

getFileInfo

Return metadata for a file or directory — size, type, mode, owner, and timestamps:

const info = await sb.getFileInfo("/workspace/src/index.ts");
console.log(info.size); // bytes
console.log(info.type); // "file" | "directory" | "symlink"
console.log(info.mode); // unix permission bits
console.log(info.modified_at); // ISO timestamp

replaceInFiles

Replace a substring in one or more files in a single API call. More efficient than readFile → string replace → writeFile for targeted edits:

await sb.replaceInFiles([
  { path: "/app/config.json", old: "localhost", new: "0.0.0.0" },
  { path: "/app/src/version.ts", old: "0.0.0", new: "1.2.3" },
]);

transfer

Copy a file from this sandbox into another sandbox. Useful after fork() to move results between containers:

const fork = await sb.fork("after-build");

await fork.exec("npm run build");
await fork.transfer("/app/dist/bundle.js", sb); // copy back to original

await fork.close();

Pattern: patch a file

Use replaceInFiles for in-place text replacements — no exec/sed needed:

await sb.writeFile("/workspace/src/index.ts", 'export const VERSION = "0.0.0";\n');
await sb.replaceInFiles([{ path: "/workspace/src/index.ts", old: "0.0.0", new: "1.2.3" }]);
const patched = await sb.readFile("/workspace/src/index.ts");
console.log(patched.trim()); // 'export const VERSION = "1.2.3";'

Pattern: write a generated script and run it

const script = `
import sys
print(f"Python {sys.version.split()[0]}")
`.trim();

await sb.writeFile("/tmp/script.py", script);
await sb.exec("python3 /tmp/script.py").pipe(process.stdout);

File ops in the workflow builder

writeFile, readFile, deleteFile, and moveFile are available in SandboxBuilder for use in @alineo-labs/workflow (createDirectory, deleteDirectory, getFileInfo, replaceInFiles, searchFiles, listDirectory, and transfer are not queueable — call them directly on a SandboxHandle outside the workflow builder). readFile takes an extra as argument to store the result in vars:

await workflow(client)
  .sandbox({ image: "node:22", resources: { cpu: "500m", memory: "256Mi" } }, (sb) => {
    sb.writeFile("/tmp/hello.txt", "hello\n");
    sb.exec("cat /tmp/hello.txt").pipe(process.stdout);
    sb.readFile("/tmp/hello.txt", "greeting"); // → vars["greeting"]
    sb.moveFile("/tmp/hello.txt", "/tmp/moved.txt");
    sb.deleteFile("/tmp/moved.txt");
  })
  .result();