Initialize Once, Claim Many: Custom AI Agent Sandboxes on Sandbox0
The slow part of an AI agent sandbox is not always creating the sandbox.
For coding agents, data agents, browser agents, and internal automation, the hidden cost is often everything that happens after the sandbox is already alive:
- install project dependencies
- clone or fetch a repository
- warm package manager caches
- generate indexes, build artifacts, or language server state
- write local tool configuration
- prepare a workspace for task-specific execution
The usual answer is a custom template.
That is the right answer when the runtime shape changes: a different image, resource envelope, mount declaration, network default, runtime class, or privileged field. But it is a heavy answer when all you need is ordinary filesystem initialization on top of a base environment that already fits.
Every custom template can become a capacity object. If you want it to start fast, someone has to keep idle pods warm for that template. If every team, repository, branch family, or dependency set becomes its own warm pool, the platform starts paying for environment variants before users are doing work.
Sandbox0 gives you another path:
claim from a builtin template, initialize the writable root filesystem once, pause it, create a rootfs snapshot, then claim new sandboxes with that snapshot_id.
That turns a generic builtin template into a reusable initialized environment without creating a new template ID for every variation.
The Layering Matters#
Sandbox0 separates three things that are easy to collapse into one bucket:
| Layer | What it controls | Best use |
|---|---|---|
| Template | Image, resources, mount points, default network policy, warm pool behavior | Runtime shape and fast claims |
| Sandbox rootfs | Writable filesystem tied to a sandbox identity and checkpointed across pause/resume | Initialized environment state inside one sandbox shape |
| Volume | Durable storage independent of one sandbox identity | Shared workspaces, long-lived data, direct file APIs, Volume snapshots and forks |
Rootfs snapshots live in the middle layer.
They are not a replacement for templates. They do not change the base image, CPU and memory, declared mounts, default network policy, or runtime class. When you claim with snapshot_id, the requested template still controls the runtime shape while the snapshot initializes the writable rootfs.
They are also not the same as Volumes. A Volume is the durable workspace primitive when data must outlive one sandbox identity, be mounted by multiple sandboxes, or be accessed directly through Volume file APIs.
Rootfs snapshots are for a different question:
Can I reuse the initialized filesystem state of a sandbox when the template shape already fits?
For many agent workloads, the answer is yes.
Why This Exists#
Warm pools are useful because agent workloads are latency-sensitive.
Sandbox0 templates can keep idle pods ready, so a claim can reuse an already-initialized runtime instead of waiting for a cold container start. That is the right primitive for broad runtime environments: default, dins, browser-enabled templates, or organization-approved base images.
But dependency sets are often more granular than templates.
A platform may have:
- one Python base template, but hundreds of package combinations
- one Node.js base template, but many monorepo workspaces
- one Docker-in-Sandbox template, but different project setup scripts
- one agent runtime template, but different tool caches per team
You can build all of those into images and assign warm pools to each. Sometimes that is correct. But it turns setup variation into idle compute demand.
Rootfs snapshots let you keep the template pool broad and platform-owned while storing per-team or per-project initialization as filesystem state.
That is the core pattern: initialize once, claim many.
What Rootfs Snapshot And Claim Do#
Sandbox0 rootfs snapshots are point-in-time copies of a paused sandbox writable root filesystem.
The API surface is intentionally small:
POST /api/v1/sandboxes/{id}/snapshotscreates a named rootfs snapshot from a paused sandbox.GET /api/v1/sandboxes/{id}/snapshotslists snapshots for a sandbox.GET /api/v1/sandbox-rootfs-snapshots/{snapshot_id}fetches a snapshot by ID.POST /api/v1/sandboxeswithsnapshot_idclaims a new sandbox and initializes its writable rootfs from that snapshot.DELETE /api/v1/sandbox-rootfs-snapshots/{snapshot_id}deletes a named snapshot.
Creating the snapshot requires the seed sandbox to be paused. If you call it while the sandbox is running, Sandbox0 returns 409 Conflict. Pause first, then wait until the sandbox status is paused.
Claiming with snapshot_id is different: it consumes an existing rootfs snapshot and creates a new running sandbox. The requested template still controls the base image, resources, mounts, services, network defaults, and other runtime shape.
Restore and fork are still available, but they solve different problems:
POST /api/v1/sandboxes/{id}/rootfs/restorerolls an existing paused sandbox rootfs back to a snapshot.POST /api/v1/sandboxes/{id}/forkcreates a new paused sandbox from a paused source sandbox rootfs.
That paused boundary is important because Sandbox0 is working with filesystem state, not live process state. Pause checkpoints the writable rootfs and releases the runtime pod. It does not preserve cgroups, memory, sockets, PID state, or live REPL sessions. After restore or fork, resume the sandbox before using files, commands, services, SSH, or contexts again.
A Minimal Workflow#
Start from a builtin template such as default:
bashSEED_SANDBOX_ID="$(s0 -o json sandbox create --template default --hard-ttl 86400 | jq -r '.id')"
Initialize the environment inside the sandbox:
bashs0 sandbox exec "$SEED_SANDBOX_ID" -- /bin/sh -lc ' set -e python3 -m venv /workspace/.venv . /workspace/.venv/bin/activate pip install ruff pytest mkdir -p /workspace/project printf "initialized at %s\n" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > /workspace/project/ENVIRONMENT '
Pause and wait for the rootfs checkpoint to become ready:
bashs0 sandbox pause "$SEED_SANDBOX_ID" s0 sandbox get "$SEED_SANDBOX_ID"
Create a named rootfs snapshot:
bashSNAPSHOT_ID="$(s0 -o json sandbox snapshot create "$SEED_SANDBOX_ID" \ --name python-test-tools-v1 \ --description "default template with venv, ruff, and pytest" \ | jq -r '.id')"
Claim a fresh task sandbox from the same builtin template and the rootfs snapshot:
bashTASK_SANDBOX_ID="$(s0 -o json sandbox create \ --template default \ --snapshot-id "$SNAPSHOT_ID" \ --hard-ttl 3600 \ | jq -r '.id')"
At this point, the task sandbox has its own sandbox ID and writable rootfs initialized from the snapshot. Writes made in the task sandbox do not modify the seed sandbox or the immutable snapshot.
Claim, Restore, Or Fork?#
Use snapshot plus claim with snapshot_id when you need reusable custom rootfs state.
That path is good when you want to:
- give the checkpoint a stable name and description
- list and inspect available restore points
- create many fresh running sandboxes from the same initialized state
- keep an expiration metadata value for cleanup workflows
- record a known-good environment version
Use restore when you need to roll an existing paused sandbox back to a known filesystem state. Restore is destructive for the target sandbox rootfs and leaves the sandbox paused until you resume it.
Use fork when you specifically need another paused sandbox cloned from a paused source sandbox. Fork preserves the source sandbox's template and sandbox configuration while giving the child sandbox its own identity and writable rootfs head.
Deleting a snapshot does not modify any sandbox already claimed or restored from it, and it does not affect forks created from the same rootfs state.
What Happens Under the Hood#
Sandbox0 stores persistent rootfs state as filesystem heads and layer metadata.
A rootfs snapshot is an immutable pointer to one rootfs filesystem head. Claiming with snapshot_id creates a new sandbox identity, binds that sandbox's writable rootfs to the snapshot head, and applies the rootfs state before procd, file APIs, services, SSH, and contexts are initialized. Sandbox0 stores rootfs diffs in durable object storage and keeps metadata in PostgreSQL.
The useful operational detail is that each claimed task sandbox starts from the same snapshot state and diverges through later writes. The snapshot remains immutable; task-specific writes belong to the newly claimed sandbox.
That makes claim-time snapshots a practical primitive for agent branching:
- run several attempts from the same initialized workspace
- compare different prompts, models, or tool policies
- keep failed branches isolated
- discard losing branches without modifying the seed
It is the same mental model as branching a working tree, but at the sandbox rootfs layer.
Where This Helps#
Rootfs snapshots and claim-time snapshot_id fit best when your initialization is ordinary filesystem state on top of an existing template.
The same pattern powers the Sandbox0 backend for Vercel Eve: Eve prewarm runs bootstrap and seed files once, the adapter captures a Sandbox0 rootfs snapshot, and later Eve sessions claim fresh sandboxes from that snapshot. See Vercel Eve Sandbox Backend for the Eve-specific lifecycle.
Good candidates:
- Python virtual environments
- npm, pnpm, uv, pip, or cargo caches
- checked-out repositories
- generated build artifacts
- local CLIs installed into the writable filesystem
- test fixtures and lightweight seed data
- tool configuration in home directories or workspace paths
- language server indexes or project metadata that can be regenerated
For coding agents, this can remove a large chunk of per-task setup. The task sandbox can start from a workspace that already has the repository, dependency cache, and tool configuration in place.
For eval systems, this gives every run the same initialized baseline without asking every worker to rebuild that baseline.
For multi-agent search, it gives each branch an isolated filesystem while keeping source setup centralized.
Where It Does Not Help#
Rootfs snapshots are not magic templates.
Use a custom template when you need to change:
- the container image
- CPU, memory, or ephemeral storage defaults
- declared Volume mount points
- default network policy
- runtime class or privileged runtime fields
- warm process definitions
- environment defaults that should exist before any sandbox command runs
Use a Volume when state must:
- outlive one sandbox identity
- be mounted by multiple sandboxes
- be read or written without a running sandbox
- use Volume snapshot, restore, or fork APIs
- be the durable source of truth for a long-running agent
Do not use rootfs snapshots to preserve live runtime state. Running processes, memory, sockets, in-flight requests, and live REPL sessions are not preserved by rootfs snapshot, claim, restore, or fork.
The right split is usually:
- template for broad runtime shape
- rootfs snapshot plus claim with
snapshot_idfor initialized environment state - Volume for durable workspace data
- external systems for authoritative application state
The Cost Boundary#
The warm pool is the expensive part of template proliferation.
If every initialized variation becomes a template, the platform either:
- keeps too many idle pods warm, or
- accepts cold starts for long-tail environments, or
- forces users to wait for image builds and template rollout
Rootfs snapshots move many environment variations out of that capacity layer.
The platform can maintain a smaller set of high-quality builtin templates with healthy warm pools. Users can still customize the environment by writing normal filesystem state, pausing the seed sandbox, creating a snapshot, and claiming future sandboxes with that snapshot_id.
That is the product distinction:
template warm pools optimize the base runtime; rootfs snapshots preserve initialized state that new sandboxes can claim within that runtime.
You still pay for persisted rootfs state. You do not have to keep a dedicated pool of idle pods for every dependency set just to make those environments reusable.
Operational Pattern#
For production agent infrastructure, treat rootfs snapshots as versioned initialization artifacts:
- Choose the smallest builtin or custom template whose runtime shape is correct.
- Claim a seed sandbox from that template.
- Run deterministic setup commands inside the seed sandbox.
- Write a marker file with the setup version, repository commit, lockfile hash, or toolchain version.
- Pause the seed sandbox and wait for
paused. - Create a named rootfs snapshot for the initialized state.
- Claim each task sandbox with the same template and
snapshot_id. - Run task-specific work in the claimed sandbox.
- Delete obsolete snapshots and old seed or task sandboxes through a cleanup workflow.
Names matter. Use names that identify what the rootfs contains:
textpython-tools-2026-06-17 repo-api-main-9f31c2a eval-baseline-py312-v4 frontend-agent-cache-lockfile-8c0d9b
The snapshot name is not the source of truth, but it is what humans will see when they debug environment drift.
Why This Is Useful for AI Agents#
AI agents benefit from environments that feel like real workspaces.
A one-shot code runner can start empty, run a snippet, and disappear. A production coding agent usually cannot. It needs repository state, tools, dependency caches, generated files, test fixtures, and repeatable recovery points.
Custom templates solve part of that. Persistent Volumes solve another part.
Rootfs snapshots and claim-time snapshot IDs fill the gap between them:
- lighter than building a new image for every initialized variation
- more environment-shaped than a shared data Volume
- isolated enough for parallel task sandboxes
- explicit enough to claim, restore, inspect, and clean up
- compatible with platform-owned builtin template warm pools
That is why "initialize once, claim many" is a useful design pattern for AI agent infrastructure.
It lets platform teams keep the runtime surface small while giving users a practical way to customize the environment they actually run in.
Read the API workflow in Snapshot And Restore, the template tradeoff in Template, and the storage boundary in Volumes. For a Volume-focused snapshot and fork workflow, see Persistent Storage for AI Agent Sandboxes.