Agent Sandbox Hive
Scalable sandbox cluster for LLM Agents and Agent RL Rollouts
Quick Start • Architecture • Deployment • Configuration
Ash provides on-demand, isolated Kubernetes-based sandbox environments for AI agents. Agents connect via MCP (Model Context Protocol) to execute code, browse the web, and run tools safely. Spawn thousands of sandboxes dynamically with automatic routing, resource limits, and lifecycle management.
|
Isolated Execution Each agent gets its own container with resource limits, network isolation, and automatic cleanup. |
MCP Native First-class support for Model Context Protocol. Plug in terminal, web fetch, search, and custom tools. |
Scale to Thousands Dynamic provisioning on Kubernetes. Auto-routing via Redis. Works on EKS, GKE, or local. |
If you don't have an existing Kubernetes cluster, see Deployment first.
import asyncio
from client import SandboxClient, SandboxConfig
async def main():
config = SandboxConfig(
control_plane_url="http://your-control-plane:80",
gateway_url="http://your-gateway:80",
)
# Context manager handles cleanup automatically
with SandboxClient(config) as client:
# Spawn a sandbox
sandbox = client.spawn()
print(f"Sandbox ready: {sandbox.uuid}")
# Connect via MCP and use tools
mcp = client.connect()
async with mcp:
tools = await mcp.list_tools()
print(f"Tools: {[t.name for t in tools]}")
# Execute a shell command
result = await mcp.call_tool(
"terminal-controller_execute_command",
{"command": "echo 'Hello from sandbox!'"}
)
print(result.content[0].text)
asyncio.run(main())See client/demo.py for a complete benchmark example.
mcp = client.connect()
async with mcp:
# Terminal - execute commands
await mcp.call_tool("terminal-controller_execute_command", {
"command": "python --version"
})
# Fetch - get web content
await mcp.call_tool("fetch_fetch", {
"url": "https://example.com"
})
# Search - web search
await mcp.call_tool("ddgs_search_mcp_search", {
"query": "python asyncio tutorial",
"max_results": 5
})The default image timemagic/rl-mcp:general-1.7 includes:
| Tool | Description |
|---|---|
terminal-controller |
Execute shell commands in the sandbox |
fetch |
Fetch web content from URLs |
ddgs_search |
Web search via DuckDuckGo |
Bring your own tools — provide a custom image with your MCP server. See sandbox-recipe/ for examples.
┌──────────────────────────────────────────────────────────┐
│ Kubernetes │
┌─────────┐ │ │
│ │ POST /spawn │ ┌───────────────┐ ┌───────────────────┐ │
│ Agent │─────────────────────▶│ │ Control Plane │─────────▶│ Sandbox Pod │ │
│ │ │ └───────┬───────┘ Create │ ┌─────────────┐ │ │
└────┬────┘ │ │ │ │ FastMCP │ │ │
│ │ │ Store route │ │ Server │ │ │
│ │ ▼ │ └─────────────┘ │ │
│ │ ┌───────────────┐ └────────▲──────────┘ │
│ │ │ Redis │ │ │
│ │ │ │ │ │
│ │ └───────▲───────┘ │ │
│ MCP + X-Session-ID │ │ Lookup │ Proxy │
│ │ ┌───────┴───────┐ │ │
└──────────────────────────▶│ │ Gateway │───────────────────┘ │
│ └───────────────┘ │
└──────────────────────────────────────────────────────────┘
| Component | Language | Description |
|---|---|---|
| Control Plane | Go | REST API for spawning/destroying sandbox pods |
| Gateway | Go | Routes MCP requests using X-Session-ID header |
| Sandbox | Python | Isolated container running FastMCP server |
| Redis | — | Session → sandbox routing table |
- Kubernetes cluster (EKS, GKE, or Minikube)
kubectlconfigured- Docker (for custom images)
1. Create EKS Nodegroups
# Infrastructure nodegroup (control-plane, gateway, redis)
eksctl create nodegroup \
--cluster your-cluster \
--name infra \
--node-type m5.large \
--nodes 3 \
--node-labels "eks.amazonaws.com/nodegroup=infra"
# Sandbox nodegroup (where sandbox pods run)
eksctl create nodegroup \
--cluster your-cluster \
--name sandbox \
--node-type m5.xlarge \
--nodes-min 0 \
--nodes-max 100 \
--node-labels "eks.amazonaws.com/nodegroup=sandbox"2. Build Images (Optional)
Skip if using pre-built images.
cd k8s-scaffold
make build
docker push timemagic/ash:control-plane-0.1
docker push timemagic/ash:gateway-0.13. Deploy to Kubernetes
cd k8s-config
# Create namespace and RBAC
kubectl apply -f rbac.yaml
# Deploy infrastructure
kubectl apply -f infra.yaml
# Wait for ready
kubectl -n ash rollout status deploy/redis
kubectl -n ash rollout status deploy/control-plane
kubectl -n ash rollout status deploy/gateway4. Get Service URLs
kubectl -n ash get svc control-plane gateway
# Example output:
# NAME TYPE EXTERNAL-IP PORT(S)
# control-plane LoadBalancer abc123.us-west-2.elb.amazonaws.com 80:31234/TCP
# gateway LoadBalancer xyz789.us-west-2.elb.amazonaws.com 80:31235/TCP5. Configure Client
from client import SandboxClient, SandboxConfig
config = SandboxConfig(
control_plane_url="http://abc123.us-west-2.elb.amazonaws.com",
gateway_url="http://xyz789.us-west-2.elb.amazonaws.com",
node_selector={"eks.amazonaws.com/nodegroup": "sandbox"},
)
client = SandboxClient(config)
sandbox = client.spawn()# Start minikube and deploy everything
make all-local
# Get service URLs
minikube service control-plane -n ash --url
minikube service gateway -n ash --urlfrom client import SandboxClient, SandboxConfig, ResourceReq, ResourceSpec
config = SandboxConfig(
# Connection URLs
control_plane_url="http://control-plane:80",
gateway_url="http://gateway:80",
# Container settings
image="custom-sandbox:latest",
ports=[3000],
env={"DEBUG": "true", "API_KEY": "..."},
resources=ResourceReq(
requests=ResourceSpec(cpu="100m", memory="256Mi"),
limits=ResourceSpec(cpu="500m", memory="512Mi"),
),
node_selector={"gpu": "true"},
# Timeouts
timeout=300,
mcp_timeout=180,
)
client = SandboxClient(config)| Option | Default | Description |
|---|---|---|
control_plane_url |
— | Control plane endpoint (required) |
gateway_url |
— | Gateway endpoint for MCP (required) |
image |
timemagic/rl-mcp:general-1.7 |
Sandbox container image |
ports |
[3000] |
Ports to expose |
env |
{} |
Environment variables |
resources |
None |
CPU/memory requests & limits |
node_selector |
{} |
Kubernetes node selector |
timeout |
300 |
Spawn/destroy timeout (seconds) |
mcp_timeout |
180 |
MCP call timeout (seconds) |
# GPU nodes
config = SandboxConfig(..., node_selector={"gpu": "true"})
# Specific EKS nodegroup
config = SandboxConfig(..., node_selector={"eks.amazonaws.com/nodegroup": "sandbox"})
# Specific instance type
config = SandboxConfig(..., node_selector={"node.kubernetes.io/instance-type": "m5.large"})# Reuse config for multiple sandboxes
config = SandboxConfig(
control_plane_url="http://control-plane:80",
gateway_url="http://gateway:80",
)
# Each client manages one sandbox
clients = [SandboxClient(config) for _ in range(10)]
sandboxes = [c.spawn() for c in clients]ash/
├── client/ # Python client library
├── example/ # Usage examples
├── k8s-scaffold/ # Control plane & gateway (Go)
├── k8s-config/ # Kubernetes manifests
└── sandbox-recipe/ # Sandbox container images
Apache 2.0 — See LICENSE for details.
Built for scalable AI agent infrastructure