Guides

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 dependenciesnpm 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

Pass setup options directly to the binding factory. The sandbox is automatically set up when the session starts:

src/agent.ts
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:

src/session.ts
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

  1. First run (cold start) — No snapshot exists. run executes on a fresh sandbox.
  2. Snapshot — After run completes, the sandbox state is snapshotted.
  3. Subsequent sessions — Restore from the snapshot. run does not run again.
  4. Invalidation — Change version to force a new snapshot. The next cold start will re-run run.

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:

src/agent.ts
const myAgent = agent("my-agent", {
  sandbox: [vercelSandbox(), localSandbox()],
});
src/session.ts
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. VercelBindingConfig for Vercel, LocalBindingConfig for 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:

MethodReturnsDescription
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:

MethodDescription
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