sbx.exec runs a command and waits for it. sbx.spawn starts a command and hands you a live handle. The sandbox must be running; otherwise both fail with invalid_state (409).
exec
bash -lc, so pipes, && and globs work. An array runs as-is, with no shell:
check: true to throw a CommandError (with exitCode and stderr) instead.
Options
Buffered or streamed
exec picks one of two transports:
- Buffered (
POST /v1/sandboxes/{id}/exec) when none of the conditions below apply. The command runs for at most 55 s, and 30 s if you set notimeoutMs. Stdin is at most 1 MiB, the command string at most 16 KB, and output is cut at 1 MiB per stream (stdout_truncated/stderr_truncatedsay so). - Streamed over the attach WebSocket when you pass
onStdoutoronStderr, settty, passstdinas aUint8Arrayor larger than 1 MiB, settimeoutMsabove 55000, or setmaxOutputBytes. There is no server-side time limit.timeoutMsis enforced by the SDK: it closes the session, which kills the process, and returnstimed_out: truewithexit_code-1. When you pass nostdin, the SDK closes stdin at once so commands that read it do not wait.
env travels in a request header, never in the URL.
Result
exec resolves with an ExecResult:
For binary output, read a file with
files.read or use the raw chunks from spawn.
spawn
sbx.spawn(command?, options?) opens the attach WebSocket and returns a CommandHandle at once. A string runs under bash -lc, an array runs as-is, and no command opens a login shell. It takes the same options as exec except check.
CommandHandle
Writes made before the socket opens are queued. If you pass
stdin in the options, it is written and stdin is closed for you; otherwise stdin stays open until you call closeStdin().
wait() and ready() reject with a ZodeError when the session fails: attach_failed (the socket could not open), attach_closed (it closed without an exit status, which is what kill() with no signal causes), or session_error (the sandbox ended the session with an error).
Interactive shell
exec or spawn lives only as long as its session.