Skip to content

dreamyang-liu/Ash

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ash Logo

Ash

Agent Sandbox Hive

Scalable sandbox cluster for LLM Agents and Agent RL Rollouts

Quick StartArchitectureDeploymentConfiguration

Go Python Kubernetes MCP License


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.


Quick Start

If you don't have an existing Kubernetes cluster, see Deployment first.

Basic Usage

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.


Using MCP Tools

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
    })

Available MCP Tools

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.



Architecture

                                 ┌──────────────────────────────────────────────────────────┐
                                 │                      Kubernetes                          │
┌─────────┐                      │                                                          │
│         │   POST /spawn        │  ┌───────────────┐          ┌───────────────────┐        │
│  Agent  │─────────────────────▶│  │ Control Plane │─────────▶│    Sandbox Pod    │        │
│         │                      │  └───────┬───────┘  Create  │  ┌─────────────┐  │        │
└────┬────┘                      │          │                  │  │  FastMCP    │  │        │
     │                           │          │ Store route      │  │  Server     │  │        │
     │                           │          ▼                  │  └─────────────┘  │        │
     │                           │  ┌───────────────┐          └────────▲──────────┘        │
     │                           │  │     Redis     │                   │                   │
     │                           │  │               │                   │                   │
     │                           │  └───────▲───────┘                   │                   │
     │   MCP + X-Session-ID      │          │ Lookup                    │ Proxy             │
     │                           │  ┌───────┴───────┐                   │                   │
     └──────────────────────────▶│  │    Gateway    │───────────────────┘                   │
                                 │  └───────────────┘                                       │
                                 └──────────────────────────────────────────────────────────┘

Components

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


Deployment

Prerequisites

  • Kubernetes cluster (EKS, GKE, or Minikube)
  • kubectl configured
  • Docker (for custom images)

AWS EKS

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.1
3. 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/gateway
4. 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/TCP
5. 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()

Local (Minikube)

# Start minikube and deploy everything
make all-local

# Get service URLs
minikube service control-plane -n ash --url
minikube service gateway -n ash --url


Configuration

SandboxConfig

from 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)

Config Options

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)

Node Scheduling

# 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"})

Multiple Sandboxes

# 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]


Repository Structure

ash/
├── client/           # Python client library
├── example/          # Usage examples
├── k8s-scaffold/     # Control plane & gateway (Go)
├── k8s-config/       # Kubernetes manifests
└── sandbox-recipe/   # Sandbox container images


License

Apache 2.0 — See LICENSE for details.



Built for scalable AI agent infrastructure

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors