Skip to content

Latest commit

 

History

History
248 lines (197 loc) · 8.88 KB

File metadata and controls

248 lines (197 loc) · 8.88 KB

Sandbox

Run agent shell commands inside an isolated Docker container so untrusted code never touches your host.

Overview

When sandbox mode is enabled, every exec or shell tool call is routed into a Docker container instead of running directly on the host. The container is ephemeral, network-isolated, and heavily restricted by default — dropped capabilities, read-only root filesystem, tmpfs for /tmp, and a 512 MB memory cap.

If Docker is unavailable at runtime, GoClaw falls back to host execution and logs a warning.

graph LR
    Agent -->|exec tool call| ExecTool
    ExecTool -->|sandbox enabled| DockerManager
    DockerManager -->|Get or Create| Container["Docker Container\ngoclaw-sbx-*"]
    Container -->|docker exec| Command
    Command -->|stdout/stderr| ExecTool
    ExecTool -->|result| Agent
    ExecTool -->|Docker unavailable| HostExec["Host exec\n(fallback)"]
Loading

Sandbox Modes

Set GOCLAW_SANDBOX_MODE (or sandbox.mode in config) to one of:

Mode Which agents are sandboxed
off None — all commands run on host (default)
non-main All agents except main and default
all Every agent

Container Scope

Scope controls how containers are reused across requests:

Scope Container lifetime Best for
session One container per session Maximum isolation (default)
agent One container shared across all sessions for an agent Persistent state within an agent
shared One container for all agents Lowest overhead

Default Security Profile

Out of the box, every sandbox container runs with:

Setting Value
Root filesystem Read-only (--read-only)
Capabilities All dropped (--cap-drop ALL)
New privileges Blocked (--security-opt no-new-privileges)
tmpfs mounts /tmp, /var/tmp, /run
Network Disabled (--network none)
Memory limit 512 MB
CPUs 1.0
Execution timeout 300 seconds
Max output 1 MB (stdout + stderr combined)
Container prefix goclaw-sbx-
Working directory /workspace

If a command produces more than 1 MB of output, the output is truncated and ...[output truncated] is appended.

Configuration

All settings can be provided as environment variables or in config.json under a sandbox key.

Environment variables

GOCLAW_SANDBOX_MODE=all
GOCLAW_SANDBOX_IMAGE=goclaw-sandbox:bookworm-slim
GOCLAW_SANDBOX_WORKSPACE_ACCESS=rw   # none | ro | rw
GOCLAW_SANDBOX_SCOPE=session         # session | agent | shared
GOCLAW_SANDBOX_MEMORY_MB=512
GOCLAW_SANDBOX_CPUS=1.0
GOCLAW_SANDBOX_TIMEOUT_SEC=300
GOCLAW_SANDBOX_NETWORK=false

config.json

{
  "sandbox": {
    "mode": "all",
    "image": "goclaw-sandbox:bookworm-slim",
    "workspace_access": "rw",
    "scope": "session",
    "memory_mb": 512,
    "cpus": 1.0,
    "timeout_sec": 300,
    "network_enabled": false,
    "read_only_root": true,
    "cap_drop": ["ALL"],
    "tmpfs": ["/tmp", "/var/tmp", "/run"],
    "max_output_bytes": 1048576,
    "idle_hours": 24,
    "max_age_days": 7,
    "prune_interval_min": 5
  }
}

Full config reference

Field Type Default Description
mode string off off, non-main, or all
image string goclaw-sandbox:bookworm-slim Docker image to use
workspace_access string rw Mount workspace as none, ro, or rw
scope string session Container reuse: session, agent, or shared
memory_mb int 512 Memory limit in MB
cpus float 1.0 CPU quota
timeout_sec int 300 Per-command timeout in seconds
network_enabled bool false Enable container networking
restricted_domains string[] Allowed domains when network is enabled
read_only_root bool true Mount root filesystem read-only
cap_drop string[] ["ALL"] Linux capabilities to drop
tmpfs string[] /tmp, /var/tmp, /run Writable tmpfs mounts
tmpfs_size_mb int 0 Default size for tmpfs mounts (0 = Docker default)
pids_limit int 0 Max PIDs in container (0 = unlimited)
user string Container user, e.g. 1000:1000 or nobody
max_output_bytes int 1048576 Max stdout+stderr capture per exec (1 MB)
setup_command string Shell command run once after container creation
container_prefix string goclaw-sbx- Prefix for container names
workdir string /workspace Container working directory
idle_hours int 24 Prune containers idle longer than N hours
max_age_days int 7 Prune containers older than N days
prune_interval_min int 5 Background prune check interval (minutes)

Workspace Access

The workspace directory is mounted at /workspace inside the container:

  • none — no filesystem mount; container has no access to your project files
  • ro — read-only mount; agent can read files but cannot write
  • rw — read-write mount (default); agent can read and write project files

Container Lifecycle

  1. Creation — on first exec call for a scope key, docker run -d ... sleep infinity starts a long-lived container.
  2. Execution — each command runs via docker exec inside the running container.
  3. Pruning — a background goroutine checks every prune_interval_min minutes and destroys containers that have been idle longer than idle_hours or exist longer than max_age_days.
  4. Destructiondocker rm -f <id> is called on pruning, session end, or ReleaseAll at shutdown.

Container names follow the pattern goclaw-sbx-<sanitized-scope-key>, where the scope key is derived from the session key, agent ID, or "shared" depending on the configured scope.

Setup with docker-compose

Build the sandbox image first:

docker build -t goclaw-sandbox:bookworm-slim -f Dockerfile.sandbox .

Then add the sandbox overlay to your compose command:

docker compose \
  -f docker-compose.yml \
  -f docker-compose.postgres.yml \
  -f docker-compose.sandbox.yml \
  up

The docker-compose.sandbox.yml overlay mounts the Docker socket and sets sandbox environment variables:

services:
  goclaw:
    build:
      args:
        ENABLE_SANDBOX: "true"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - GOCLAW_SANDBOX_MODE=all
      - GOCLAW_SANDBOX_IMAGE=goclaw-sandbox:bookworm-slim
      - GOCLAW_SANDBOX_WORKSPACE_ACCESS=rw
      - GOCLAW_SANDBOX_SCOPE=session
      - GOCLAW_SANDBOX_MEMORY_MB=512
      - GOCLAW_SANDBOX_TIMEOUT_SEC=300
      - GOCLAW_SANDBOX_NETWORK=false
    group_add:
      - ${DOCKER_GID:-999}

Security note: Mounting the Docker socket gives the GoClaw container control over the host Docker daemon. Only use sandbox mode in environments where you trust the GoClaw process itself.

Examples

Sandbox only sub-agents, not the main agent

GOCLAW_SANDBOX_MODE=non-main

The main and default agents run commands on the host. All other agents (sub-agents, specialized workers) are sandboxed.

Read-only workspace with custom setup

{
  "sandbox": {
    "mode": "all",
    "workspace_access": "ro",
    "setup_command": "pip install -q pandas numpy",
    "memory_mb": 1024,
    "timeout_sec": 120
  }
}

The setup_command runs once after the container is created. Use it to pre-install dependencies so they are available on every subsequent exec.

Check active sandbox containers

GET /v1/sandbox/stats
{
  "mode": "all",
  "image": "goclaw-sandbox:bookworm-slim",
  "active": 3,
  "containers": {
    "agent:session-abc123": "a1b2c3d4e5f6",
    "agent:session-def456": "b2c3d4e5f6a1"
  }
}

Common Issues

Issue Cause Fix
docker not available in logs Docker daemon not running or socket not mounted Start Docker; ensure socket is mounted in compose
Commands fall back to host execution Docker unavailable at exec time Check sandbox unavailable, falling back to host exec warning in logs
docker run failed on container creation Image not found or insufficient permissions Build the sandbox image; check DOCKER_GID
Output truncated at 1 MB Command produced very large output Increase max_output_bytes or pipe output to a file
Container not cleaned up after session Pruner not running or idle_hours too high Lower idle_hours; check sandbox pruning started in logs
Write fails inside container workspace_access: ro or read_only_root: true with no tmpfs Switch to rw or add a tmpfs mount for the target path

What's Next

  • Custom Tools — define shell tools that also benefit from sandbox isolation
  • Exec Approval — require human approval before any command runs, sandboxed or not
  • Scheduling & Cron — run sandboxed agent turns on a schedule