Sandbox Setup & Snapshots
One-time setup with version and run, snapshot-based fast resume, network policies, exposed ports, and lifecycle management.
By default, each session gets a fresh sandbox. For agents that need pre-installed dependencies, cloned repos, or a configured environment, use sandbox.setup() to initialize once. The sandbox state is snapshotted after setup completes, and subsequent sessions restore from the snapshot.
Why Sandbox Setup
- Install dependencies —
npm install,pip install, or system packages - Clone repos — Pre-populate the workspace before the agent runs
- Configure environment — Set env vars, create config files
- Fast startup — After setup completes, the sandbox is snapshotted; subsequent sessions restore from the snapshot instead of re-running setup
Setup Configuration
Inline defaults (recommended)
Pass setup options directly to the binding factory. The sandbox is automatically set up when the session starts:
import { agent } from "experimental-agent";
import { vercelSandbox } from "experimental-agent/sandbox";
export const myAgent = agent("my-agent", {
model: "anthropic/claude-opus-4.6",
sandbox: vercelSandbox({
version: "my-env-v3",
run: async (sandbox) => {
await sandbox.exec({ command: "npm", args: ["install", "-g", "typescript"] });
await sandbox.exec({ command: "git", args: ["clone", "https://github.com/my/repo.git"] });
},
}),
});All three bindings accept the same defaults: version, run, config, and networkPolicy.
Explicit setup
For cases where you need more control (e.g. dynamic sandbox IDs or conditional setup), call .setup() on a sandbox handle:
const sb = myAgent.sandbox("my-sandbox");
await sb.setup({
version: "my-env-v3",
run: async (sandbox) => {
await sandbox.exec({ command: "npm", args: ["install", "-g", "typescript"] });
await sandbox.exec({ command: "git", args: ["clone", "https://github.com/my/repo.git"] });
},
});Options passed to .setup() override any defaults set on the binding factory.
version— A string that identifies this setup. Bump it (e.g."my-env-v3"to"my-env-v4") to invalidate the snapshot and re-run setup.run— An async function that receives the sandbox instance. Run any commands needed to prepare the environment.
How Snapshots Work
- First run (cold start) — No snapshot exists.
runexecutes on a fresh sandbox. - Snapshot — After
runcompletes, the sandbox state is snapshotted. - Subsequent sessions — Restore from the snapshot.
rundoes not run again. - Invalidation — Change
versionto force a new snapshot. The next cold start will re-runrun.
This keeps startup fast while allowing you to update the environment when dependencies or config change.
Binding-Specific Config
When your agent has multiple bindings or you need to pass binding-specific options, use type and config:
const myAgent = agent("my-agent", {
sandbox: [vercelSandbox(), localSandbox()],
});const sb = myAgent.sandbox("my-sandbox");
await sb.setup({
type: "vercel",
version: "v1",
config: {
ports: [3000],
resources: { vcpus: 4 },
},
run: async (sandbox) => {
await sandbox.exec({ command: "npm", args: ["install"] });
},
});type— Selects which binding to use when the agent has multiple bindings configured.config— Binding-specific options (e.g.VercelBindingConfigfor Vercel,LocalBindingConfigfor local).
Network Policies
Control outbound network access. Vercel sandboxes support network policies:
await sandbox.updateNetworkPolicy({ policy: { allow: ["github.com", "*.npmjs.org"] } });
await sandbox.updateNetworkPolicy({ policy: "deny-all" });
await sandbox.updateNetworkPolicy({ policy: "allow-all" });{ allow: ["domain.com"] }— Allow only listed domains (supports wildcards like*.npmjs.org)"deny-all"— Block all outbound traffic"allow-all"— Allow all (default)
You can also set network policy in the setup config:
await sb.setup({
type: "vercel",
networkPolicy: { allow: ["github.com"] },
});Exposed Ports and Domains
Expose ports for dev servers or web apps via the Vercel binding config:
await sb.setup({
type: "vercel",
config: { ports: [3000, 8080] },
});Then get the public URL for a port:
const url = await sandbox.getDomain({ port: 3000 });
// e.g. "https://abc123.sandbox.vercel.app"Lifecycle Management
Sandbox instances expose lifecycle methods directly:
| Method | Returns | Description |
|---|---|---|
start() | Promise<void> | Start the sandbox. |
stop() | Promise<void> | Stop the sandbox. |
snapshot() | Promise<{ snapshotId: string }> | Create a snapshot for fast resume. |
getStatus() | Promise<SandboxStatus> | Returns pending, running, stopping, stopped, or failed. |
const status = await sandbox.getStatus();
if (status === "running") {
await sandbox.snapshot();
}Sandbox API Reference
Inside setup.run or custom tools (via ToolContext), the sandbox exposes:
| Method | Description |
|---|---|
exec({ command, args?, cwd?, env?, sudo?, signal? }) | Run a shell command. Returns ExecResult with stdout, stderr, exit code. |
readFile({ path, signal? }) | Read file contents. Returns Buffer | null. |
writeFiles({ files, destPath, signal? }) | Write multiple files to a destination path. |
getDomain({ port, signal? }) | Get the public domain URL for an exposed port. |
kill({ commandId, signal? }) | Kill a running command by ID. |
updateNetworkPolicy({ policy, signal? }) | Update network policy at runtime (Vercel only). |
Next Steps
- Sandbox Bindings — Binding factories and full SandboxInstance reference
- Sandbox — Sandbox types, API, and conceptual overview
- Tools — Built-in tools that run in the sandbox
- Storage — Where sandbox records and setup snapshots are persisted