Execute commands in a sandbox
sb.exec, sb.shell, streaming, interactive shells, sandbox filesystem.
Once you have a Sandbox handle (from launchSandbox, runInSandbox, or connectToSandbox), you run code in it via the methods below. These are all re-exported from the microsandbox SDK — lightbox doesn’t wrap them, it just hands the handle back.
One-shot exec
sb.exec(cmd, args?) → Promise<ExecOutput>
Direct argv execution — no shell interpretation. Safest when args contain user data or paths with spaces.
const out = await sb.exec("python", ["-c", "import sys; print(sys.version)"]);
console.log(out.code); // exit code
console.log(out.success); // shorthand for code === 0
console.log(out.stdout()); // decoded UTF-8
console.log(out.stderr());
sb.shell(script) → Promise<ExecOutput>
Runs the script through sh -lc — pipes, redirects, &&, env expansion all work.
const out = await sb.shell("ls -la /work | head -5 && echo done");
console.log(out.stdout());
ExecOutput
class ExecOutput {
get code(): number;
get success(): boolean; // code === 0
stdout(): string; // decoded UTF-8
stderr(): string;
stdoutBytes(): Uint8Array; // raw bytes for binary output
stderrBytes(): Uint8Array;
}
Streaming exec
For long-running commands you want to watch live (installs, builds, tests), use the stream variants. They return an ExecHandle that’s an AsyncIterable<ExecEvent>.
sb.execStream(cmd, args?) → Promise<ExecHandle>
sb.shellStream(script) → Promise<ExecHandle>
const handle = await sb.shellStream("npm install");
for await (const event of handle) {
if (event.kind === "stdout") process.stdout.write(event.data);
else if (event.kind === "stderr") process.stderr.write(event.data);
else if (event.kind === "exited") console.log(`exited with ${event.code}`);
}
Event kinds: started (with pid), stdout / stderr (with Uint8Array data), exited (with code).
ExecHandle also exposes:
class ExecHandle implements AsyncIterable<ExecEvent> {
recv(): Promise<ExecEvent | null>; // pull one event manually
wait(): Promise<ExitStatus>; // await final exit code without iterating
collect(): Promise<ExecOutput>; // drain to an ExecOutput
kill(): Promise<void>; // SIGKILL the guest process
}
Interactive shell
sb.attachShell() → Promise<number>
Drop into an interactive shell on your terminal, wired to the guest. Returns the exit code when the shell terminates. Useful for debugging — see Debug a failed build for an end-to-end walkthrough.
const code = await sb.attachShell();
console.log("shell exited with", code);
Filesystem access
sb.fs() → SandboxFs
Read and write the guest filesystem from the host, without using cat/echo shell commands.
const fs = sb.fs();
// Whole-file convenience
const config = await fs.readToString("/etc/os-release");
const bytes = await fs.read("/usr/bin/node"); // Uint8Array
// Streaming
const stream = await fs.readStream("/var/log/big.log");
for await (const chunk of stream) {
// chunk is Uint8Array
}
const sink = await fs.writeStream("/work/output.txt");
await sink.write("hello\n");
await sink.close();
// Metadata + listing
const entries = await fs.list("/work"); // FsEntry[]
const meta = await fs.stat("/work/output.txt"); // FsMetadata
(See the microsandbox SDK source for the full SandboxFs surface — mkdir, remove, rename, etc.)