Sandboxes
Create, execute, inspect, and terminate remote Modal, E2B, and Daytona sandboxes over the HTTP tool protocol.
services/sandbox is an independent Node.js 24 HTTP tool service that wraps Modal, E2B, and Daytona behind four standard Brain tools: sandbox_create, sandbox_exec, sandbox_inspect, and sandbox_terminate.
Provider identifiers are wrapped in HMAC-signed handles scoped to the calling tenant and session. Keep SANDBOX_SIGNING_KEY stable across service restarts; no external ownership database is needed.
Before you begin
- Node.js
24+andnpm. TOOL_API_KEYset to a random secret of at least 24 characters (shared with Brain asSANDBOX_TOOL_TOKEN).SANDBOX_SIGNING_KEYset to a random secret of at least 32 characters.- Credentials for at least one sandbox provider (
modal,e2b, ordaytona).
1. Install and start the service
Install dependencies, start the service (listening on 127.0.0.1:8091 by default), and print the tool descriptors for the providers you configured:
npm --prefix services/sandbox ci --ignore-scripts
# Set TOOL_API_KEY (24+ characters), SANDBOX_SIGNING_KEY (32+ characters),
# and credentials for at least one provider below.
npm --prefix services/sandbox start
npm --prefix services/sandbox run catalog -- http://127.0.0.1:8091 local modal,e2b,daytona2. Register the tools in Brain
Copy the generated JSON descriptors into the tools array of your Brain configuration file (brain.json) and set SANDBOX_TOOL_TOKEN in Brain's environment to match the service's TOOL_API_KEY.
- Advertise only configured providers: Pass only the providers you have configured to
npm --prefix services/sandbox run catalog. - Network binding: The service binds to loopback (
127.0.0.1:8091) by default; setHOST=0.0.0.0only behind TLS or private networking. - Container image: To build the standalone container image from the repository root, run
docker build -f services/sandbox/Dockerfile -t brain-sandbox-tools ..
Providers and lifecycles
| Provider | Required secrets | Optional host settings | Lifecycle |
|---|---|---|---|
| Modal | MODAL_TOKEN_ID, MODAL_TOKEN_SECRET | MODAL_APP (brain-tools), MODAL_IMAGE (python:3.13-slim) | Five-minute maximum lifetime; one CPU, 512 MiB. Uses the official JS SDK. |
| E2B | E2B_API_KEY | E2B_TEMPLATE (code-interpreter-v1) | Five-minute sandbox timeout. Inspect does not reconnect or resume it. |
| Daytona | DAYTONA_API_KEY | DAYTONA_API_URL, DAYTONA_TARGET (us) | Five-minute inactivity stop, then automatic deletion. Preview access is private. |
- Handle lifetime: Signed handles authorize
sandbox_execfor 5 minutes.sandbox_inspectandsandbox_terminateremain available afterward so callers can clean up expired sandboxes. - Explicit provider lifecycles: Daytona's provider timeout is an inactivity limit rather than a wall-clock lifetime. No tool resumes stopped sandboxes or extends handle lifetimes.
Execution limits and failure semantics
- Command execution (
sandbox_exec): Commands run inside the remote sandbox through a Python 3 helper with a 30-second deadline and 64 KiB combinedstdout/stderrcap. On timeout or excess output, the helper kills the process group. Results include the exit status plus explicit truncation and timeout flags. - No automatic retries: Provider failures and lost responses become tool errors (
is_error: true) withunknown_outcome: truewhen the remote outcome is ambiguous; the service never retries a model action. - Disconnect behavior: Disconnecting a client does not guarantee remote cancellation: an in-flight command retains its 30-second deadline, and the provider's sandbox expiry (see the table above) is the final cleanup bound.
- Concurrency and isolation: The service runs at most 16 concurrent HTTP requests. Keep provider account quotas and host CPU/memory limits appropriate for your workload. This common interface exposes no GPUs, public port tunnels, persistent disks, arbitrary container images, or cross-provider snapshots, and injects no credentials into sandboxes.
Verification and security notes
npm --prefix services/sandbox test runs the local contract tests (SDK types, HTTP lifecycle, authentication, cross-session isolation, handle tampering, service restarts, expiry, ambiguous failures, cleanup, and execution limits):
npm --prefix services/sandbox testTo test against a live provider (modal, e2b, or daytona), configure that provider's credentials and run:
npm --prefix services/sandbox run live -- modalThe live script creates a sandbox, executes a command, inspects it, and terminates it in a finally block. Missing credentials fail explicitly (no silent skips), and running against a live account can incur provider charges.
Note: Daytona
0.224.1carries an upstreambracesadvisory through its file-glob dependencies (GHSA-vfj7-8cjw-p6xm), with no published fix at review time. This service never calls the Daytona SDK's upload/glob APIs or passes model input as glob patterns. Track the upstream fix and do not expand to those APIs without addressing it.
Sources: Modal SDK, E2B sandbox API, Daytona SDK.