LangBot Docs
Sandbox

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.

box:
  enabled: true
  backend: 'local'        # auto-pick from Docker / Nsjail
  local:
    profile: 'default'
    host_root: './data/box'
    skills_root: 'skills'
  docker:
    cpu_limit_enabled: true
  • enabled: master switch. When false, 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 /workspace inside the sandbox.
  • local.skills_root: skill package directory; relative paths resolve under host_root (defaults to host_root/skills).
  • docker.cpu_limit_enabled: whether Docker sandbox containers get a CPU limit; set to false to omit docker run --cpus while 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:

backendWhere it runsBehavior
local (default)Local containersAuto-pick from Docker / Nsjail (Docker preferred)
dockerLocal containersForce Docker; requires the Docker daemon
nsjailLocal containersForce Nsjail (Linux only); no custom image support
e2bCloudUse E2B cloud sandbox; requires API key
hostBox Runtime hostStart 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:

ProfileNetworkMountsResourcesWhen to use
defaultOffRead-writeDefault limitsDefault choice
offline_readonlyOffRead-onlyStricterReading untrusted files
network_basicBasic networkRead-writeDefault limitsAPI access or dependency install
network_extendedFull networkRead-writeRelaxedDevelopment, 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:

SettingDefaultNotes
local.profiledefaultDocker / Nsjail security profile; Host provides no matching isolation
local.imageemptyDocker-only custom image; empty = use profile default
local.host_root./data/boxHost workspace base, mapped to /workspace inside the sandbox
local.default_workspaceemptyDefault workspace name; empty = <host_root>/default
local.skills_rootskillsSkill 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_mbnullWorkspace disk quota (MB); null = use profile default; Host provides no hard quota guarantee
default_memory_mb1536Memory 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.
  • exec and 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 persistent rules match the other backends.
  • Status responses include unsafe_direct_execution: true so 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.

SettingNotesDefault
box.default_memory_mbMCP 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.*)

SettingDefaultNotes
docker.cpu_limit_enabledtrueDocker 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':

SettingDefaultNotes
e2b.api_keyemptyE2B API key; can also be set via E2B_API_KEY
e2b.api_urlemptySelf-hosted E2B endpoint; can also be set via E2B_API_URL
e2b.templateemptyDefault 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 variableMaps to
BOX__ENABLEDbox.enabled
BOX__BACKENDbox.backend
BOX__LOCAL__PROFILEbox.local.profile
BOX__LOCAL__IMAGEbox.local.image
BOX__LOCAL__HOST_ROOTbox.local.host_root
BOX__LOCAL__DEFAULT_WORKSPACEbox.local.default_workspace
BOX__LOCAL__SKILLS_ROOTbox.local.skills_root
BOX__LOCAL__ALLOWED_MOUNT_ROOTSbox.local.allowed_mount_roots, comma-separated
BOX__LOCAL__WORKSPACE_QUOTA_MBbox.local.workspace_quota_mb
BOX__DEFAULT_MEMORY_MBbox.default_memory_mb
BOX__DOCKER__CPU_LIMIT_ENABLEDbox.docker.cpu_limit_enabled
BOX__E2B__API_KEYbox.e2b.api_key
BOX__E2B__API_URLbox.e2b.api_url
BOX__E2B__TEMPLATEbox.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.

On this page