Den
Self-hosted sandbox runtime for AI agents
Getting Started •
API Reference •
SDKs •
MCP Integration •
Configuration
English | 中文
Den gives AI agents secure, isolated sandbox environments to execute code. It's the open-source, self-hosted alternative to E2B and similar cloud sandbox services.
Single binary. Zero config. Works with any AI framework.
curl -sSL https://get.den.dev | sh
den serve
What's New
Storage Layer (v0.0.2)
- Configurable tmpfs — Per-sandbox tmpfs size overrides (e.g.
/tmp with 128MB instead of default 256MB)
- Persistent volumes — Docker named volumes that survive sandbox destruction
- Shared volumes — Mount the same volume across multiple sandboxes (read-write or read-only)
- S3 sync (hooks mode) — Automatically download files from S3 on sandbox create, upload back on destroy
- S3 sync (on-demand) — Import/export files between sandboxes and S3 via REST API
- S3 FUSE mount — Mount an S3 bucket as a filesystem inside the sandbox (requires
SYS_ADMIN)
- Go, TypeScript, Python SDKs — Updated with full storage type support
See Configuration > Storage for setup details.
Why Den?
AI agents need to run code, but running untrusted code on your machine is dangerous. Den solves this by providing:
- Isolated containers — Each sandbox runs in its own Docker container with dropped capabilities, read-only rootfs, PID limits, and resource constraints
- Simple REST API — Create sandboxes, execute commands, read/write files, manage snapshots — all via HTTP
- WebSocket streaming — Real-time command output for interactive use cases
- MCP server — Native Model Context Protocol support for Claude, Cursor, and other AI tools
- Snapshot/Restore — Save sandbox state and restore it later for reproducible environments
- Storage — Persistent volumes, shared volumes, configurable tmpfs, and S3 integration
- Go + TypeScript + Python SDKs — First-class client libraries
Quick Start
Prerequisites
- Docker running locally
- Go 1.21+ (to build from source)
Run the Server
# Build and run
go build -o den ./cmd/den
./den serve
# Or with custom config
./den serve --config den.yaml
Create a Sandbox and Run Code
# Create a sandbox
curl -X POST http://localhost:8080/api/v1/sandboxes \
-H 'Content-Type: application/json' \
-d '{"image": "ubuntu:22.04"}'
# → {"id":"abc123","status":"running",...}
# Execute a command
curl -X POST http://localhost:8080/api/v1/sandboxes/abc123/exec \
-H 'Content-Type: application/json' \
-d '{"cmd": ["python3", "-c", "print(2+2)"]}'
# → {"exit_code":0,"stdout":"4\n","stderr":""}
# Write a file
curl -X PUT 'http://localhost:8080/api/v1/sandboxes/abc123/files?path=/tmp/hello.py' \
-d 'print("Hello from sandbox!")'
# Read a file
curl 'http://localhost:8080/api/v1/sandboxes/abc123/files?path=/tmp/hello.py'
# Destroy the sandbox
curl -X DELETE http://localhost:8080/api/v1/sandboxes/abc123
Use with Go SDK
package main
import (
"context"
"fmt"
client "github.com/den/den/pkg/client"
)
func main() {
c := client.New("http://localhost:8080", client.WithAPIKey("your-key"))
ctx := context.Background()
// Create sandbox
sb, _ := c.CreateSandbox(ctx, client.SandboxConfig{
Image: "ubuntu:22.04",
})
// Run code
result, _ := c.Exec(ctx, sb.ID, client.ExecOpts{
Cmd: []string{"echo", "Hello from Go SDK!"},
})
fmt.Println(result.Stdout)
// Clean up
c.DestroySandbox(ctx, sb.ID)
}
Use with MCP (Claude Code, Cursor)
# Start the MCP server (stdio mode)
den mcp
Add to your Claude Code config (~/.claude/claude_desktop_config.json):
{
"mcpServers": {
"den": {
"command": "den",
"args": ["mcp"]
}
}
}
Now Claude can create sandboxes, run code, and manage files directly.
Features
| Feature |
Description |
| Sandbox CRUD |
Create, list, get, stop, destroy containers |
| Command Execution |
Sync exec with exit code, stdout, stderr |
| Streaming Exec |
WebSocket-based real-time output |
| File Operations |
Read, write, list, mkdir, delete files inside sandboxes |
| File Upload/Download |
Multipart upload and direct download |
| Snapshots |
Save and restore sandbox state via docker commit |
| Persistent Volumes |
Docker named volumes that survive sandbox destruction |
| Shared Volumes |
Mount the same volume across sandboxes (RW or RO) |
| Configurable Tmpfs |
Per-sandbox tmpfs size and option overrides |
| S3 Sync |
Import/export files via hooks, on-demand API, or FUSE mount |
| Port Forwarding |
Expose sandbox ports to host (bound to 127.0.0.1) |
| Resource Limits |
CPU, memory, PID limits per sandbox |
| Auto-Expiry |
Sandboxes auto-destroy after configurable timeout |
| Rate Limiting |
Per-key rate limiting on all API endpoints |
| API Key Auth |
Header-based authentication with constant-time comparison |
| MCP Server |
stdio-based Model Context Protocol for AI tool integration |
| Dashboard |
Embedded web UI for monitoring and management |
Security
Den takes security seriously. Every sandbox runs with:
- Dropped capabilities —
ALL capabilities dropped, minimal set added back
- Read-only root filesystem — Only tmpfs mounts and explicit volumes are writable
- PID limits — Default 256 processes per container
- No new privileges —
no-new-privileges security option
- Network isolation — Containers on internal Docker network
- Port binding — Forwarded ports bind to
127.0.0.1 only
- Path validation — Null byte and traversal protection on all file operations
- Constant-time auth — API key comparison resistant to timing attacks
- No error leaking — Internal errors are logged, generic messages returned to clients
Architecture
┌──────────────────────────────────────────────────────┐
│ Clients │
│ CLI │ Go SDK │ TS SDK │ Python SDK │ MCP │
└───────┴──────────┴──────────┴──────────────┴────────┘
│
┌─────┴─────┐
│ HTTP API │ chi router + middleware
│ WebSocket │ gorilla/websocket
└─────┬─────┘
│
┌─────┴─────┐
│ Engine │ Lifecycle, reaper, limits
└──┬────┬──┘
│ │
┌────────────┘ └────────────┐
┌───────┴───────┐ ┌──────────┴─────────┐
│ Docker Runtime│ │ Storage Layer │
│ Docker SDK │ │ Volumes, S3, Tmpfs│
└───────┬───────┘ └──────────┬─────────┘
│ │
┌───────┴───────┐ ┌──────────┴─────────┐
│ Containers │ │ S3 / MinIO │
│ (sandboxes) │ │ Docker Volumes │
└───────────────┘ └────────────────────┘
Benchmarked on Apple Silicon (M-series):
| Operation |
Latency |
Notes |
| API health check |
< 1ms |
Near-zero overhead |
| Create sandbox |
~100ms |
Cold start; warm pool brings this to ~5ms |
| Execute command |
~30ms |
Including Docker exec round-trip |
| Read file |
~10ms |
Docker tar API |
| Write file |
~40ms |
Docker tar API with auto-mkdir |
| Destroy sandbox |
~1s |
SIGTERM + cleanup |
| Parallel create (5x) |
~42ms/each |
Concurrent container creation |
| Parallel exec (10x) |
~7ms/each |
Concurrent command execution |
vs. Alternatives
|
Den |
E2B |
Daytona |
Modal |
| Sandbox create |
~100ms |
~150ms |
~90ms |
2-5s |
| Pricing |
Free (OSS) |
$0.10/min+ |
Free (complex) |
$0.10/min+ |
| Setup |
curl | sh |
SDK + API key |
Docker + K8s |
SDK + API key |
| Self-hosted |
Yes |
No |
Yes (heavy) |
No |
| Offline |
Yes |
No |
Partial |
No |
Documentation
CLI
den serve # Start API server
den create --image ubuntu:22.04 # Create sandbox
den ls # List sandboxes
den exec <id> -- echo hello # Execute command
den rm <id> # Destroy sandbox
den snapshot create <id> # Create snapshot
den snapshot restore <snap-id> # Restore snapshot
den stats # System stats
den mcp # Start MCP server
den version # Version info
Configuration
server:
host: "0.0.0.0"
port: 8080
rate_limit_rps: 10
rate_limit_burst: 20
sandbox:
default_image: "ubuntu:22.04"
default_timeout: "30m"
max_sandboxes: 50
default_memory: 536870912 # 512MB
allow_volumes: true
allow_s3: true
max_volumes_per_sandbox: 5
s3:
endpoint: "http://localhost:9000" # MinIO or S3-compatible
region: "us-east-1"
access_key: "minioadmin"
secret_key: "minioadmin"
auth:
enabled: true
api_keys:
- "your-secret-key"
See Configuration Guide for all options.
Contributing
# Clone and build
git clone https://github.com/den/den
cd den
go build ./cmd/den
# Run tests
go test ./internal/... -race
# Run with race detector
go test ./internal/... -count=1 -race -v
License
AGPL-3.0 — See LICENSE for details.