Long-lived sandboxes
Create one isolated workspace, run many commands, checkpoint it — pod or desktop substrate.
Use a long-lived sandbox when one workflow needs the same filesystem across many commands. Create the box once instead of paying setup on every turn.
| Need | Use |
|---|---|
| Interactive agent/dev loop | Long-lived sandbox (sandboxes-default) |
| Re-run tests in the same workspace | Long-lived sandbox verify |
| GUI desktop in the browser | Desktop sandboxes (desktop-*) |
| One short snippet | CodeEdit |
| Benchmark + verifier | Harbor |
| Free-form one-shot agent | Agent runs |
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.
Profiles and substrates
The same POST /sandbox/sandboxes/v1 API serves headless workspaces and desktops.
The profile picks the substrate:
| Profile | Substrate | GUI? |
|---|---|---|
sandboxes-default | Kubernetes pod + PVC | No — exec/files API |
desktop-ubuntu | Kubernetes pod + noVNC | Yes |
desktop-windows | EC2 VM + Guacamole | Yes |
desktop-macos | External Mac cloud | Yes |
This page covers the headless path (sandboxes-default). For GUI profiles see
Desktop sandboxes.
Lifecycle
For sandboxes-default, the service runs one pod plus a PVC in the trial
namespace. Kubernetes objects are runtime truth; object storage holds durable
workspace checkpoints. 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 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 filesystem until the sandbox is stopped, destroyed, expires, or is reaped for idleness.
Continue with an agent
Attach a catalog agent with integration: sandbox (for example opencode) 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 to POST /sandbox/agent/v1/runs with the same tenancy. The session image
must already contain that agent CLI. sandbox_id with pass_at_k > 1 is
rejected. Agent list: Supported agents.
Stop, start, and destroy
curl -sS -X POST -H "X-Api-Key: $SANDBOX_API_KEY" \
"$SANDBOX_GATEWAY_URL/sandbox/sandboxes/v1/$SANDBOX_ID/stop"
curl -sS -X POST -H "X-Api-Key: $SANDBOX_API_KEY" \
"$SANDBOX_GATEWAY_URL/sandbox/sandboxes/v1/$SANDBOX_ID/start"
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. Destroy sandboxes you no longer need — idle sessions hold storage and, while running, a concurrency slot.
Lifetime: idle stop, TTL, and extending
Two clocks end a session:
| Clock | Field | What happens |
|---|---|---|
| Idle | autostop_sec (default 1800) | Stopped after this long without activity. Workspace is checkpointed; start resumes. 0 = never idle-stop. |
| Absolute | expires_at (create: now + ttl_sec, default 86400) | Destroyed. A final checkpoint is taken first and snapshots are kept (SANDBOX_SNAPSHOT_RETENTION_SEC, default 30 days). If that checkpoint cannot be taken, the workspace volume is retained (labelled sandbox.turing.com/retained=true) instead of deleted. |
Activity is any API call on the sandbox (exec, files, capture, …) and traffic through the viewer / IDE proxy (throttled to one touch per minute per sandbox).
Extend a long-running session instead of recreating it:
# New lifetime counted from now (may shorten or extend), and never idle-stop
curl -sS -X PATCH -H "X-Api-Key: $SANDBOX_API_KEY" -H "Content-Type: application/json" \
-d '{"ttl_sec": 604800, "autostop_sec": 0}' \
"$SANDBOX_GATEWAY_URL/sandbox/sandboxes/v1/$SANDBOX_ID"
# Or an absolute expiry (ISO 8601; naive = UTC)
curl -sS -X PATCH -H "X-Api-Key: $SANDBOX_API_KEY" -H "Content-Type: application/json" \
-d '{"expires_at": "2026-12-01T00:00:00Z"}' \
"$SANDBOX_GATEWAY_URL/sandbox/sandboxes/v1/$SANDBOX_ID"
# Heartbeat between agent turns (resets the idle clock; 409 when not running)
curl -sS -X POST -H "X-Api-Key: $SANDBOX_API_KEY" \
"$SANDBOX_GATEWAY_URL/sandbox/sandboxes/v1/$SANDBOX_ID/touch"Each grant is capped by the profile max_ttl_sec (default 30 days, catalog
infra/catalog/profiles/*.yaml; operators may override per tenant with
SANDBOX_TENANT_MAX_TTL_SEC). Larger values are clamped, not rejected: the
response carries the effective expires_at plus a warnings list. ttl_sec on
the record is always expires_at - created_at.
reuse: true with a larger ttl_sec extends the reused sandbox (TTL only grows)
and replaces autostop_sec with the requested value.
Session pods carry a PodDisruptionBudget, safe-to-evict: "false" and a
sandbox-session PriorityClass, so routine node drains wait for them. GKE still
proceeds with an upgrade after about an hour, so keep the workspace checkpointed.
Warm sessions vs warm nodes
| 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 speeds up model reasoning.
Tenancy
Ownership comes from the authenticated principal. List/get/exec only expose
sandboxes in the same tenant:project.
See Caching and reuse and Architecture.