Cloudflare Sandbox SDK

repository·main·Indexed 21 days ago

https://github.com/cloudflare/sandbox-sdk

The Cloudflare Sandbox Bridge acts as an intermediary between the OpenAI Agents SDK and Cloudflare's Sandbox environment. It translates sandbox session operations into API calls against the @cloudflare/sandbox Durable Object API, allowing AI agents to interact with sandboxed compute and filesystem resources. The SDK includes a deployable Cloudflare Worker and examples such as a one-shot coding agent and a full-stack Workspace Chat application.

Tokens
75.1K
Snippets
219
Records
331
Agent score
77%

What's inside cloudflare-sandbox-sdk

  1. Overview of @cloudflare/sandbox/bridge

    main

    The @cloudflare/sandbox/bridge library provides the core infrastructure for managing sandbox environments. It exports the following key components:

    • bridge(): A factory function used to initialize the bridge.
    • Warm Pool Durable Object: Manages a pool of pre-warmed sandbox environments to reduce latency.
    • API Routes: Provides the endpoints required for interacting with the sandbox.
    • OpenAPI Schema: Defines the contract for the bridge's API.

    For detailed information on API references, deployment, authentication, security, and warm pool configuration, refer to the bridge/worker/README.md documentation.

  2. Overview of the S3 Mount Example

    main

    The S3 Mount Example demonstrates how to mount an AWS S3 bucket as a standard read/write folder inside a Cloudflare Sandbox container.

    Key Features:

    • FUSE-based Mounting: Uses mount-s3 inside the container so files in /mnt/s3/ correspond to S3 objects.
    • Secure Credential Vending: The container never sees long-lived AWS keys. Instead, it requests short-lived credentials from the Worker via an intercepted HTTP request to the well-known ECS task metadata IP (169.254.170.2).
    • Minimal Secret Surface: The only long-lived secret is a 'broker' IAM user that is strictly limited to assuming a single specific IAM role.
    IMPORTANT

    This demo requires FUSE support in the container environment. It will not work locally using wrangler dev and requires deployment to a production environment via wrangler deploy.

  3. Overview of Claude Code Sandbox SDK Example

    main

    This example demonstrates how to run Claude Code within a Cloudflare Sandbox. The workflow is as follows:

    1. A Worker receives a POST request containing a repo URL and a task description.
    2. The Worker spawns a sandbox, clones the specified repository, and executes Claude Code in headless mode.
    3. Claude Code performs the requested task by editing files.
    4. The Worker returns a response containing the execution logs and the resulting file diffs.
  4. Workspace Chat Architecture and Capabilities

    main

    Workspace Chat is an AI chat agent that uses a Cloudflare Sandbox backend to provide a persistent virtual filesystem.

    Architecture

    • Backend: Python Starlette server using the OpenAI Agents SDK.
    • Frontend: React + Vite using @cloudflare/kumo UI and @ai-sdk/react for streaming.

    Core Capabilities

    • Filesystem: Uses the Filesystem capability from the OpenAI Agents SDK. The agent uses apply_patch for structured file edits.
    • Shell: Uses the Shell capability. The agent can run arbitrary shell commands (e.g., bun, node, npm) via exec_command.
    • Streaming: Uses OpenAI gpt-5.4 with streaming via the AI SDK Data Stream Protocol.
  5. Understand the Sandbox output convention

    main

    The coding agent is strictly instructed to place all task outputs under the /workspace/output/ directory inside the sandbox.

    • Multiple files: If the agent generates multiple files, they are automatically compressed into result.zip before being transferred to your host.
    • Single file: If the agent generates only one file, it is copied directly to your specified output directory (or the current directory if no --output flag is provided).
  6. Understand the Session Concurrency Model

    main

    The Sandbox SDK uses a mutex-based concurrency model to manage command execution within sessions.

    Per-Session Serialization

    Each session has its own mutex. This ensures that commands within the same session are serialized (run one at a time, in order), while commands in different sessions can run in parallel.

    Lock Release Strategies

    • Foreground Commands (execStream): The session lock is held for the entire duration of the command. This prevents other commands from interleaving output while a user is actively watching the stream.
    • Background Commands (startProcess): The session lock is released immediately after the command successfully starts and its PID is captured. This allows other commands to be issued to the same session while the background process (e.g., a server) continues to run.

    Kill Operations

    killCommand() does not acquire the session lock. This is critical to prevent deadlocks: if a command is stuck in an infinite loop and holding the lock, the user must still be able to issue a kill command to break the loop.

  7. Network Isolation in Claude Code Sandbox

    main

    The sandbox is configured with restricted internet access. Only the Anthropic and GitHub APIs are accessible. This restriction allows Claude Code to run headlessly without requiring manual permission prompts for network access.

    Note: To run claude as root, the environment variable IS_SANDBOX=1 must be set. This allows the use of the --permission-mode bypassPermissions flag.

  8. Kill entire process trees to prevent orphaned processes

    main

    When terminating a process, simply killing the parent PID is insufficient because child processes will be orphaned and adopted by init (PID 1), continuing to run in the background.

    To prevent this, the SDK performs a depth-first walk of the process tree using /proc to ensure children are killed before their parents. This ensures the relationship is still visible to the OS during the teardown.

    The Kill Sequence:

    1. Send SIGTERM to the entire tree to allow graceful cleanup.
    2. Wait for a timeout (e.g., 5 seconds).
    3. If processes remain, perform a re-walk of the tree and send SIGKILL to all identified descendants and the original root PID.
    // Example of the depth-first kill logic used internally
    const killTree = (targetPid: number, signal: NodeJS.Signals) => {
      try {
        // Read this process's children from /proc
        const childrenFile = `/proc/${targetPid}/task/${targetPid}/children`;
        const children = readFileSync(childrenFile, 'utf8').trim().split(/\s+/);
    
        // Recursively kill children FIRST
        for (const childPid of children.filter(Boolean)) {
          killTree(parseInt(childPid, 10), signal);
        }
      } catch {
        // Process already exited, or /proc not available
      }
    
      // Then kill this process
      try {
        process.kill(targetPid, signal);
      } catch {
        // Process already exited
      }
    };
  9. How the WebSocket Tunnel works

    main

    The WebSocket Tunnel example demonstrates a Cloudflare Worker that tunnels WebSocket connections from a browser to a Bun server running inside a Cloudflare Sandbox using Cloudflare Tunnel.

    Tunneling Modes

    1. Quick Tunnels: By default, the worker uses sandbox.tunnels.get(port). This generates a fresh *.trycloudflare.com URL on every container restart with zero configuration.

    2. Named Tunnels: If TUNNEL_NAME is provided along with a CLOUDFLARE_API_TOKEN, the worker uses sandbox.tunnels.get(port, { name: TUNNEL_NAME }). This binds a stable hostname <TUNNEL_NAME>.<zone> that survives container restarts. The SDK automatically rediscovers the tagged Cloudflare resources on re-run.

    Lifecycle and Cleanup

    • Persistence: Named tunnels and DNS records persist on Cloudflare across container restarts.
    • Automatic Cleanup: Stopping the sandbox stops all associated tunnels, deleting the Cloudflare tunnel and DNS record for named tunnels.
    • Manual Cleanup: You can trigger cleanup by calling sandbox.destroy(). In this example, a /destroy route is provided to perform this action.
    • Note: You do not need to call sandbox.tunnels.destroy(port) separately unless you want to remove a single tunnel while keeping the sandbox running.
  10. How Sandbox Sessions work

    main

    Sessions allow you to maintain separate execution contexts (working directories, environment variables, and shell state) within a single sandbox. This is useful for multi-user applications where you want to use one sandbox ID but keep user environments isolated.

    Workflow:

    1. Create: POST /v1/sandbox/:id/session returns a session ID (e.g., sess_abc123).
    2. Use: Include the Session-Id: <session-id> header in subsequent /exec, /pty, and file operation requests.
    3. Delete: DELETE /v1/sandbox/:id/session/:sid tears down the session.

    Important Notes:

    • Statelessness: If you do not provide a Session-Id header, requests are stateless and do not reuse the default shell session (e.g., cd commands won't persist).
    • Ephemeral Nature: Custom sessions do not survive container sleep/restarts. If the container restarts, you must create a new session.
    • Sandbox Destruction: Calling DELETE /v1/sandbox/:id kills all active sessions immediately.
    # Create a session
    curl -X POST http://localhost:8787/v1/sandbox/mfrggzdfmy2tqnrz/session \
      -H "Authorization: Bearer $SANDBOX_API_KEY"
    
    # Use the session (using the returned ID)
    curl -X POST http://localhost:8787/v1/sandbox/mfrggzdfmy2tqnrz/exec \
      -H "Authorization: Bearer $SANDBOX_API_KEY" \
      -H "Session-Id: sess_abc123" \
      -H "Content-Type: application/json" \
      -d '{"argv": ["ls"]}'