architecture

$npx mdskill add cloudflare/sandbox-sdk/architecture

Explains the codebase structure and request flow for the Sandbox project

  • Helps navigate the monorepo and three-layer architecture for new developers
  • Describes SDK, shared utilities, and container runtime components and their locations
  • Details how client methods interact with the container runtime through the Sandbox DO
  • Clarifies the request flow from Worker to container and back

SKILL.md

.github/skills/architectureView on GitHub ↗
---
name: architecture
description: Use when navigating the codebase for the first time, adding a new client method, adding a new container handler/service, or understanding how a request flows from Worker through the Sandbox DO into the container. Covers the three-layer architecture, client pattern, container runtime structure, and monorepo layout. (project)
---

# Architecture

## Three-Layer Architecture

1. **`@cloudflare/sandbox` (`packages/sandbox/`)** — Public SDK published to npm
   - `Sandbox` class: Durable Object that manages the container lifecycle
   - Modular HTTP clients per capability (`CommandClient`, `FileClient`, `ProcessClient`, …)
   - `CodeInterpreter`: high-level API for Python/JS with structured outputs
   - `proxyToSandbox()`: request handler for preview URL routing

2. **`@repo/shared` (`packages/shared/`)** — Internal shared utilities
   - Type definitions used by both SDK and container runtime
   - Centralized error classes (`packages/shared/src/errors/`) and logging
   - **Not published to npm**

3. **`@repo/sandbox-container` (`packages/sandbox-container/`)** — Container runtime
   - Bun-based HTTP server running inside the Docker container
   - Dependency-injection container in `core/container.ts`
   - Route handlers for command execution, file operations, process management
   - **Not published to npm** (bundled into the Docker image)

## Request Flow

Primary control path:

```
Worker
  → Sandbox DO (packages/sandbox)
    → ContainerControlClient (packages/sandbox/src/container-control/)
      → capnweb over /rpc WebSocket
        → SandboxControlAPI (packages/sandbox-container/src/control-plane/)
          → container services
            → Shell commands / filesystem
```

Route-based compatibility path:

```
Worker
  → Sandbox DO (packages/sandbox)
    → SandboxClient / clients/transport
      → Container HTTP API on port 3000 (packages/sandbox-container)
        → Router / handlers
          → container services
            → Shell commands / filesystem
```

Errors flow back the same path: container → Sandbox DO → Worker, using the custom error classes in `packages/shared/src/errors/` keyed by the `ErrorCode` enum.

## Primary Control Path

The primary Sandbox Durable Object to container control path is the container-control/control-plane path:

- SDK side: `packages/sandbox/src/container-control/`
- Container side: `packages/sandbox-container/src/control-plane/`
- Current wire implementation: capnweb RPC over the `/rpc` WebSocket route

Control-channel/transport-layer capabilities belong in this path. Treat capnweb/RPC as the current implementation detail, not the architectural boundary.

The shared `@repo/shared` `SandboxAPI` interface remains named `SandboxAPI` because it defines the current control API contract used by both sides.

## Route-Based Compatibility Path (`packages/sandbox/src/clients/`)

`packages/sandbox/src/clients/` and `packages/sandbox/src/clients/transport/` implement the HTTP and custom WebSocket route-based compatibility API. Maintain these for compatibility, debugging, local development, fallback behavior, and bug fixes, but do not add new control-plane capabilities there by default.

The route-based client pattern is:

- **`BaseHttpClient`** — abstract route-based HTTP/WebSocket client with shared request/response handling
- **`SandboxClient`** — compatibility aggregator that exposes all specialized route-based clients
- **Specialized clients** — one per domain:
  - `CommandClient` — exec / execStream
  - `FileClient` — read, write, list, delete
  - `ProcessClient` — start, stop, list, signal
  - `PortClient` — port readiness streams
  - `GitClient` — clone, checkout, status
  - `UtilityClient` — ping, metadata
  - `InterpreterClient` — code interpreter sessions

When maintaining route-based compatibility, add or extend specialized clients under `packages/sandbox/src/clients/`. DO-to-container control capabilities belong in `packages/sandbox/src/container-control/` and `packages/sandbox-container/src/control-plane/`.

## Container Runtime (`packages/sandbox-container/src/`)

- **DI container** (`core/container.ts`) — manages service lifecycle and wiring
- **Router** — simple HTTP router with middleware
- **Control plane** (`control-plane/`) — primary container-side API called by the Sandbox DO
- **Handlers** (`handlers/`) — route-based compatibility handlers, thin layer that parses requests
- **Services** (`services/`) — business logic (`CommandService`, `FileService`, `ProcessService`, …)
- **Managers** (`managers/`) — stateful coordinators such as `ProcessManager`

Entry point: `packages/sandbox-container/src/index.ts` starts a Bun HTTP server on port 3000.

When adding a new container control operation:

1. Add/extend a service in `services/` for the business logic.
2. Add the control-plane method in `packages/sandbox-container/src/control-plane/`.
3. Mirror the call in `packages/sandbox/src/container-control/`.
4. Add unit tests on both sides; add an E2E test if it touches real shell/filesystem behavior.

Only add a route handler in `handlers/` and a route-based SDK client in `packages/sandbox/src/clients/` when maintaining HTTP/WebSocket compatibility.

## Monorepo Structure

Uses npm workspaces + [Turbo](https://turbo.build/):

- `packages/sandbox` — main SDK package (published)
- `packages/shared` — shared types and utilities (internal)
- `packages/sandbox-container` — container runtime (internal, bundled into image)
- `examples/` — working example projects
- `tooling/` — shared TypeScript configs

`turbo.json` orchestrates dependency-aware builds.

## Cross-Cutting Patterns

- **Sessions** — isolate execution contexts (cwd, env vars). Default session is auto-created; multiple sessions per sandbox are supported.
- **Ports** — expose internal services via preview URLs with token auth. Preview URL authorization is Durable Object-owned, while forwarding is active only after `exposePort()` activates the port for the current runtime. Production preview URLs require a custom domain with wildcard DNS (`*.yourdomain.com`); `.workers.dev` does not support the required subdomain patterns.
- **Container isolation** — handled at the Cloudflare platform level (VMs), not by SDK code.

## Container Base Image

The container runtime uses Ubuntu 22.04 with:

- Python 3.11 (matplotlib, numpy, pandas, ipython)
- Node.js 20 LTS
- Bun 1.x (powers the container HTTP server)
- Git, curl, wget, jq, and other common utilities

When modifying `packages/sandbox/Dockerfile`:

- Keep images lean — every MB affects cold start
- Pin versions for reproducibility
- Clean up package manager caches to reduce image size

More from cloudflare/sandbox-sdk

SkillDescription
changesetsUse when creating a changeset, preparing a release, or bumping versions. Covers which packages to reference, how to write user-facing changeset descriptions, the release automation flow, and the npm/Docker version sync requirement. (project)
coding-standardsUse when writing or reviewing TypeScript in this repo. Covers the no-`any` rule and where to put new types, the uppercase-acronym style guide, and the rules for code comments (no historical context). (project)
examplesUse when working in the examples/ directory, running an example with wrangler dev, adding a new example, or answering questions about EXPOSE directives and the local Docker dev loop. (project)
git-commitUse when creating git commits to ensure commit messages follow project standards. Applies the 7 rules for great commit messages with focus on conciseness and imperative mood.
loggingUse when adding logs, debugging, or working with the Logger across the SDK and container runtime. Covers the constructor-injection pattern, child loggers, env-var configuration, and test mocking. (project)
sandbox-bridgeUse when you need to exercise a real, running Sandbox deployment via HTTP — for example to validate SDK changes against a live container, reproduce a user-reported issue, or experiment with the API (including FUSE bucket mounts) without spinning up `wrangler dev`. Documents the Sandbox bridge worker reachable via `SANDBOX_WORKER_URL` + `SANDBOX_API_KEY` when the host injects them.
session-executionUse when working on or reviewing session execution, command handling, shell state, FIFO-based streaming, or stdout/stderr separation. Relevant for session.ts, command handlers, exec/execStream, or anything involving shell process management. (project)
testingUse when writing or running tests for this project. Covers unit vs E2E test decisions, test file locations, mock patterns, and project-specific testing conventions. (project)