How Claude Code Sandbox Execution Integrates with External Providers Like e2b
Claude Code's sandbox execution feature routes remote code execution to e2b.dev's isolated containers via a Python bridge, while keeping API credentials server-side and streaming real-time progress back to the client.
The davila7/claude-code-templates repository implements a secure sandbox execution architecture that lets developers choose between running Claude Code locally or inside remote external sandbox providers. This hybrid approach isolates potentially unsafe code generation in ephemeral cloud containers while maintaining a seamless local development experience through a unified HTTP API.
The Mode Dispatch Logic in sandbox-server.js
When the Express server starts at cli-tool/src/sandbox-server.js, it first loads sensitive credentials via loadEnvFile() (lines 13‑33), which parses E2B_API_KEY and ANTHROPIC_API_KEY from a local .env file into process.env. These credentials remain in server memory and never travel to the browser.
The core dispatch logic occurs in the POST /api/execute handler (lines 12‑53). When a client sends a JSON payload containing prompt, mode, and agent, the server creates a task object and routes it based on the mode parameter:
mode='cloud'→ InvokesexecuteE2BTask(task)(lines 41‑43)mode='local'→ InvokesexecuteLocalTask(task)(lines 45‑47)
This branching allows a single endpoint to serve both external sandbox provider runs and local executions without client-side configuration changes.
How the Python Bridge Orchestrates External Sandboxes
When executeE2BTask triggers (lines 17‑55), it constructs a command to spawn the Python bridge at cli-tool/components/sandbox/e2b/e2b-launcher.py. The Node.js server passes the user prompt, selected agent, and both API keys as command-line arguments and environment variables:
const pythonProcess = spawn('python3', [
launcherPath,
'--prompt', task.prompt,
'--agent', task.agent,
'--api-key', process.env.E2B_API_KEY,
'--anthropic-key', process.env.ANTHROPIC_API_KEY
], {
env: { ...process.env } // Secure credential injection
});
The Python script authenticates against https://api.e2b.dev, provisions an isolated sandbox container, uploads the requested agent markdown file, and executes the claude binary inside that container. Because the sandbox runs on external infrastructure, arbitrary code generated by Claude cannot access the developer's local file system.
Real-time Progress Streaming from Remote Sandboxes
The Node.js server listens to stdout and stderr of the Python child process (lines 66‑88), parsing structured log markers to update the task state:
Sandbox created: <id>→ Setstask.sandboxIdInstalling→ Incrementstask.progressto 25%Executing Claude Code→ Advancestask.progressto 50%Execution completed successfully→ Finalizes output
Clients poll GET /api/task/:taskId to receive the current state, including the live progress percentage and accumulated output strings. This architecture allows the UI to display a real-time progress bar while the external sandbox provider handles the heavy lifting.
Error Handling and Credential Security
If the Python bridge exits with a non-zero code, the close listener (lines 98‑108) inspects the stderr buffer for specific missing-key errors:
E2B API key is requiredAnthropic API key is required
When detected, the server surfaces actionable error messages without exposing the full stack trace. This design ensures that sandbox execution fails gracefully when credentials are missing, while keeping the actual key values encrypted in server memory and environment variables.
Local vs. Cloud Sandbox Execution
The repository supports two distinct execution strategies within the same API:
| Feature | Local (mode='local') |
Cloud (mode='cloud') |
|---|---|---|
| Isolation | Runs directly on the developer's machine with full file-system access | Executes inside an e2b container provided by the external sandbox provider |
| Dependencies | Requires the claude CLI binary installed locally |
No local Claude binary needed; the remote sandbox includes it |
| API Keys | Optional (uses local CLI configuration) | Requires both E2B_API_KEY and ANTHROPIC_API_KEY |
| Performance | Faster startup, limited by local compute resources | Slight provisioning latency, but safe for untrusted code |
| Use Case | Trusted code prototypes and quick iterations | AI-generated code that may modify files or perform network calls |
The executeLocalTask function (lines 37‑58) handles the local path by spawning the claude CLI directly with the prompt and optional agent prefix, bypassing the external provider entirely.
Configuring the External Sandbox Provider Integration
To enable remote sandbox execution with e2b:
-
Create environment file in the directory where you launch the server:
E2B_API_KEY=your-e2b-key ANTHROPIC_API_KEY=sk-ant-api03-... -
Start the orchestration server:
node cli-tool/src/sandbox-server.js -
Execute code via HTTP:
POST /api/execute HTTP/1.1 Content-Type: application/json { "prompt": "Create a React component that fetches data from an API", "mode": "cloud", "agent": "development-team/frontend-developer" }
The server immediately returns a taskId. Poll the status endpoint to retrieve results:
GET /api/task/task-1703829273456-abc123 HTTP/1.1
A successful response includes the sandbox identifier and execution output:
{
"success": true,
"task": {
"id": "task-1703829273456-abc123",
"status": "completed",
"progress": 100,
"sandboxId": "sbox-7f4c1a2b",
"output": "✓ Component created successfully..."
}
}
Summary
- Dual-mode architecture: The
sandbox-server.jsdispatches to either local CLI execution or remote external sandbox providers based on themodeparameter. - Secure credential isolation: API keys for e2b and Anthropic load from
.envvialoadEnvFile()and reside only in server memory, passed securely to the Python child process environment. - Python bridge pattern:
e2b-launcher.pyacts as a thin wrapper that creates isolated containers, uploads agents, and streams structured logs back to Node.js. - Real-time monitoring: Progress parsing of markers like
Sandbox created:andExecuting Claude Codeenables live UI updates without WebSocket complexity. - Isolation guarantee: Cloud mode runs inside e2b's infrastructure, preventing AI-generated code from accessing the host file system, while local mode offers speed for trusted workloads.
Frequently Asked Questions
What external sandbox providers does Claude Code support?
Currently, the implementation supports e2b.dev as the primary external sandbox provider. The integration is handled through the Python bridge at cli-tool/components/sandbox/e2b/e2b-launcher.py, which uses the official e2b SDK to authenticate against https://api.e2b.dev and provision ephemeral containers. The architecture is modular, allowing for future providers by implementing similar launcher scripts following the same stdout marker protocol.
How are API keys secured during sandbox execution?
API keys are never transmitted to the client browser. The Node.js server loads E2B_API_KEY and ANTHROPIC_API_KEY from a .env file into process.env at startup via loadEnvFile(). When spawning the Python bridge, these credentials pass through the env option of child_process.spawn(), ensuring they remain in server-side memory and environment variables only. If keys are missing, the server returns specific error messages without exposing stack traces or attempting network requests.
What is the difference between local and cloud execution modes?
Local mode (mode='local') spawns the claude CLI directly on the host machine using executeLocalTask(), offering faster startup but no isolation from the host file system. Cloud mode (mode='cloud') invokes executeE2BTask(), which delegates to the external provider's infrastructure, creating an isolated container where even malicious generated code cannot harm the developer's machine. Cloud mode requires both API keys and incurs slight latency for container provisioning, while local mode requires only the local CLI installation.
How does the server track progress of remote sandbox tasks?
The Node.js server parses structured log markers from the Python bridge's stdout stream. Specific strings like Sandbox created:, Installing, and Executing Claude Code trigger increments to the task's progress field (stored in the activeTasks map). Clients poll the REST endpoint /api/task/:taskId to fetch the current progress percentage, status, and accumulated output, allowing the frontend to render real-time progress bars without maintaining a persistent WebSocket connection.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →