Skip to main content
Run commands inside a running sandbox: collect output in one shot, stream it as it arrives, attach an interactive PTY, or pipe data to stdin. These methods live on a running Sandbox. See Commands for usage examples.

Typical flow

import { Sandbox } from "microsandbox";

const sandbox = await Sandbox.create("api", { image: "python" });

// 1. one-shot
const out = await sandbox.exec("python3", ["-c", "print(1 + 1)"]);
console.log(out.stdout()); // "2\n"

// 2. stream
const handle = await sandbox.execStream("tail", ["-f", "/var/log/app.log"]);
for await (const event of handle) {
  if (event.kind === "stdout") process.stdout.write(event.data);
  if (event.kind === "exited") break;
}

await sandbox.stop();

Run and collect

sandbox.exec()

exec(cmd: string, args?: Iterable<string>): Promise<ExecOutput>
const result = await sandbox.exec("python3", ["-c", "print(1 + 1)"]);
console.log(result.stdout()); // "2\n"
console.log(result.code);     // 0
Run a command inside the sandbox and wait for it to complete. Collects all stdout and stderr into memory and returns them along with the exit code. For long-running processes or large output, use execStream() instead.

Parameters

cmdstring
Command to execute (e.g. “python3”, “/usr/bin/node”).
args?Iterable<string>
Command arguments (e.g. [“-c”, “print(‘hello’)”]).

Returns

Collected stdout, stderr, and exit status.

sandbox.execWith()

execWith(
  cmd: string,
  configure: (b: ExecOptionsBuilder) => ExecOptionsBuilder,
): Promise<ExecOutput>
const out = await sandbox.execWith("python3", (e) =>
  e.args(["script.py"])
    .cwd("/app")
    .env("PYTHONPATH", "/app/lib")
    .timeout(30_000),
);
Run a command with per-execution overrides. Configure working directory, environment variables, timeout, stdin, TTY allocation, and rlimits via the builder callback. These overrides apply only to this execution and don’t change the sandbox’s defaults.

Parameters

cmdstring
Command to execute.
Builder callback for per-call overrides.

Returns

Collected stdout, stderr, and exit status.

sandbox.shell()

shell(script: string): Promise<ExecOutput>
const out = await sandbox.shell("ls -la /app && echo done");
console.log(out.stdout());
Run a command through the sandbox’s configured shell (defaults to /bin/sh). Shell syntax like pipes, redirects, and && chains works.

Parameters

scriptstring
Shell command string (e.g. “ls -la /app && echo done”).

Returns

Collected stdout, stderr, and exit status.

sandbox.attachShell()

attachShell(): Promise<number>
const code = await sandbox.attachShell();
Bridge your terminal to the sandbox’s default shell in a fully interactive PTY session.

Returns

Promise<number>
Exit code of the shell process.

Stream and attach

sandbox.execStream()

execStream(cmd: string, args?: Iterable<string>): Promise<ExecHandle>
const handle = await sandbox.execStream("tail", ["-f", "/var/log/app.log"]);
for await (const event of handle) {
  if (event.kind === "stdout") process.stdout.write(event.data);
  if (event.kind === "exited") break;
}
Run a command with streaming output. Returns a handle that emits stdout, stderr, and exit events as they happen, rather than buffering everything.

Parameters

cmdstring
Command to execute.
args?Iterable<string>
Command arguments.

Returns

Streaming handle for receiving events and controlling the process.

sandbox.execStreamWith()

execStreamWith(
  cmd: string,
  configure: (b: ExecOptionsBuilder) => ExecOptionsBuilder,
): Promise<ExecHandle>
const handle = await sandbox.execStreamWith("python3", (e) =>
  e.args(["-u", "worker.py"]).env("LEVEL", "debug").stdinPipe(),
);
const stdin = await handle.takeStdin();
await stdin?.write("task-1\n");
Streaming variant of execWith(): same configuration via ExecOptionsBuilder, but returns an ExecHandle instead of buffering output.

Parameters

cmdstring
Command to execute.
Builder callback for per-call overrides.

Returns

Streaming handle.

sandbox.shellStream()

shellStream(script: string): Promise<ExecHandle>
const handle = await sandbox.shellStream("for i in 1 2 3; do echo $i; sleep 1; done");
for await (const event of handle) {
  if (event.kind === "stdout") process.stdout.write(event.data);
}
Run a shell command with streaming output.

Parameters

scriptstring
Shell command string.

Returns

Streaming handle.

sandbox.attach()

attach(cmd: string, args?: Iterable<string>): Promise<number>
const code = await sandbox.attach("python3");
Bridge your terminal directly to a process inside the sandbox for a fully interactive PTY session. Press Ctrl+] (or configured detach keys) to disconnect without stopping the process.

Parameters

cmdstring
Command to run.
args?Iterable<string>
Command arguments.

Returns

Promise<number>
Exit code of the process.

sandbox.attachWith()

attachWith(
  cmd: string,
  configure: (b: AttachOptionsBuilder) => AttachOptionsBuilder,
): Promise<number>
const code = await sandbox.attachWith("bash", (a) =>
  a.cwd("/app")
    .env("EDITOR", "vim")
    .detachKeys("ctrl-]"),
);
Interactive PTY attach with options for arguments, environment variables, working directory, user, custom detach keys, and rlimits. Configure via the builder callback.

Parameters

cmdstring
Command to run.
Builder callback for the attach session.

Returns

Promise<number>
Exit code of the process.

Types

ExecOutput

Returned by exec() · execWith() · shell() · ExecHandle.collect()

The result of a completed command execution: collected output plus exit status.
Property / MethodTypeDescription
codenumber (getter)Process exit code
successboolean (getter)true when code === 0
statusExitStatus (getter)Exit status object
stdout()stringCollected stdout decoded as UTF-8 (lossy on invalid sequences)
stderr()stringCollected stderr decoded as UTF-8 (lossy on invalid sequences)
stdoutBytes()Uint8ArrayRaw stdout bytes
stderrBytes()Uint8ArrayRaw stderr bytes

ExecHandle

Returned by execStream() · execStreamWith() · shellStream()

A handle to a running streaming execution. Implements AsyncIterable<ExecEvent> and AsyncDisposable, so it works with for await...of and await using.
Property / MethodTypeDescription
recv()Promise<ExecEvent | null>Receive the next event, or null once the stream ends
takeStdin()Promise<ExecSink | null>Take ownership of the stdin sink. Returns null after the first call
wait()Promise<ExitStatus>Wait for the process to exit
collect()Promise<ExecOutput>Drain stdout/stderr and wait for exit
signal(signal)Promise<void>Send a POSIX signal (numeric) to the process
kill()Promise<void>Force-terminate the process
[Symbol.asyncIterator]()AsyncIterator<ExecEvent>Iterate events with for await...of
[Symbol.asyncDispose]()Promise<void>Best-effort kill on await using scope exit

ExecSink

Returned by ExecHandle.takeStdin()

Writer for sending data to a running process’s stdin. Implements AsyncDisposable. Obtained from ExecHandle.takeStdin() when the execution was configured with .stdinPipe().
MethodTypeDescription
write(data)(data: Uint8Array | string) => Promise<void>Write bytes to the process’s stdin. Strings are UTF-8 encoded
close()() => Promise<void>Send EOF. Idempotent
[Symbol.asyncDispose]()() => Promise<void>Calls close() on await using scope exit

ExecEvent

Emitted by ExecHandle

Discriminated union emitted while iterating an ExecHandle. The discriminator is kind.
type ExecEvent =
  | { kind: "started"; pid: number }
  | { kind: "stdout"; data: Uint8Array }
  | { kind: "stderr"; data: Uint8Array }
  | { kind: "exited"; code: number };
kindPayloadDescription
"started"pid: numberThe process has started
"stdout"data: Uint8ArrayA chunk of stdout data
"stderr"data: Uint8ArrayA chunk of stderr data
"exited"code: numberThe process has exited

ExitStatus

Returned by ExecHandle.wait() · ExecOutput.status

The exit result of a process.
FieldTypeDescription
codenumberProcess exit code
successbooleantrue when code === 0

ExecOptionsBuilder

Used by execWith() · execStreamWith()

Fluent builder passed to the callback in execWith(cmd, b => ...) and execStreamWith(cmd, b => ...). Every setter mutates the builder and returns it, so calls chain.
MethodTypeDescription
arg(arg)(arg: string) => thisAppend a single argument
args(args)(args: string[]) => thisAppend many arguments
cwd(cwd)(cwd: string) => thisWorking directory
user(user)(user: string) => thisGuest user
env(key, value)(key: string, value: string) => thisAdd a single env var
envs(vars)(vars: Record<string, string>) => thisAdd many env vars
timeout(ms)(ms: number) => thisKill the process after this many milliseconds
stdinNull()() => thisConnect stdin to /dev/null (default)
stdinPipe()() => thisOpen a writable stdin pipe; read it back with ExecHandle.takeStdin()
stdinBytes(data)(data: Buffer) => thisPre-supply stdin bytes and close it
tty(enabled)(enabled: boolean) => thisAllocate a pseudo-terminal
rlimit(resource, limit)(resource: RlimitResource, limit: number) => thisSet both soft and hard rlimit
rlimitRange(resource, soft, hard)(resource: RlimitResource, soft: number, hard: number) => thisSet distinct soft and hard rlimits

AttachOptionsBuilder

Used by attachWith()

Fluent builder passed to the callback in attachWith(cmd, b => ...). Every setter mutates the builder and returns it, so calls chain.
MethodTypeDescription
arg(arg)(arg: string) => thisAppend a single argument
args(args)(args: string[]) => thisAppend many arguments
cwd(cwd)(cwd: string) => thisWorking directory
user(user)(user: string) => thisGuest user
env(key, value)(key: string, value: string) => thisAdd a single env var
envs(vars)(vars: Record<string, string>) => thisAdd many env vars
detachKeys(spec)(spec: string) => thisDetach key sequence (e.g. "ctrl-]" or "ctrl-p,ctrl-q")
rlimit(resource, limit)(resource: RlimitResource, limit: number) => thisSet both soft and hard rlimit
rlimitRange(resource, soft, hard)(resource: RlimitResource, soft: number, hard: number) => thisSet distinct soft and hard rlimits

Stdin

Produces StdinMode

Helper factory for constructing a StdinMode. Equivalent to the stdinNull / stdinPipe / stdinBytes setters on ExecOptionsBuilder.
MethodTypeDescription
Stdin.null()() => StdinModeConnect stdin to /dev/null
Stdin.pipe()() => StdinModeOpen a writable pipe; caller writes via ExecHandle.takeStdin()
Stdin.bytes(data)(data: Uint8Array | string) => StdinModeSend the given bytes (or UTF-8-encoded string) and close stdin

StdinMode

Produced by Stdin

Discriminated union describing stdin behavior for an execution.
type StdinMode =
  | { kind: "null" }
  | { kind: "pipe" }
  | { kind: "bytes"; data: Uint8Array };
kindPayloadDescription
"null"-Stdin connected to /dev/null
"pipe"-Writable pipe opened for the caller
"bytes"data: Uint8ArrayPre-supplied stdin bytes, then EOF

Rlimit

Set via ExecOptionsBuilder.rlimit() · AttachOptionsBuilder.rlimit()

A POSIX resource limit applied to the process.
FieldTypeDescription
resourceRlimitResourceWhich resource is limited
softnumberSoft limit
hardnumberHard limit

RlimitResource

Used by Rlimit.resource · rlimit() · rlimit()

String union naming a limitable POSIX resource.
type RlimitResource =
  | "cpu" | "fsize" | "data" | "stack" | "core" | "rss"
  | "nproc" | "nofile" | "memlock" | "as" | "locks"
  | "sigpending" | "msgqueue" | "nice" | "rtprio" | "rttime";