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
Custom Storage Backends
Use your own database (Postgres, Redis, KV, DynamoDB) as agent storage. Implement handlers inline in the storage function.
Frontend Integration
Integrate experimental-agent agents with React using @ai-sdk/react. useChat with DefaultChatTransport, tool rendering, approval UI, status updates, stream reconnection, and type safety.