Sandbox Configuration
Configure LangBot Box Runtime with Docker, nsjail, E2B, or the explicitly enabled non-isolated Host backend.
Box settings are owned by the LangBot main process; Box Runtime performs the actual execution. For most deployments, you only need to choose a backend, set the workspace directory, and pick a security profile. Docker, nsjail, and E2B provide sandbox environments; the Host backend runs commands directly on the Box Runtime host.
All box.* settings on this page live in data/config.yaml. See System Environment Settings for the file's location and how it's loaded.
Recommended Configuration
box:
enabled: true
backend: 'local' # auto-pick from Docker / Nsjail
local:
profile: 'default'
host_root: './data/box'
skills_root: 'skills'
docker:
cpu_limit_enabled: trueenabled: master switch. Whenfalse, all Box-dependent features are disabled (sandbox tools, skill add/edit, stdio MCP hosting).backend: see "Backend Selection" below.local.profile: security profile — controls network, mounts, and resource limits.local.host_root: host workspace directory, mapped to/workspaceinside the sandbox.local.skills_root: skill package directory; relative paths resolve underhost_root(defaults tohost_root/skills).docker.cpu_limit_enabled: whether Docker sandbox containers get a CPU limit; set tofalseto omitdocker run --cpuswhile keeping memory and PID limits.
Skills are loaded only from the Box-managed skill store. When Box Runtime or the backend is unavailable, the skill list is empty and create/edit/register_skill are disabled — there's no fallback to data/skills/.
Backend Selection
Box can run in local containers, in a cloud sandbox, or as a process on the Box Runtime host. box.backend picks which:
backend | Where it runs | Behavior |
|---|---|---|
local (default) | Local containers | Auto-pick from Docker / Nsjail (Docker preferred) |
docker | Local containers | Force Docker; requires the Docker daemon |
nsjail | Local containers | Force Nsjail (Linux only); no custom image support |
e2b | Cloud | Use E2B cloud sandbox; requires API key |
host | Box Runtime host | Start local processes with the Box Runtime user's permissions; requires POSIX and sh |
local is shorthand for "auto-pick", not a fourth backend sitting next to docker/nsjail. It only tries Docker and Nsjail and never auto-selects host. Local backends use workspace settings from box.local.*; the cloud backend uses box.e2b.*.
host is not a sandbox. Commands have the Box Runtime user's host permissions, with no filesystem, process, network, namespace, cgroup, rootfs, or image isolation. Read-only mounts and hard disk quotas are not guaranteed. Use it only for single-user local development with trusted input; never use it for public services, shared hosts, or untrusted code.
backend is a hard selection. Setting docker and finding Docker unavailable does not fall back to Nsjail or E2B — only local auto-fans-out.
BOX__BACKEND environment variable overrides box.backend (highest priority).
Security Profiles
box.local.profile controls network, mounts, and resource limits for the Docker / Nsjail local sandbox backends:
| Profile | Network | Mounts | Resources | When to use |
|---|---|---|---|---|
default | Off | Read-write | Default limits | Default choice |
offline_readonly | Off | Read-only | Stricter | Reading untrusted files |
network_basic | Basic network | Read-write | Default limits | API access or dependency install |
network_extended | Full network | Read-write | Relaxed | Development, debugging, complex tasks |
Prefer least privilege: skip the network unless you need it (default / offline_readonly); only add necessary directories to allowed_mount_roots.
The Host backend does not enforce these isolation policies. A configured profile, CPU / memory / PID limit, read-only rootfs, or disabled network does not create a sandbox boundary around host processes.
Local Workspace Configuration (box.local.*)
Docker, Nsjail, and Host share workspace path settings. Isolation and resource settings only take effect when the selected sandbox backend can enforce them:
| Setting | Default | Notes |
|---|---|---|
local.profile | default | Docker / Nsjail security profile; Host provides no matching isolation |
local.image | empty | Docker-only custom image; empty = use profile default |
local.host_root | ./data/box | Host workspace base, mapped to /workspace inside the sandbox |
local.default_workspace | empty | Default workspace name; empty = <host_root>/default |
local.skills_root | skills | Skill package directory; relative paths resolve under host_root |
local.allowed_mount_roots | [host_root] | Allowlist of host directories the Agent can mount |
local.workspace_quota_mb | null | Workspace disk quota (MB); null = use profile default; Host provides no hard quota guarantee |
default_memory_mb | 1536 | Memory limit for each MCP stdio process (MB); Host cannot enforce it through cgroups |
Host Backend (Trusted Local Development)
Host is the lowest-dependency local option and does not require Docker or Nsjail. It must be selected explicitly:
box:
enabled: true
backend: 'host'
local:
host_root: './data/box'
skills_root: 'skills'The WebUI, Agent tools, and calling conventions stay the same: session scopes, exec/read/write/edit/glob/grep, Skills, and stdio MCP all use the existing Box APIs. Only the execution layer changes:
/workspace,workdir, and Skill mount paths are translated to real paths on the Box Runtime host.- Child processes inherit only a minimal path, locale, and terminal environment plus variables explicitly supplied by the request. LangBot / Box control secrets are not inherited automatically. This reduces accidental leakage but does not provide filesystem isolation.
execand managed processes start in separate process groups. Timeouts, cancellation, process stop, session deletion, and Runtime shutdown terminate the corresponding process trees.- Idle cleanup, managed-process keepalive, and
persistentrules match the other backends. - Status responses include
unsafe_direct_execution: trueso operators can detect the lack of sandbox isolation.
Host means the environment where Box Runtime runs. With LangBot's local stdio-managed Box Runtime, that is the current machine. If Box Runtime itself runs in a container, commands run directly in that container; Host does not automatically break through to the physical host.
The Host MVP supports POSIX systems with sh (Linux / macOS). Use WSL on Windows; a native Windows process backend is not yet supported.
When Host is used through an external WebSocket Box Runtime, set the same strong random LANGBOT_BOX_CONTROL_TOKEN on both LangBot and Box Runtime. The locally managed stdio Runtime needs no extra token configuration. Cloud environments with managed-sandbox admission still validate isolation capabilities and the required backend; Host does not bypass those checks.
Box Sandbox Memory Configuration
box.default_memory_mb sets the nsjail cgroup memory cap for every stdio-mode MCP server process.
The Host backend has no cgroup memory isolation, so this value cannot limit MCP processes running on Host.
| Setting | Notes | Default |
|---|---|---|
box.default_memory_mb | MCP process memory cap (MB) | 1536 |
Can be set in config.yaml or via the BOX__DEFAULT_MEMORY_MB environment variable.
When to adjust:
- Node.js MCP servers (launched via npx/bunx): V8 + WebAssembly module initialisation needs significant memory; keep at ≥ 1536 MB
- Python MCP servers (launched via uvx): 512 MB is usually enough, but the default is fine too
- When memory is exhausted, the process is forcibly killed (return_code=137), logged as "Box managed process exited unexpectedly"
Per-server override: Set box.memory_mb in the individual MCP server config to override the global default.
Docker Backend Configuration (box.docker.*)
| Setting | Default | Notes |
|---|---|---|
docker.cpu_limit_enabled | true | Docker backend only. When false, sandbox containers start without --cpus; --memory and --pids-limit still apply. |
Cloud Backend Configuration (box.e2b.*)
Configure after setting backend: 'e2b':
| Setting | Default | Notes |
|---|---|---|
e2b.api_key | empty | E2B API key; can also be set via E2B_API_KEY |
e2b.api_url | empty | Self-hosted E2B endpoint; can also be set via E2B_API_URL |
e2b.template | empty | Default E2B template ID |
E2B doesn't need Docker or Nsjail on the host — every execution goes through the remote sandbox.
Docker Compose Deployment
In Docker Compose, sandbox settings live on the langbot service. LangBot forwards them to langbot_box via INIT RPC at startup.
services:
langbot_box:
image: rockchin/langbot:latest
container_name: langbot_box
profiles: ["box", "all"]
volumes:
- ${LANGBOT_BOX_ROOT:-${PWD}/data/box}:${LANGBOT_BOX_ROOT:-${PWD}/data/box}
- /var/run/docker.sock:/var/run/docker.sock
command: ["uv", "run", "--no-sync", "-m", "langbot_plugin.cli.__init__", "box"]
langbot:
image: rockchin/langbot:latest
volumes:
- ./data:/app/data
environment:
- BOX__LOCAL__HOST_ROOT=${LANGBOT_BOX_ROOT:-${PWD}/data/box}
- BOX__LOCAL__SKILLS_ROOT=skills
- BOX__LOCAL__ALLOWED_MOUNT_ROOTS=${LANGBOT_BOX_ROOT:-${PWD}/data/box}
- BOX__DOCKER__CPU_LIMIT_ENABLED=${LANGBOT_BOX_DOCKER_CPU_LIMIT_ENABLED:-true}langbot_box needs the Docker daemon. Only mount docker.sock in trusted environments, and keep the Box root path identical on the host and inside the langbot_box container.
To point LangBot at an externally-managed Box Runtime (e.g. a remote host), use box.runtime.endpoint:
box:
runtime:
endpoint: 'ws://192.168.1.10:5410'Environment Variables
| Environment variable | Maps to |
|---|---|
BOX__ENABLED | box.enabled |
BOX__BACKEND | box.backend |
BOX__LOCAL__PROFILE | box.local.profile |
BOX__LOCAL__IMAGE | box.local.image |
BOX__LOCAL__HOST_ROOT | box.local.host_root |
BOX__LOCAL__DEFAULT_WORKSPACE | box.local.default_workspace |
BOX__LOCAL__SKILLS_ROOT | box.local.skills_root |
BOX__LOCAL__ALLOWED_MOUNT_ROOTS | box.local.allowed_mount_roots, comma-separated |
BOX__LOCAL__WORKSPACE_QUOTA_MB | box.local.workspace_quota_mb |
BOX__DEFAULT_MEMORY_MB | box.default_memory_mb |
BOX__DOCKER__CPU_LIMIT_ENABLED | box.docker.cpu_limit_enabled |
BOX__E2B__API_KEY | box.e2b.api_key |
BOX__E2B__API_URL | box.e2b.api_url |
BOX__E2B__TEMPLATE | box.e2b.template |
Don't set BOX__* or LANGBOT_BOX_* on the langbot_box service — Box Runtime doesn't read them directly. Its configuration arrives over INIT RPC from LangBot.