Sandboxes
Run agent-generated code in an isolated VM from the TypeScript SDK
Sandboxes are experimental. The API may change without a deprecation period, and access is granted per account rather than self-served. Attaching from an account without it returns SandboxNotEnabledError.
A sandbox is a virtual machine with its own kernel and filesystem, separate from the process your agent runs in and from the cluster around it. Use one to execute code your agent generates.
Install
SandboxClient is exported from the package root and from the @astropods/adapter-core/sandbox subpath.
Client
Zero-argument construction works in a deployed agent, because Astropods injects ASTRO_AUTHZ_TOKEN and the server URL comes from that token.
Sandbox names
Every method takes the sandbox name as its first argument. The same name resolves to the same filesystem, and two names never share one. Names match ^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$.
Use the conversation or thread id, so a resumed conversation reattaches to its own files. Commands run in /workspace.
Attaching
Creates a sandbox on the first call, reuses a running one, and resumes a suspended one. The server settles concurrent first calls onto a single sandbox, so parallel tool calls do not create several.
exec, run, and spawn attach on first use, so calling attach directly is optional. sandboxClass accepts only default; any other value returns 409.
The client holds the handle and refreshes it, so an agent does not use these fields directly.
Running commands
exec
Holds one HTTP request open for the life of the command. The client bounds the command’s deadline to one second under its own request timeout, so a command cannot outlive the request waiting for it.
command is argv, so a shell line needs an explicit shell:
execCombined
Runs a shell line with stderr folded into stdout, the way a terminal shows it, so output stays interleaved.
run
Spawns the command and polls until it exits. Neither the output cap nor the request timeout applies, which suits installs, builds, and test suites.
RunResult extends ProcessOutput with two fields:
spawn
Starts a command and returns before it finishes, so the process outlives the call.
poll
Reads a process’s status and the output after the offsets you ask from. PollOptions takes stdoutFrom and stderrFrom, both number.
ProcessOutput extends ProcessStatus with:
A sandbox retains 1 MiB per stream per process and discards oldest-first beyond that. A non-zero dropped count means output was lost, not delayed.
run is this loop, so reach for poll only when the process should outlive the turn.
processes, signal, and kill
signal defaults to TERM and sends to the process group, so a shell’s children receive it too. Signal is "TERM" | "KILL" | "INT" | "HUP" | "QUIT" | "USR1" | "USR2". kill stops the process if it is still running, then forgets it.
A sandbox runs at most 64 processes, so reap what you spawn.
Files and search
listDir and grep default path to .. DirEntry is { name: string; isDirectory: boolean }. GrepMatch is { path: string; line: number; text: string }.
grep returns an empty array when nothing matches, because grep exits 1 on no match. readFile and readFileBytes throw SandboxRequestError with status 404 when the path cannot be read.
Both byte methods move data as base64 through a shell command, and writes are chunked at 48 KiB, so large files are slow.
Inspecting and ending a sandbox
get and list carry no credentials. list returns every sandbox for the deployment.
Lifecycle
An attach after reclamation succeeds and returns an empty sandbox rather than failing. Treat /workspace as scratch space and store anything that must outlive the conversation elsewhere.
Suspend and resume restore the most recent state only. There are no addressable checkpoints.
Errors
SandboxRequestError.status is 402 when a cap is reached, 404 for an unknown sandbox or unreadable path, and 502 when the sandbox could not be brought up.
Check SandboxNotEnabledError before SandboxRequestError, because it extends it.
Credentials last 15 minutes. The client re-attaches once on its own when a sandbox rejects them, so callers do not handle expiry. It does not retry a transport failure, because a command that timed out client-side may have run to completion.
A non-zero exitCode is a result, not an exception. Check the field.
Limitations
Credentials are minted for the data-plane port alone, so a service your agent starts inside a sandbox is not reachable from outside it.
Framework adapters
Both take { name } plus the SandboxClient options, and accept a client to share one instance. Each framework builds its own filesystem tools on the provider, so neither adds a separate toolset.
Mastra adapter covers the Mastra mapping in full.
Next steps
- Custom adapter (Node) covers the rest of
@astropods/adapter-core. - Usage limits covers the caps a 402 reports against.
- Managing your agents covers the environment a deployed agent receives.