Repository navigation
Sandbox Specification
Reference. The exact container settings the launcher uses. They are built in code (
agentbox/launcher.py); callers can't change them.
| Setting | Value |
|---|---|
| Image |
agentbox/agent:local (Chainguard wolfi-base; Claude Code; no apk, su, sudo or setuid files) |
| User |
AGENTBOX_AGENT_UID:AGENTBOX_AGENT_GID (64000:64000) |
| Network |
NetworkMode: none: a private namespace with only lo. NetworkDisabled is deliberately unset (under gVisor it removes lo too). |
| Root filesystem | read-only |
| Capabilities |
CapDrop: [ALL]; none added |
| Security options |
no-new-privileges:true; Docker default seccomp and AppArmor |
| Init | tini (Init: true) |
| IPC | private |
| Limits | pids 512 · memory 8 GiB, swap 0 · 4 CPUs · nofile 4096 |
| tmpfs |
/tmp 2 GiB (1777) · /home/agent 1 GiB (owned by agent uid, 0700) |
| Mounts (agent) |
worktrees/<id> → /workspace (rw) · sockets/<id> → /run/gw (rw, contains only llm.sock) · optional venv → /opt/venv (ro) |
| Mounts (check) |
worktrees/<id> → /workspace (rw) · optional venv (ro). No socket.
|
| Command (agent) |
agent-shim → claude … (must start with claude) |
| Command (check) | bash -c <command> |
| Env | allowlist ANTHROPIC_AUTH_TOKEN, CLAUDE_CODE_MAX_OUTPUT_TOKENS, AGENT_NO_GUIDE, MAX_THINKING_TOKENS; plus model ids, venv PATH, PYTHONDONTWRITEBYTECODE=1
|
| Deadline | agent: timeout_minutes (max 4 h); check: max 1 h. Killed by the launcher even if agentbox dies. |
| Logs | json-file, 20 MB × 2 |
| Runtime |
AGENTBOX_AGENT_RUNTIME: runsc (gVisor) is recommended and needs --host-uds=open; unset means runc. Validated by the launcher at startup. |
| Labels |
agentbox.role (agent or check), agentbox.tid, agentbox.model
|
The agent image, run as your uid with no network, CapDrop: [ALL], no-new-privileges, a read-only root, a 64 MB tmpfs /tmp, 64 pids, 1 GiB memory and the runc runtime. Each runs one fixed script:
- probe the folder;
- snapshot a commit;
- deliver an
agent/<id>branch; - delete such a branch;
- check a venv.
It mounts exactly what that operation needs:
- the one repo (read-only for snapshots, read-write for delivery);
- for a worktree, also its common
.gitdir; - the task's shadow dir.
Mounts use the Docker Mounts API, so a missing path is an error, never created. The helper exits with an error unless the folder is owned by you.
The same image, run as root with CapAdd: [CHOWN, DAC_OVERRIDE, FOWNER] only. It has no network, a
read-only root, no-new-privileges and pids 16. It mounts only the one workspace and runs
chown -R -h <uid>:<gid> /w (never follows symlinks) and chmod -R u+rwX /w. It first checks that /w is the exact device:inode the launcher validated, so a path swapped after the check is refused. It always uses runc: it executes no untrusted
code.
NetworkMode: host (binds 127.0.0.1:port), all GPUs, models_dir → /models (ro), vllm_cache →
/cache, journald logging (tag agentbox-<model-id>), auto-remove, plus the memory, shm_size /
ipc_host, env, entrypoint and args from models.yaml.
agentbox, agentbox-launcher, llm-bridge and ollama all run as your uid with a read-only root, cap_drop: ALL
and no-new-privileges, with memory and pids limits.
- The launcher uses
network_mode: noneand has the docker group plus the socket. - The others use host networking and bind to 127.0.0.1.
Tutorials
How-to guides
- Install
- Delegate from Claude Code
- Write good specs
- Python environments
- Add a local model
- Connect remote APIs
- Run under gVisor
- Operate
- Troubleshoot
Reference
Explanation