Reuse a sandbox
Keep an environment open for agent turns, commands and tests on the same files.
Open a sandbox
Section titled “Open a sandbox”Open a sandbox with createSandbox() when several operations need the same files and installed dependencies. await using closes it at the end of the scope, including when an operation throws.
The agent edits the worktree, then npm test runs in the same sandbox against its changes. How this differs from a one-shot dispatch(), and who closes what, is explained in How it works.
Run agent turns
Section titled “Run agent turns”sandbox.dispatch() takes the same brief and turn options as dispatch(), without the repository and sandbox settings. Each call starts a new conversation: continue one with sandbox.resume(id, options) or sandbox.fork(id, options) (Conversations).
An agent passed to sandbox.dispatch() replaces the one given to createSandbox().
Run a command
Section titled “Run a command”sandbox.command() runs one executable with an array of arguments. No shell parses them: *, | and $HOME reach the program as plain text. Call a shell yourself when you need one.
sandbox.root is the repository path inside the sandbox and the default working directory.
API reference: Command.
Check the outcome
Section titled “Check the outcome”A command that exits resolves with status, stdout and stderr, whatever its exit code. A command Outpost had to stop rejects instead.
| Outcome | Result |
|---|---|
| Process exits, even with status 1 | Resolves; test result.status. |
deadlineMs elapses | Rejects with an OutpostError of code timeout; on Vercel and Daytona, with a TimeoutError. |
signal aborts | Rejects with the signal’s reason. |
| The sandbox closes during the command | Rejects; the process is stopped. |
The result waits for the process to exit, not for its output to close. Read status rather than guessing success from stdout. Error codes are listed in Errors.
Stream a long command
Section titled “Stream a long command”observe shows output while the command runs. retain only bounds what the result keeps, not what observe receives.
Pass it to sandbox.command(build). Stopping a command terminates its process group and its descendants. The sandbox stays open for the next operation.
Open an interactive terminal
Section titled “Open an interactive terminal”sandbox.attach() starts the agent’s own CLI in your terminal, inside the sandbox. You work with it by hand; the call resolves when you quit, with status and the commits made during the session.
Run it from a real terminal. continuation reopens a captured conversation. The top-level attach() opens and closes its own sandbox, and applies the branch policy when the session exits with status 0.
| Provider | attach() |
|---|---|
| Docker, Podman, host | Supported |
| Daytona | Supported |
| Vercel, Firecracker | Rejected |
Attach needs a CLI agent such as Codex or Claude Code. The built-in harness, fallback agents and replay agents are rejected.
Integrate the work yourself
Section titled “Integrate the work yourself”A sandbox you create never merges its branch on its own. With branch: { mode: "integrate" }, call sandbox.workspace.integrate() before closing to merge the work branch into its base.
With other branch modes, integrate() does nothing. A merge conflict, or a host branch switched during the run, rejects with code conflict and keeps the worktree. close({ preserve: true }) also keeps it for inspection (Recover work).
Limits
Section titled “Limits”- A sandbox runs one operation at a time: a second call made while one runs is rejected, not queued. Use separate sandboxes for parallel work.
- Output is captured as text. Move binary files with the provider’s transfer methods (Cloud sandboxes).
API: createSandbox · Sandbox · Command · CommandResult · AttachOptions · attach.