Long-lived sandboxes
Create one isolated workspace, run many commands, checkpoint it, and release it safely.
Use a long-lived sandbox when one workflow needs the same filesystem across many commands. Create the box once instead of paying pod creation and setup on every turn.
| Need | Use |
|---|---|
| Interactive agent/dev loop | Long-lived sandbox |
| Re-run tests in the same workspace | Long-lived sandbox verify |
| One short snippet | CodeEdit |
| Benchmark task, verifier, pass@k | Harbor datapoint |
| Free-form one-shot agent instruction | Agent Runtime |
Not for pass@k
Pass@k attempts must be independent. Do not attach multiple attempts to the same sandbox or carry files, conversation state, or answers between them.
Lifecycle
The service runs one gVisor pod plus a PVC in the sandbox-jobs namespace.
Kubernetes objects are runtime truth; GCS checkpoints hold durable workspace
bytes. Redis is a lookup and quota store, not the durable workspace.
Create
curl -sS -X POST \
-H "X-Api-Key: $SANDBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profile": "sandboxes-default",
"autostop_sec": 1800,
"ttl_sec": 14400
}' \
"$SANDBOX_GATEWAY_URL/sandbox/sandboxes/v1"The response contains sandbox_id. Keep it for every later call. A create or
start consumes one L2 concurrency slot for the authenticated
tenant:project; when the project is full, the API returns 429 and
Retry-After.
You may bootstrap from an HTTPS archive, a permitted GCS prefix, or a prior snapshot:
{
"profile": "sandboxes-default",
"source": {
"archive_url": "https://storage.example/task.zip"
}
}The source is fetched once. Later exec calls use the PVC; they do not download the archive again.
Exec in the same workspace
curl -sS -X POST \
-H "X-Api-Key: $SANDBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"command":["bash","-lc","python -m pytest -q"],"timeout_sec":300}' \
"$SANDBOX_GATEWAY_URL/sandbox/sandboxes/v1/$SANDBOX_ID/exec"Each exec uses the same pod and filesystem until the sandbox is stopped, destroyed, expires, or is reaped for idleness.
Continue with an agent
For an ungraded interactive loop, a native Sandbox agent can attach to the running session:
{
"agent_id": "opencode",
"model": "wandb/moonshotai/Kimi-K2.5",
"instruction": "Continue from the current files and fix the next failure",
"sandbox_id": "your-sandbox-id"
}Submit that body to POST /sandbox/agent/v1/runs with the same tenant/project
credential. The agent uploads its instruction/config into the existing
workspace, runs there, and leaves the sandbox alive.
The session image must already contain the selected agent CLI. An attached run
cannot rebuild a running sandbox image. Only catalog agents with
integration: sandbox support this path.
sandbox_id with pass_at_k > 1 is rejected. Use Harbor for independent,
graded attempts.
Stop, start, and destroy
# Release compute and checkpoint the workspace.
curl -sS -X POST -H "X-Api-Key: $SANDBOX_API_KEY" \
"$SANDBOX_GATEWAY_URL/sandbox/sandboxes/v1/$SANDBOX_ID/stop"
# Restore the workspace and acquire quota again.
curl -sS -X POST -H "X-Api-Key: $SANDBOX_API_KEY" \
"$SANDBOX_GATEWAY_URL/sandbox/sandboxes/v1/$SANDBOX_ID/start"
# Remove the runtime; the service checkpoints before deletion.
curl -sS -X DELETE -H "X-Api-Key: $SANDBOX_API_KEY" \
"$SANDBOX_GATEWAY_URL/sandbox/sandboxes/v1/$SANDBOX_ID"Default auto-stop is 30 minutes on dev. Always destroy a sandbox you no longer need; idle sessions hold storage and, while running, one project concurrency slot.
Warm sessions vs warm nodes
These solve different waits:
| Pool | Holds | Benefit |
|---|---|---|
| Session warm pool | Ready pod + PVC for a profile | Faster create/claim |
| Node warm placeholders | Empty gVisor node capacity | Avoids node scale-up |
Neither makes model reasoning faster. They reduce time before the agent can start work.
Tenancy
Ownership comes from the authenticated principal, not a caller-supplied
tenant header. List/get/exec/files/stop/start/destroy only expose sandboxes in
the same tenant:project. Platform callers acting for a project must carry
that scope on every request.
See Caching and reuse for the boundary between workspace reuse and independent evaluation.
Operations (cluster)
Attached agent runs on the harbor-worker call the sandboxes API through the
in-cluster gateway (SANDBOX_GATEWAY_URL=http://sandbox-gateway:8780) using the
worker’s SANDBOX_API_KEY from sandbox-runtime, with per-job
X-Sandbox-Tenant-Id / X-Sandbox-Project-Id headers. After deploy, confirm:
kubectl -n sandbox exec deploy/sandbox-harbor-worker -- printenv SANDBOX_GATEWAY_URL