Guides
Using the Sandbox
A Sandbox is a machine that belongs to one NPC: a shell, a filesystem that persists between Conversations, a browser, and the ability to install what it needs. Every NPC gets its own, so two NPCs can run long jobs at the same time without colliding.
First, the Operator switches it on
Sandboxes ship behind a Compose profile. A Village that does not want them runs four services and nothing else.
Three settings in the root .env govern it:
SANDBOX_BROKER_URL— where the API server reaches the broker, by defaulthttp://sandbox-broker:8008SANDBOX_BROKER_TOKEN— required, at least 16 characters. The broker refuses to start without one:openssl rand -base64 24SANDBOX_IDLE_MINUTES— how long a Sandbox may sit idle before it is stopped. Default 30.
Until that profile is running, the Sandbox pane says so plainly rather than showing a broken machine, and Sandbox Tools report themselves as unavailable instead of failing obscurely.
The broker is the only part of the stack that holds the Docker socket. It publishes no ports, sits on the internal network, and the reverse proxy has no route to it. The reasoning is in ADR 0006.
Give an NPC a machine
Open the NPC and go to its Sandbox pane. Press Give this NPC a machine.
That writes the grant — PUT /api/npcs/:npcId/sandbox — and the badge at the
top, which GET /api/npcs/:npcId/sandbox fills in, switches from no machine
to stopped. The machine itself is created the first time something actually
uses it.
Then go to the Tools pane and tick the sandbox built-in. The pane is two
separate decisions on purpose: the Sandbox pane gives the NPC a machine, the
Tools pane lets the NPC reach it. Without the grant on the Tools pane, the
machine exists and the NPC cannot see it.
What is in the machine
The image is deliberately ordinary. Beyond a Node 24 base it carries:
bash,curl,less,unzipgitjqpython3, withpipandvenvripgrep- Chromium, installed at build time with Playwright, and a
browsecommand that drives it
Chromium is baked in rather than fetched on demand, because a Sandbox with no internet access cannot download a browser the first time it wants one.
Anything else the NPC installs itself, into /work.
What the NPC can do with it
Granting sandbox gives the NPC six Tools, and each one renders in the
transcript like any other Tool call:
/work is a volume of its own, one per NPC. It survives between Conversations,
survives the machine being stopped, and is invisible to every other NPC.
/tmp is writable and does not survive.
The terminal and the files
The Sandbox pane is your own window into the same machine.
Type a command and press Run. Output streams back line by line over
POST /api/npcs/:npcId/sandbox/exec, and a Stop button appears while it
runs. When the command finishes the pane appends [exit 0], or [timed out]
if it ran too long.
Browse files calls GET /api/npcs/:npcId/sandbox/files and lists /work —
names, whether each entry is a directory, and the size in bytes.
Two more buttons change the machine itself:
- Stop (
POST /api/npcs/:npcId/sandbox/stop) shuts the machine down./workis untouched, and the next command starts it again. - Destroy (
DELETE /api/npcs/:npcId/sandbox) removes the machine and its filesystem. This is not recoverable.
Remove machine revokes the grant and destroys the machine with it. Revoking a Sandbox should not leave a filesystem lying around, so it does not.
An idle machine is stopped for you after SANDBOX_IDLE_MINUTES. Nothing is
lost; the next command starts it again.
Internet access is off, and only the Operator turns it on
sandbox.egress is false by default and the Sandbox sits on a network with no
route out. The database, the API server and the broker are not reachable from
inside it either.
Only the Operator can change it. A Player who tries gets a 403 saying why: a Sandbox with a browser and a route to the internet can send anything it can read anywhere. When egress is on, the pane carries a red internet badge so nobody has to go looking for the setting to find out.
With egress off, browse and install_package will fail. That is the trade,
and it is stated rather than hidden.
Changing egress replaces the machine, because the network cannot be swapped
under a running one. /work survives, so no work is lost.
Host folders
The Operator can lend folders from the host machine to Sandboxes — a shared
documents folder, a checkout of a repository — in Settings → Host Mounts. A
lent folder appears inside the Sandbox at /work/mnt/<name>, so read_file,
list_files and bash reach it like anything else in /work, and the NPC is
told which folders it has and whether it may change them.
- Read-only by default. A read-write mount lets a model edit or delete those files on the host; the Settings card says so in red.
- All NPCs, a Group, or one NPC. "All NPCs" means every Player's NPCs, not only the Operator's.
- Only inside the allowed roots. The Operator lists them in
SANDBOX_HOST_MOUNT_ROOTS. With it empty, Host Mounts are off. The sandbox broker — the only process holding the Docker socket — checks every path against its own copy of the list before Docker sees it, so nothing sent by the API server can mount/or the socket. - Applied on the next command. Adding or removing a mount replaces the
machine, like a change of egress;
/worksurvives.
The broker checks paths by name, not by following them: a symbolic link inside an allowed folder that points outside it is followed by Docker. Do not lend a folder that contains links you would not lend. See ADR 0025.
What contains it
Every Sandbox runs unprivileged as a fixed non-root account, with every Linux
capability dropped, no-new-privileges set, and a read-only root filesystem.
Resource limits are fixed: 2 GB of memory, 1.5 CPUs, 512 processes.
The threat model is stated honestly in ADR 0006: this is isolation against a careless or manipulated model, not against a determined attacker with a kernel exploit.