English | 简体中文
AI Agent Sandbox - A sandbox execution environment for AI Agents, built with Golang
mkdir /path/to/memory
mkdir /path/to/memory/workspaces
# Set the host path for persistent storage (workspace, prompts, etc.)
export LOCAL_MEMORY="/path/to/memory"
# On Linux, the container runs as UID 1000 which may differ from the host user, fix directory permissions to avoid Permission Denied
sudo chown -R 1000:1000 "/path/to/memory"
make docker-start- IndexPage: http://localhost:8080/
- API: http://localhost:8080/v1/
- VNC: http://localhost:8080/vnc/
- Terminal: http://localhost:8080/terminal/
- MCP: http://localhost:8080/mcp
- Health: http://localhost:8080/health
Run sandbox-server and mcp-hub on the host, merge stdout/stderr into a single log, and tail it:
make run-all # build, start both services, tail merged log at /tmp/sandbox.log
make stop-all # stop both services
make tail-log # re-attach to the merged logTwo Integration Methods:
-
MCP Hub: Built-in MCP protocol service providing standardized Tool interfaces (bash, file, web, etc.). Directly integrates with AI models supporting MCP like Claude and OpenAI. Combined with the Eino framework, you can implement a complete ReAct Agent with just a few lines of code.
-
Sandbox SDK: Provides a Go SDK for programmatic access to Bash, FileSystem, Grep, Web, JSONL, and other services. Can be wrapped as Tools for AI Agent calls or used directly for product development (file browser, Git management, LSP services, etc.).
sandbox/
├── cmd/
│ ├── sandbox-server/main.go # Main server entry
│ └── mcp-hub/main.go # MCP Hub entry
├── internal/
│ ├── api/
│ │ ├── router.go # Router configuration
│ │ ├── middleware/ # JWT auth, Logger, Context
│ │ └── handlers/ # Bash/File/Grep/JSONL/Terminal/Web/WS/Sandbox/Swagger
│ ├── services/
│ │ ├── bash/ # Bash command execution
│ │ ├── filesystem/ # Filesystem operations (manager, glob, grep, read, write, replacer, operations)
│ │ ├── jsonl/ # JSONL append / read / count
│ │ ├── terminal/ # Web terminal (PTY)
│ │ └── web/ # Web services (fetch, search)
│ ├── mcp/
│ │ ├── registry.go # MCP Tool registration
│ │ ├── server.go # MCP protocol server
│ │ └── tools/ # MCP Tools implementation
│ └── config/config.go
├── types/
│ ├── consts/ # Constants (env, headers)
│ └── model/ # Shared data models (bash, file, grep, web, jsonl, response)
├── pkg/
│ ├── ctxutil/ # Context utilities (cwd, log ID)
│ ├── logger/ # Plain-text logger wrapper
│ └── safe/ # Safety utility functions
├── docker/
│ ├── Dockerfile
│ ├── nginx/nginx.conf # Nginx gateway config
│ ├── scripts/
│ │ ├── supervisord.conf # Process management
│ │ └── entrypoint.sh
│ └── volumes/ # Volume mount examples
├── docs/
│ └── ENV.md # Environment variables reference
├── web/
│ ├── index.html # Web homepage
│ └── terminal/index.html # Web terminal frontend (xterm.js)
├── sdk/
│ └── go/ # Go SDK (bash, file, grep, web, jsonl)
├── examples/
│ ├── filesystem/ # Filesystem examples
│ └── web/ # Web examples
├── docker-compose.yaml
├── Makefile
└── go.mod
| Service | Port | Description |
|---|---|---|
| Nginx | 8080 | Unified entry, reverse proxy |
| Sandbox Server | 8000 | HTTP API + WebSocket API |
| MCP Hub | 8001 | MCP protocol service |
| noVNC | 6080 | VNC Web client |
| VNC Server | 5900 | VNC service |
| Chromium CDP | 9222 | Chrome DevTools Protocol (internal, used by agent-browser) |
The container manages 8 processes via Supervisord, started in priority order:
| # | Program | Command | Priority | Purpose |
|---|---|---|---|---|
| 1 | xvfb | Xvfb :99 -screen 0 1280x1024x24 |
100 | Virtual framebuffer X server, creates virtual display :99 |
| 2 | fluxbox | fluxbox |
200 | Lightweight window manager |
| 3 | x11vnc | x11vnc -display :99 -forever -shared -rfbport 5900 -nopw |
300 | VNC server, shares virtual display to port 5900 |
| 4 | websockify | websockify --web=/usr/share/novnc 6080 localhost:5900 |
400 | WebSocket proxy, enables noVNC web access |
| 5 | chromium | chromium-browser --no-sandbox --remote-debugging-port=9222 ... |
500 | Chromium browser with CDP remote debugging |
| 6 | sandbox-server | sandbox-server |
600 | Sandbox main service (Bash/File/Grep/JSONL/Web API) |
| 7 | mcp-hub | mcp-hub |
700 | MCP Hub service (MCP protocol + Tool interfaces) |
| 8 | nginx | nginx -g "daemon off;" |
800 | Nginx reverse proxy gateway |
Startup Order: Xvfb → Fluxbox → x11vnc → websockify → Chromium → sandbox-server → mcp-hub → Nginx
Architecture Notes:
- Programs 1-4 form the VNC Remote Desktop stack, allowing browser access to virtual desktop
- Program 5 is the Chromium Browser, used internally (e.g. by the external agent-browser) via CDP port 9222
- Programs 6-7 are Business Services, providing API and MCP protocol
- Program 8 is the Gateway, unified external service exposure
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check |
/docs |
GET | Swagger UI documentation |
/v1/openapi.json |
GET | OpenAPI specification |
/v1/sandbox |
GET | Get sandbox environment info |
| Endpoint | Method | Description |
|---|---|---|
/v1/bash/exec |
POST | Execute Bash command |
/v1/bash/exec/stream |
POST | Stream execute Bash command |
| Endpoint | Method | Description |
|---|---|---|
/v1/file/read |
POST | Read file |
/v1/file/write |
POST | Write file |
/v1/file/append |
POST | Append to file |
/v1/file/list |
POST | List directory |
/v1/file/delete |
POST | Delete file |
/v1/file/move |
POST | Move file |
/v1/file/copy |
POST | Copy file |
/v1/file/mkdir |
POST | Create directory |
/v1/file/exists |
GET | Check if file exists |
/v1/file/stat |
POST | Get file metadata |
/v1/file/upload |
POST | Upload file (multipart) |
/v1/file/download |
GET | Download file (inline preview for browsers) |
/v1/grep/search |
POST | Grep search file content |
| Endpoint | Method | Description |
|---|---|---|
/v1/jsonl/count |
POST | Count lines in a JSONL file |
/v1/jsonl/read |
POST | Read lines from a JSONL file |
/v1/jsonl/append |
POST | Append line(s) to a JSONL file |
| Endpoint | Method | Description |
|---|---|---|
/v1/web/fetch |
POST | Fetch web content |
/v1/web/search |
POST | Web search |
| Endpoint | Method | Description |
|---|---|---|
/mcp |
WebSocket | MCP protocol endpoint |
/websockify |
WebSocket | VNC (noVNC) remote desktop proxy |
/terminal/ |
GET | Web terminal page |
/v1/terminal/ws |
WebSocket | Terminal WebSocket connection |
/v1/ws |
WebSocket | General WebSocket interface |
package main
import (
"fmt"
"github.com/deep-agent/sandbox/sdk/go/http"
"github.com/deep-agent/sandbox/types/model"
)
func main() {
client := http.NewClient("http://localhost:8080")
// Get sandbox info
ctx, _ := client.GetContext()
fmt.Printf("HomeDir: %s\n", ctx.HomeDir)
// Execute Bash command
result, _ := client.BashExec(&model.BashExecRequest{
Command: "ls -la",
})
fmt.Println(result.Output)
// Read file
content, _ := client.FileRead(&model.FileReadRequest{
File: "/home/sandbox/.bashrc",
})
fmt.Println(content.Content)
// Check if file exists
exists, _ := client.FileExists("/home/sandbox/.bashrc")
fmt.Printf("File exists: %v\n", exists.Exists)
// Append to a JSONL file
_ = client.JSONLAppendLine(&model.JSONLAppendRequest{
File: "/home/sandbox/workspaces/events.jsonl",
JSONString: []string{`{"event":"hello"}`},
})
}MCP Hub provides the following tools:
| Tool | Description |
|---|---|
Bash |
Execute Bash command |
Glob |
File glob matching |
Grep |
File content search |
Read |
Read file content |
Write |
Write file content |
Edit |
Edit file (search & replace) |
| Tool | Description |
|---|---|
WebFetch |
Fetch web content |
WebSearch |
Web search |
| Variable | Default | Description |
|---|---|---|
SANDBOX_SRV_PORT |
8000 | Sandbox Server port |
MCP_HUB_PORT |
8001 | MCP Hub port |
SUPERVISOR_CONF_DIR |
/home/sandbox/app.supervisor.d | Supervisord config directory |
APP_SERVICE_PORT |
9000 | User HTTP service port (proxied via /app/) |
JWT_SECRET |
- | JWT HMAC shared secret (optional) |
JWT_AUTH_REQUIRED |
false | Enforce authentication (optional) |
ENABLE_MCP |
true | Enable MCP Hub process |
ENABLE_BROWSER |
true | Enable Chromium process |
ENABLE_VNC |
true | Enable VNC/noVNC processes |
TZ |
Asia/Shanghai | Timezone |
Setting JWT_SECRET enables Authorization: Bearer <token> validation (HS256/384/512) for /v1 routes.
If JWT_AUTH_REQUIRED=true is set, all requests will be rejected (returning 401) even if JWT_SECRET is not configured, preventing accidental exposure of unauthenticated services.
Example:
export JWT_SECRET="your-secret-key"
export JWT_AUTH_REQUIRED="true" # Optional, enforce authThese variables are consumed by docker-compose on the host side.
| Variable | Default | Description |
|---|---|---|
HOST_PORT |
8080 | Host port mapped to container port 8080 |
LOCAL_MEMORY |
./docker/volumes | Host base path for persistent storage; workspaces subdirectory is mounted to /home/sandbox/workspaces |
LOCAL_SUPERVISOR_CONF |
./docker/volumes/app.supervisor.d | Host path mounted to /home/sandbox/app.supervisor.d |
LOCAL_USERDATA |
./docker/volumes/userdata | Host path mounted to /home/sandbox/userdata |
LOCAL_INIT_SCRIPTS |
./docker/volumes/init.d | Host path mounted to /docker-entrypoint.d |
| Variable | Default | Description |
|---|---|---|
HTTP_PROXY |
- | Proxy for docker build |
HTTPS_PROXY |
- | Proxy for docker build |
NO_PROXY |
localhost,127.0.0.1 | No-proxy list for docker build |
Sandbox supports user-injected custom programs and scripts through the following extension mechanisms:
docker/volumes/
├── workspaces/ # User workspace, mounted to /home/sandbox/workspaces
├── app.supervisor.d/ # Supervisord config dir, mounted to /home/sandbox/app.supervisor.d
├── userdata/ # User data dir, mounted to /home/sandbox/userdata (scripts, binaries)
└── init.d/ # Init scripts dir, mounted to /docker-entrypoint.d
Place Supervisord configuration files in docker/volumes/app.supervisor.d/ directory to register background services.
Auto-register with Supervisord: Create .conf files in the app.supervisor.d directory:
docker/volumes/app.supervisor.d/
└── my-service.conf # supervisord config
my-service.conf example:
[program:my-service]
command=/home/sandbox/userdata/my-service --port=9000
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
priority=900Place user scripts or binaries in docker/volumes/userdata/ directory, accessible at /home/sandbox/userdata/ after container startup.
docker/volumes/userdata/
├── my-service # Executable program
├── script.sh # Shell script
└── data.json # Data file
Place scripts in docker/volumes/init.d/ directory, automatically executed in alphabetical order at container startup:
docker/volumes/init.d/
├── 01-setup-env.sh # Environment setup
├── 02-install-deps.sh # Install dependencies
└── 03-start-services.sh # Start services
Script example:
#!/bin/bash
echo "Setting up environment..."
pip install requests numpy
npm install -g typescriptExecution Rules:
.shfiles: Execute if executable, otherwise source- Other files: Execute if executable
If your user program is an HTTP service, access it via the /app/ path. Nginx automatically forwards requests to the APP_SERVICE_PORT (default 9000).
User request: http://localhost:8080/app/api/hello
↓
Nginx forwards: http://127.0.0.1:9000/api/hello
↓
User service handles
Usage:
- User service listens on
APP_SERVICE_PORT - Access via
/app/path
Custom Port:
APP_SERVICE_PORT=3000 docker-compose upUsers can create custom images based on the Sandbox image:
FROM your-registry/sandbox:latest
USER root
RUN apt-get update && apt-get install -y your-package
COPY --chown=sandbox:sandbox my-binary /home/sandbox/userdata/
COPY --chown=sandbox:sandbox my-init.sh /docker-entrypoint.d/
USER sandboxCustomize mount paths via docker-compose or environment variables:
LOCAL_MEMORY=/path/to/memory \
LOCAL_SUPERVISOR_CONF=/path/to/app.supervisor.d \
LOCAL_USERDATA=/path/to/userdata \
LOCAL_INIT_SCRIPTS=/path/to/init.d \
APP_SERVICE_PORT=3000 \
docker-compose upApache License 2.0
