Manage sandbox lifecycle
Create, keep, reconnect to, list, suspend and delete sandboxes, run many at once, and keep local disk use bounded.
Sandboxes run on this machine by default, so the examples pass no location.
To use your own cloud, pass
on="aws" (or "gcp", "modal") to Sandbox.create.
Ephemeral or kept#
from cua_sandbox import Image, Sandbox
# Deleted when the block exits.
async with Sandbox.ephemeral(Image.linux()) as sb:
...
# Kept until you delete it.
sb = await Sandbox.create(Image.linux(), name="dev")
await sb.disconnect() # the sandbox keeps runningDisconnecting never stops a sandbox. A connection and a sandbox have separate lifetimes.
Inspect#
print(sb.id) # its ref, like local:dev: what connect() and delete() take
info = await sb.info()
info.status # provisioning, starting, ready or stopped
info.location # local, direct or the cloud you chose
info.services # {"web": 8000, ...}
info.provider_details # backend internals (for example the local runtime)| Status | Meaning |
|---|---|
provisioning | Capacity is being found or created (image pull) |
starting | Booting, or wait_for probes have not passed yet |
ready | Running and every probe passed |
stopped | Exited, suspended or released |
Refs are local:<name>, aws:<name> (also gcp: and modal:) or direct:<host:port>. A bare name
works when it is unique; otherwise the call raises AmbiguousSandbox.
Reconnect, list, delete#
sb = await Sandbox.connect("dev")
for s in await Sandbox.list():
print(s.name, s.status, s.location)
await Sandbox.suspend("dev")
sb = await Sandbox.resume("dev")
await Sandbox.delete("dev")await sb.destroy() deletes the sandbox you hold. Suspend, resume and restart
are local only: elsewhere suspend and restart raise Unsupported, and
resume of a running sandbox reconnects. The CLI and the SDK share local state
in ~/.cua/sandboxes, so either can reconnect to the other's sandboxes.
cua sb create linux --name dev
cua sb ls # every location; --local filters
cua sb info dev
cua sb suspend dev && cua sb resume dev
cua sb rm dev -fLocal sandboxes run until you delete them. In your own cloud, a sandbox deletes itself at its time limit.
Run many at once#
Sandbox.ephemeral is async, so asyncio.gather runs sandboxes in parallel.
Cap concurrency with an asyncio.Semaphore (every local sandbox uses host CPU,
memory and disk) and pass return_exceptions=True so one failure does not
cancel the rest.
Keep sandboxes ready (pools)#
A local create restores a snapshot when the image has one (under a second for
gVisor containers) and boots otherwise. When creates of one shape repeat, the
cua daemon keeps a few sandboxes of that shape ready on its own and a create
takes one in about 0.1 s; cua daemon status says what it keeps and why. It
keeps none for one-off creates, on battery, or when memory is short.
A pool asks for ready sandboxes explicitly: min of them at all times (one
starts again as soon as one is taken), up to max while creates come faster
than sandboxes start, and none after idle without a create. Pools run on
this machine, are kept by the cua daemon (cua daemon start) and survive its
restarts.
from cua_sandbox import Image, Sandbox, create_pool
pool = await create_pool(Image.linux(), name="agents", min=2, max=8, idle=600)
sb = await pool.create() # or Sandbox.create(pool="agents")
await sb.shell.run("uname -a")
await sb.destroy() # the pool starts a replacement
await pool.delete()cua sb pool create linux --name agents --min 2 --max 8 --idle 10m
cua sb create --pool agents --name a1
cua sb pool ls
cua sb pool rm agents- A create from a pool gets the pool's image and size; asking for another image or size is an error.
maxcounts only ready sandboxes, not those created from the pool.- Each ready sandbox holds memory and a little CPU while it waits; size
minfor the bursts you expect. list_pools(),get_pool(name)anddelete_pool(name)(CLIcua sb pool ls/rm, MCPsandbox_pool_*) manage them; deleting a pool deletes its ready sandboxes, not the ones created from it.- TypeScript, Swift and Kotlin:
cua.sandboxes().createPool(image, options),listPools(),getPool(name),deletePool(name), andpoolonSandboxCreateOptions.
Disk usage and cleanup#
Images, VM disks and logs live under ~/.cua (CUA_HOME moves them).
cua cache du # usage per category, budget, free space
cua sb ls # SIZE column (--no-size skips it)Automatic cleanup#
- Cache budget. Pulled images, macOS base VMs and local builds share one budget: 30 GiB or 10% of free space, whichever is smaller. Least recently used entries go first, after every pull and build and when the daemon is idle.
- Never removed: sandboxes (running or stopped), anything a sandbox uses, checkpoints, and Docker objects the SDK did not create or pull.
- Base images stay over budget when a sandbox was created from them, when
they are this release's macOS or Linux default, or when a create from them
failed (so the retry does not download it again).
cua cache prune --allremoves every base no sandbox uses. - Ephemeral sandboxes are deleted with their handle. If the program
crashes, the next
cua sbcommand or the daemon deletes them 10 minutes later. - Logs are capped at 10 MiB per file (also the Lume installer's
/tmplogs when cua installed Lume). - Screenshots from
cua do screenshotwithout--savego to~/.cua/screenshots; the newest 20 are kept.
Free space now#
cua cache prune --dry-run # what would go
cua cache prune # down to the budget
cua cache prune --all # every unused cache entry
cua sb rm my-box -f # a sandbox and all its disksSettings#
cua cache config --budget 50G --min-free 10G{
"budget": "50G",
"min_free": "10G",
"warn_free": "20G",
"orphan_reap_minutes": 10,
"auto_gc": true
}The environment wins: CUA_CACHE_BUDGET (auto, off or a size),
CUA_DISK_MIN_FREE (default 5G), CUA_DISK_WARN_FREE (20G),
CUA_ORPHAN_REAP_MINUTES (10), CUA_CACHE_AUTO_GC (0 turns it off).
Low disk#
A pull, build or VM create that would leave less than CUA_DISK_MIN_FREE
fails before writing anything: CuaError.InsufficientDisk in the SDKs, exit
code 7 in the CLI.
cua: insufficient disk: not enough disk space to pull ghcr.io/trycua/linux:24.04:
it needs about 3.2 GiB and cua keeps 5.0 GiB free, but only 6.1 GiB is available
on /Users/me/.cua/images (run `cua cache prune` to free space, or lower
CUA_DISK_MIN_FREE)cua-bench results#
Kept until you remove them; cua-bench warns past 10 GiB
(CUA_BENCH_WARN_SIZE). Keep fewer with cb run ... --keep-runs 20 or
cb prune --runs --keep 20.