When to use this
Most sandbox work is one-shot: run something, take the output, throw the box away. A different class of problem needs the session to stay alive:- Remote dev boxes. One clean isolated environment per user or per branch, where they install dependencies, edit files, and run tests.
- A workbench for an agent. A coding agent that runs
apt-get install, thengit clone, thenpytest— where each step depends on state the previous one left behind. - Multi-tenant terminals. A platform giving every tenant a shell isolated at the VM level, with no shared kernel or filesystem.
CodeBox.run cannot do this: every call is a fresh execution. InteractiveBox keeps a long-running shell inside the box, so repeated exec calls land in the same session and state persists between them. When a human needs it, the same box forwards a real PTY to their terminal.
Architecture
The shell outlives individual commands, so everything written to disk, installed, or exported stays available to the next call. Two ways in: programmaticexec for automation, or wait() to hand the terminal to a person.
Prerequisites
- BoxLite installed and a working virtualization host — see Installation.
- Any image with a shell. This guide uses
alpine:latest.
Build it
Programmatic: a session that remembers
Interactive: hand the shell to a person
wait() forwards only when the host stdin is a real TTY — it detects this automatically. In scripts and CI, use the exec form above. The full InteractiveBox parameter table is on Interactive shell (PTY).
Run it
exec was read back by another. That is the difference between a session and a series of one-shot runs.
Trust and limits
- What the boundary covers. Each session is a microVM with its own kernel and filesystem. Tenants cannot see each other, and nothing a user installs or deletes reaches the host.
- State persists, which cuts both ways. A long-lived session accumulates whatever ran in it. For multi-tenant use, one box per tenant and a fresh box per session are the safe defaults; reusing a box across tenants leaks state.
execnever raises on command failure. A failed command is a non-zeroexit_code. Check it, especially in setup chains where a silent failure leaves later steps confused.wait()needs a real terminal. In a non-TTY environment it will not forward. Useexecthere.- The box lives as long as the block. Leave the
async withscope andauto_removedestroys it along with everything installed. For a session that survives your process, set anameandauto_remove=False— and remember to reclaim it later withboxlite rm.
Troubleshooting
Next steps
- One box per tenant. Give each box a stable
name, setauto_remove=False, and reattach later with the runtime — see Lifecycle. - Bring your own toolchain. Start from an image that already has your compilers and CLIs — Use a custom agent image.
- Let an agent use the workbench. Run Claude Code puts an autonomous coding agent in the same kind of persistent box.
- Lock down what the session can reach — Run untrusted tools safely.

