Docs / Hotcell / Lifecycle

Sandbox lifecycle

How Hotcell sandboxes are created, paused with memory snapshots, resumed, stopped and destroyed, plus idle auto-pause, admission control and warm pools.

States

Status Meaning
creating Provisioning. statusReason holds the current phase. Only DELETE is allowed.
running Live and accepting operations.
paused Compute freed, workspace kept. Any operation resumes it automatically.
stopped Stopped by you. It doesn't resume on its own; operations return 409 until you start it.
error Create failed. The reason is in statusReason. Destroy it.
creating ──▶ running ──(idle > sleepAfter, or pause)──▶ paused ──(any operation)──▶ running
                │                                          │
                └──────────────── stop ────────────────────┴──▶ stopped ──(start)──▶ running

Create

hotcell create --image node:22 --memory 2048 --cpus 2 --repo https://github.com/you/app --setup "npm install"

Create options (CLI flag / REST body field):

Option CLI REST field Notes
Image --image image Defaults to HOTCELL_IMAGE
Driver --driver driver container, firecracker or applevz
Environment --env K=V,… env
Labels --label K=V,… labels --name sets the name label
Persistent workspace persist Default true
Idle auto-pause --sleep-after MS sleepAfter Milliseconds; 0 disables
Repo --repo URL repo Cloned into /workspace before setup; a clone failure fails the create
Ref --ref BRANCH repoRef Branch or tag to check out
New branch --branch NAME branch Created after the clone; auto generates hotcell/<first 8 chars of id>
Setup --setup "cmd" setup (array) Runs once after start; best-effort
Memory / CPU / PIDs --memory --cpus --pids memoryMb cpus pidsLimit Hard caps; override daemon defaults
Egress --egress egress true or a policy object; see Egress
Sandbox spend cap --egress-spend-cap USD egressSpendCapUsd
Detached detach Return immediately with status creating

With -n N, the CLI creates N sandboxes in one command and prints one id per line. A shared --name is suffixed per sandbox (feat-1 to feat-N), and so is a named --branch, so pushes don't collide.

Detached creates

A slow create (repo clone plus heavy setup) can outlast a single HTTP request. With detach: true the daemon responds 201 at once with status creating and provisions in the background. The SDKs then poll GET /sandboxes/:id until the sandbox is running, and throw if it reaches error. The CLI's create always uses this path and shows live per-sandbox progress. Ctrl-C leaves provisioning running.

Without detach, a provisioning failure returns 422 and the record is removed.

Setup and custom images

Setup runs once at create time and isn't re-run on resume. With persistence, installed dependencies live in the workspace volume and survive pause and resume. Other ways to arrive with tools installed:

  1. Build a custom image (extend images/base/Dockerfile) and set HOTCELL_IMAGE.
  2. Run setup after create: hotcell exec "$id" "npm i some-cli".
  3. Provision once, hotcell backup, then hotcell restore into new sandboxes.

Pause and resume

hotcell pause <id>
hotcell resume <id>      # or any operation on the sandbox

Pause uses the strongest option the driver offers:

  • MicroVM drivers (firecracker, applevz): a memory snapshot of guest RAM and device state. Background processes come back alive on resume, and tracked processes and exposed ports stay valid. If a snapshot fails to load, the daemon discards it and cold-boots with the workspace intact.
  • Container driver: stop with volume. The workspace survives; processes, exposed ports and code-interpreter contexts don't.

A paused sandbox resumes on its next operation: exec, file operations, terminal, or inbound traffic on a preview URL. Pausing a stopped sandbox returns 409.

Idle auto-pause

Set sleepAfter per sandbox, or HOTCELL_SLEEP_AFTER_MS as the daemon default (default 0, off). The idle reaper scans every HOTCELL_REAP_INTERVAL_MS (default 15000) and pauses sandboxes idle past their timeout.

  • An open exec stream counts as activity for its whole duration.
  • Reading metrics doesn't count as activity.
  • A sandbox with an exposed port or a tracked background process is auto-paused only if the driver can memory-snapshot it. On the container driver it is skipped, because pausing would kill that work.

Sandboxes never destroy themselves.

Stop and start

hotcell stop <id>
hotcell start <id>

Stop frees compute and keeps the workspace volume. Background processes, exposed ports and code-interpreter contexts end; sessions (working directory and env) are kept. A stopped sandbox stays stopped until you start it.

Destroy

hotcell rm <id>          # one or several ids
hotcell rm --all

Destroy removes the sandbox and its persistent volume, its sessions, and all its egress tokens. You can destroy a sandbox while it is creating to cancel the create.

Admission control

The daemon tracks committed memory against a host budget and refuses to over-subscribe:

  • The budget is auto-detected (HOTCELL_HOST_MEMORY_MB and HOTCELL_HOST_CPUS override it) and multiplied by HOTCELL_OVERCOMMIT (default 1).
  • A capped sandbox is charged its cap. An uncapped sandbox is charged HOTCELL_DEFAULT_RESERVATION_MB (default 256) until the sampler measures it, then its measured usage.
  • A create or resume that doesn't fit returns 503 with Retry-After: 5.
  • HOTCELL_ADMISSION=off only reports capacity.
hotcell capacity

Warm pools

A warm pool keeps pre-started sandboxes ready so a create adopts one instead of starting cold. Pools are off by default.

Driver Variable
container HOTCELL_CONTAINER_WARM_POOL
firecracker HOTCELL_FC_WARM_POOL
applevz HOTCELL_VZ_WARM_POOL
  • A create adopts a spare only if it matches the pool shape exactly: the daemon's default image and default resource limits.
  • Spares are charged to admission capacity. GET /capacity reports them under pool.
  • The pool refills in the background as spares are claimed. Beyond pool depth, creates take the cold path.
HOTCELL_CONTAINER_WARM_POOL=10 hotcell start

In a 25-wide container burst on macOS, adopting from a pool had a median create-and-probe time of 517 ms, against 1,845 ms cold. See Benchmarks.

Backups

hotcell backup <id>                  # snapshot /workspace to a host tarball
hotcell backups [<id>]               # list all, or one sandbox's
hotcell restore <id> <backupId>      # replace /workspace with a backup

Backups are stored in HOTCELL_BACKUP_DIR (default ~/.hotcell/backups). You can restore a backup into any sandbox, not only the one it came from.