> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stateset.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sandbox Architecture

> The full architecture of the StateSet Sandbox platform.

# StateSet Sandbox Architecture

> **Scope of this document:** a component-level overview suitable for new
> contributors and integrators. For the deep operational architecture —
> warm-pool internals, GKE-specific infrastructure, data layer, and event
> flows — see [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md), which is the
> canonical reference. For the Rust-controller-specific architecture see
> [`stateset-sandbox-controller/README.md`](stateset-sandbox-controller/README.md).

## Overview

StateSet Sandbox provides an isolated execution environment for running Claude Code CLI and AI agents. The system uses a controller-based architecture where a central API manages ephemeral sandbox pods on Kubernetes.

## System Components

### 1. Sandbox Controller

The controller is a Node.js/Express API that manages the lifecycle of sandbox pods.

* **Image**: `YOUR_REGISTRY/stateset/sandbox-controller:latest`
* **Replicas**: 3 (high availability)
* **Namespace**: `stateset-sandbox`
* **Exposed at**: `sandbox.stateset.com`

**Responsibilities:**

* Authenticate API requests (JWT or API key)
* Create/delete sandbox pods via Kubernetes API
* Execute commands in running sandboxes
* Stream output via SSE or WebSocket
* Manage file uploads/downloads
* Enforce resource limits and quotas

### 2. Sandbox Image

The sandbox is a multi-language runtime environment with Claude Code pre-installed.

* **Image**: `YOUR_REGISTRY/stateset/sandbox:latest`
* **Not deployed directly** - pulled on-demand by the controller

**Pre-installed Tools:**

| Category    | Tools                                         |
| ----------- | --------------------------------------------- |
| AI/ML       | Claude Code CLI, Anthropic SDK                |
| Node.js     | Node 22, TypeScript, tsx, ts-node             |
| Python      | Python 3.12, pip, anthropic, pydantic         |
| Go          | Go 1.22                                       |
| Rust        | Latest stable                                 |
| MCP Servers | filesystem, github, puppeteer                 |
| Dev Tools   | Git, GitHub CLI, ESLint, Prettier, Playwright |

***

## CI/CD Pipeline Flow

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                            GitLab Push                                       │
│                         (master branch)                                      │
└─────────────────────────────────────────────────────────────────────────────┘
                                   │
                                   ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                         CI/CD Pipeline                                       │
│                                                                              │
│  Step 1: Build Controller                                                    │
│  ────────────────────────                                                    │
│  docker build --target controller \                                          │
│    -t YOUR_REGISTRY/sandbox-controller:${CI_COMMIT_SHA}    │
│                                                                              │
│  Step 2: Build Sandbox                                                       │
│  ─────────────────────                                                       │
│  docker build --target sandbox \                                             │
│    -t YOUR_REGISTRY/sandbox:${CI_COMMIT_SHA}               │
│                                                                              │
│  Step 3: Push Both Images to Artifact Registry                              │
│                                                                              │
│  Step 4: Deploy Controller Only                                              │
│  ─────────────────────────────                                               │
│  kubectl apply -k k8s/  (deploys sandbox-controller to stateset-sandbox)    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
                                   │
                                   ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                    GKE Cluster (stateset-sandbox namespace)                  │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │  sandbox-controller (3 replicas)                                     │    │
│  │  Exposed at: sandbox.stateset.com                    │    │
│  │                                                                      │    │
│  │  ConfigMap:                                                          │    │
│  │  ┌─────────────────────────────────────────────────────────────┐    │    │
│  │  │ SANDBOX_IMAGE: YOUR_REGISTRY/sandbox:latest│    │    │
│  │  │ DEFAULT_CPUS: "2"                                            │    │    │
│  │  │ DEFAULT_MEMORY: "2Gi"                                        │    │    │
│  │  │ NAMESPACE: "stateset-sandbox"                                │    │    │
│  │  └─────────────────────────────────────────────────────────────┘    │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│  Sandbox pods: (none yet - created on demand)                               │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘
```

***

## Runtime Flow

### Creating and Using a Sandbox

```
┌─────────────────────────────────────────────────────────────────────────────┐
│  Your Application                                                            │
│                                                                              │
│  const client = new StateSetSandbox({                                       │
│    baseUrl: 'https://sandbox.stateset.com',                  │
│    authToken: 'sk-...'                                                       │
│  });                                                                         │
│  await client.create();                                                      │
└─────────────────────────────────────────────────────────────────────────────┘
                                   │
                                   │ POST /api/sandbox/create
                                   ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│  sandbox-controller                                                          │
│                                                                              │
│  1. Receives request                                                         │
│  2. Reads SANDBOX_IMAGE from env (ConfigMap)                                │
│  3. Calls K8s API to create pod:                                            │
│     ┌──────────────────────────────────────────────────────────────────┐    │
│     │ apiVersion: v1                                                    │    │
│     │ kind: Pod                                                         │    │
│     │ metadata:                                                         │    │
│     │   name: sandbox-org_xxx-abc123                                   │    │
│     │   namespace: stateset-sandbox                                     │    │
│     │ spec:                                                             │    │
│     │   containers:                                                     │    │
│     │     - image: YOUR_REGISTRY/sandbox:latest       │    │
│     │       env:                                                        │    │
│     │         - name: ANTHROPIC_API_KEY                                │    │
│     │           valueFrom: secretKeyRef...                              │    │
│     └──────────────────────────────────────────────────────────────────┘    │
│  4. Waits for pod to be ready                                               │
│  5. Returns sandbox_id to caller                                            │
└─────────────────────────────────────────────────────────────────────────────┘
                                   │
                                   ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│  Sandbox Pod (ephemeral)                                                     │
│  ────────────────────────                                                    │
│  Image: YOUR_REGISTRY/sandbox:latest                       │
│                                                                              │
│  Pre-installed:                                                              │
│  • Claude Code CLI (@anthropic-ai/claude-code)                              │
│  • Node.js 22, Python 3.12, Go 1.22, Rust                                   │
│  • MCP servers (filesystem, github, puppeteer)                              │
│  • Git, GitHub CLI                                                           │
│                                                                              │
│  Ready to execute commands via kubectl exec                                  │
└─────────────────────────────────────────────────────────────────────────────┘
```

### Command Execution Flow

```
┌──────────────┐     POST /api/sandbox/{id}/execute      ┌────────────────────┐
│              │ ──────────────────────────────────────► │                    │
│  Your App    │     { "command": "claude -p '...'" }    │  sandbox-controller│
│              │ ◄────────────────────────────────────── │                    │
└──────────────┘     SSE stream: stdout/stderr/exit      └────────────────────┘
                                                                   │
                                                                   │ kubectl exec
                                                                   ▼
                                                         ┌────────────────────┐
                                                         │   Sandbox Pod      │
                                                         │                    │
                                                         │  $ claude -p '...' │
                                                         │  (calls Anthropic) │
                                                         │                    │
                                                         └────────────────────┘
```

***

## API Endpoints

### Sandbox Management

| Method | Endpoint                  | Description                      |
| ------ | ------------------------- | -------------------------------- |
| POST   | `/api/sandbox/create`     | Create a new sandbox             |
| GET    | `/api/sandbox/:id`        | Get sandbox details              |
| GET    | `/api/sandbox/:id/status` | Get sandbox status (lightweight) |
| GET    | `/api/sandboxes`          | List all sandboxes               |
| POST   | `/api/sandbox/:id/stop`   | Stop and delete sandbox          |
| DELETE | `/api/sandbox/:id`        | Delete sandbox                   |

### File Operations

| Method | Endpoint                                   | Description            |
| ------ | ------------------------------------------ | ---------------------- |
| POST   | `/api/sandbox/:id/files`                   | Write files to sandbox |
| GET    | `/api/sandbox/:id/files?path=...`          | Read file (base64)     |
| GET    | `/api/sandbox/:id/files/download?path=...` | Download file (binary) |

### Command Execution

| Method | Endpoint                   | Description                          |
| ------ | -------------------------- | ------------------------------------ |
| POST   | `/api/sandbox/:id/execute` | Execute command (streaming optional) |
| WS     | `/ws`                      | WebSocket for real-time streaming    |

***

## Kubernetes Resources

### Namespace: `stateset-sandbox`

| Resource         | Name                        | Purpose                           |
| ---------------- | --------------------------- | --------------------------------- |
| Deployment       | `sandbox-controller`        | Controller API (3 replicas)       |
| Service          | `sandbox-controller`        | ClusterIP for internal access     |
| Ingress          | `sandbox-controller`        | External access via nginx         |
| ConfigMap        | `sandbox-controller-config` | Controller configuration          |
| Secret           | `sandbox-controller-auth`   | JWT secret, API keys              |
| Secret           | `anthropic-credentials`     | Anthropic API key for sandboxes   |
| ServiceAccount   | `sandbox-controller`        | K8s API access for pod management |
| Role/RoleBinding | `sandbox-controller`        | RBAC for pod CRUD operations      |
| NetworkPolicy    | `sandbox-controller`        | Network isolation rules           |
| ResourceQuota    | `sandbox-quota`             | Limit total sandbox resources     |

***

## Docker Build Targets

The unified `Dockerfile` supports multiple build targets:

```bash theme={null}
# Build controller image
docker build --target controller \
  -t YOUR_REGISTRY/stateset/sandbox-controller:latest .

# Build sandbox image
docker build --target sandbox \
  -t YOUR_REGISTRY/stateset/sandbox:latest .
```

| Target       | Base Image   | Size    | Purpose              |
| ------------ | ------------ | ------- | -------------------- |
| `controller` | node:22-slim | \~200MB | API server           |
| `sandbox`    | node:22-slim | \~2.5GB | Full dev environment |

***

## SDK Usage

### TypeScript SDK

```typescript theme={null}
import { StateSetSandbox, AgentRunner } from '@stateset/sandbox-sdk';

// Initialize client
const client = new StateSetSandbox({
  baseUrl: 'https://sandbox.stateset.com',
  authToken: process.env.STATESET_API_KEY!,
  orgId: 'org_xxx'
});

// Low-level: Create sandbox and execute commands
const sandbox = await client.create();
const result = await client.execute(sandbox.sandbox_id, {
  command: 'claude -p "Write a hello world in Python"'
});
console.log(result.stdout);
await client.stop(sandbox.sandbox_id);

// High-level: Use AgentRunner
const runner = new AgentRunner({
  sandbox: client,
  anthropicApiKey: process.env.ANTHROPIC_API_KEY!
});

const { events } = await runner.runAndCleanup({
  prompt: 'Create a REST API using FastAPI',
  systemPrompt: 'You are a senior backend developer',
  maxTurns: 10
});
```

***

## Security

### Sandbox Isolation

* **Ephemeral pods**: Each sandbox is a separate pod, destroyed after use
* **Non-root user**: Sandboxes run as UID 1000 (`sandbox` user)
* **Resource limits**: CPU/memory limits enforced per sandbox
* **Network policies**: Sandboxes have limited network access
* **Read-only filesystem**: Optional, configurable per deployment
* **gVisor runtime**: Optional sandboxing via `RUNTIME_CLASS` config

### Authentication

* **API Keys**: `Authorization: ApiKey sk-...`
* **JWT Tokens**: `Authorization: Bearer eyJ...`
* **Org isolation**: Sandboxes are scoped to organizations

***

## Configuration

### Environment Variables (Controller)

| Variable                | Default                   | Description                            |
| ----------------------- | ------------------------- | -------------------------------------- |
| `SANDBOX_IMAGE`         | `stateset/sandbox:latest` | Image for sandbox pods                 |
| `DEFAULT_CPUS`          | `2`                       | Default CPU limit                      |
| `DEFAULT_MEMORY`        | `2Gi`                     | Default memory limit                   |
| `DEFAULT_TIMEOUT`       | `600`                     | Sandbox timeout (seconds)              |
| `MAX_SANDBOXES_PER_ORG` | `5`                       | Max concurrent sandboxes per org       |
| `NAMESPACE`             | `stateset-sandbox`        | K8s namespace for pods                 |
| `LOG_LEVEL`             | `info`                    | Logging verbosity                      |
| `RUNTIME_CLASS`         | (unset)                   | Optional: `gvisor` for extra isolation |

***

## Directory Structure

```
stateset-sandbox/
├── Dockerfile                 # Multi-target: controller & sandbox
├── ARCHITECTURE.md           # This file
├── controller/
│   ├── src/
│   │   ├── index.ts          # Express server entrypoint
│   │   ├── routes.ts         # API route handlers
│   │   ├── sandbox-manager.ts # K8s pod management
│   │   └── middleware/
│   │       └── auth.ts       # JWT/API key authentication
│   ├── package.json
│   └── tsconfig.json
├── sdk/
│   └── src/
│       ├── client.ts         # StateSetSandbox client
│       ├── agent-runner.ts   # High-level agent runner
│       └── types.ts          # TypeScript types
├── docker/
│   ├── entrypoint.sh         # Sandbox container entrypoint
│   └── health-check.sh       # Sandbox health check
└── k8s/
    ├── deployment.yaml       # Controller deployment
    ├── service.yaml          # Controller service
    ├── ingress.yaml          # External access
    ├── configmap.yaml        # Controller config
    ├── secret.yaml           # Auth credentials
    ├── rbac.yaml             # ServiceAccount & roles
    ├── network-policy.yaml   # Network isolation
    ├── resource-quota.yaml   # Resource limits
    └── kustomization.yaml    # Kustomize config
```
