What a managed sandbox has installed, how its disk and network behave, how secrets reach it, how to move files, and how to run an agent in it.
→ Sandbox quickstart · Limits and pricing · Sandboxes API
The box
Each sandbox is a Firecracker VM on a platform engine. Its image is set by the platform; you cannot choose another one. The sandbox's image field names the one it boots.
| Item | Value |
|---|---|
| OS | Ubuntu 24.04, packages upgraded when the image is built |
| User | agent (uid 1000), shell /bin/bash, passwordless sudo |
| Home and working directory | /home/agent |
| Hostname | sbx-<sandbox id> |
| Architectures | linux/amd64 and linux/arm64 images |
Pre-installed
The image is small on purpose. It has:
belt(the version is in the image tag, for examplev1.28.9-20261107.21)git,curl,openssh-client,ca-certificates,sudo,util-linux
There is no Python, Node.js, Docker, build toolchain, browser, or coding-agent CLI. Install what you need with apt or the tool's installer:
1belt sandbox exec dev -- sudo apt-get update2belt sandbox exec dev -- sudo apt-get install -y python3 python3-pip build-essentialFiles you write on the writable disk survive a normal stop and start on the same engine while disk_kept is true (see Disk). They are gone when the disk is new: you asked for fresh_disk on start, the kept disk expired, the platform gave it up, or the box restarted on another engine. Put apt installs and other setup in a script you re-run when the disk is fresh.
What runs on boot
The box starts belt remote start --agents --exec --name <sandbox name> as agent. That daemon is the sandbox's remote: it runs your commands (--exec) and harness agent sessions (--agents). The box ends when the daemon exits, and the platform restarts it (see Lifetime).
Environment
Commands get the daemon's environment, plus any --env (CLI) or env (API) you pass to that command.
| Variable | Value |
|---|---|
INFERENCE_API_URL | The API the box talks to |
INFERENCE_API_KEY | A placeholder for the box key (see Secrets) |
INFSH_SANDBOX_ID, INFSH_SANDBOX_NAME | This sandbox |
BELT_NON_INTERACTIVE | 1 |
INFSH_NO_AUTOUPDATE | 1; belt in the box does not update itself |
NODE_EXTRA_CA_CERTS | The gateway's CA certificate, for Node.js tools |
Disk
Each sandbox has a writable disk layered over the read-only image. disk_mib is its size.
When you stop a box, the engine that ran it keeps that writable disk. The next start (or an automatic restart that still has the same kept disk) boots back onto it, so files and installs from the last run are still there. While the sandbox is stopped, disk_kept and disk_kept_until on GET /sandboxes/{id} tell you whether the disk is still held and when it expires (stopped_at plus seven days). The engine may drop it earlier if its host runs short of disk.
To start with a clean disk instead, call POST /sandboxes/{id}/start with {"fresh_disk":true} while the sandbox is stopped. A new generation still gets a new box key; the remote id does not change.
If the kept disk is gone when you start, you get a new empty disk, as when the sandbox was first created. When the box fails to start on its kept disk 3 times in a row, the platform gives the disk up and status_reason starts with its disk was lost:. A disk the engine dropped for lack of space leaves no reason; disk_kept is false. Automatic restarts that cannot return to the keeping engine also start on a new disk.
Keep work you need outside the box when disks can be lost: push to git or upload (see Files). There are no snapshots.
Network
The box has outbound internet. All its traffic goes through the engine's egress gateway: TCP is redirected to the gateway, DNS goes to the gateway's resolver, and UDP is relayed. There is no HTTP_PROXY to set; tools work unchanged.
- Private, loopback and engine-host addresses are refused. The inference.sh API is the one exception.
- Sandboxes cannot reach each other.
- Nothing can connect in. There is no public URL or port forwarding.
- Platform deny rules refuse crypto-mining pools and the stratum protocol. Repeated attempts stop the sandbox (see Network limits).
Traffic to hosts with no bound secret passes through as an opaque tunnel. For hosts with a bound secret, the gateway terminates TLS with its own CA so it can add the credential. The box trusts that CA: it is in the system store, and NODE_EXTRA_CA_CERTS points Node.js at it.
Secrets
Secret values never enter the box. The box holds placeholders (infsh_ph_...). When a request to a bound host leaves the box, the gateway swaps the placeholder for the real value. It places values only in credential positions: the Authorization header (Basic auth too), or the header or query parameter the provider uses. Never in the path or body. A placeholder sent to a host it is not bound to is refused.
The box key
Each start mints an API key for the box, bound to the API host. INFERENCE_API_KEY in the box is its placeholder. The key holds remotes:read and remotes:write, and only for this sandbox's own remote. It lets the daemon stay connected. It cannot run apps, read files, use secrets, or create sandboxes. See Sandboxes API.
To call inference.sh from inside the box, pass a key of your own to the command. A short-lived token limits the damage if the box leaks it:
1TOKEN=$(belt auth token --ttl 1h)2belt sandbox exec dev --env INFERENCE_API_KEY=$TOKEN -- belt app run <namespace/app> -i '{...}'Anything running in the box can read a value you pass this way. The API returns only the names of env entries, never their values.
Provider logins
To give the box a GitHub (or other provider) login, add it at create with credentials in the API or --credential in the CLI. The login stays in the workspace; the box gets a placeholder bound to the provider's hosts. See Sandboxes API for auto and ask modes.
1belt sandbox create repo --credential github-app --wait2belt sandbox exec repo -- git clone https://github.com/your-org/private-repoGit is set up for this. /etc/gitconfig answers HTTPS credentials for github.com and gist.github.com with user x-access-token and the password $GITHUB_TOKEN, or the marker infsh-fill when it is unset. The gateway replaces the marker with the bound login.
Use infsh-fill the same way for any tool that asks for a key on a bound host. The tool sends the marker, and the gateway puts the login in.
Plain environment variables
You cannot attach environment variables or workspace secrets to a sandbox at create. Pass them per command with --env KEY=value (CLI) or env: ["KEY=value"] (API).
Files
There is no file upload or download route for a sandbox. Move files with commands:
| Direction | How |
|---|---|
| Into the box | git clone, curl a URL, or belt file download a file you uploaded, with your own key |
| Small text in | Pass it in a command: belt sandbox exec dev -- bash -c 'cat > notes.txt <<EOF ... EOF' |
| Out of the box | Print it and read the command output, push it to git, or upload it from the box with your own key (belt file upload, with --env INFERENCE_API_KEY=...) |
1# Upload a local file to inference.sh, then fetch it in the box2TOKEN=$(belt auth token --ttl 1h)3url=$(belt file upload ./data.csv --jq .uri)4belt sandbox exec dev --env INFERENCE_API_KEY=$TOKEN -- belt file download "$url" -o data.csv56# Read a file back7belt sandbox exec dev -- cat report.md > report.mdCommand output streams in chunks of base64 through GET /execs/{id}/output. Large binaries are better uploaded from the box.
Files attached to a harness chat on the sandbox are downloaded into the box for that chat (https only, up to 50 MB and 60 seconds per file). See Attachments.
Agents in the box
There are three ways to put an agent to work on a sandbox.
1. A workspace agent drives the box. Turn on the agent's Remotes internal tools. The agent runs commands on the sandbox's remote with remote_exec (through sh -c, default timeout 600 s, the last 30000 characters of output). See Remote tools.
2. A harness runs in the box. The daemon runs with --agents, so harness sessions work once a harness is installed and signed in. The image has none. Install one with exec, sign it in, and the daemon finds it within 5 minutes. Then launch it from Resources → Remotes or with POST /remotes/{id}/sessions. See Agent harness sessions. The harness and its sign-in are gone on the next start.
3. Your own agent calls the box. From your machine or CI, an agent uses belt sandbox exec or the Exec runs API. Use --json, --no-input and the exit codes for a stable contract.