Use E2B as the sandbox runtime for Claude Managed Agents self-hosted environments.
Claude Managed Agents can use a self-hosted environment when you want tool calls to run in your own infrastructure. Claude runs the agentic loop and reasoning process; E2B provides isolated sandbox infrastructure for the environment where tool calls execute. The reusable E2B/claude-managed-agents-webhooks template receives webhooks and routes each Claude Managed Agents session to a persistent E2B worker sandbox.
This separation is intentional for security: Claude decides what work to do, while the sandbox contains the execution environment, filesystem, tools, network access, and runtime logs.
Export the values you will pass to the webhook sandbox:
# E2B dashboard API keys: https://e2b.dev/dashboard?tab=keysexport E2B_API_KEY="..."# Claude Console API keys: https://console.anthropic.com/settings/keysexport ANTHROPIC_API_KEY="..."# Claude Console environments: https://platform.claude.com/workspaces/default/environmentsexport ANTHROPIC_ENVIRONMENT_ID="..."# Open the self-hosted environment in the Claude Console and click Generate environment key.export ANTHROPIC_ENVIRONMENT_KEY="..."
Start the public template with auto-resume enabled. The template starts a webhook server on port 8000.
Because the signing key only appears after you register a webhook endpoint, write the router config now and add the signing key to the same sandbox after registration.
At this point /health returns 200, but /webhook returns 503 until the signing key is configured. Keep this sandbox running or paused; registering a different sandbox URL means writing the signing key into that sandbox instead.
Create or select a Claude Managed Agents agent in the Claude Console, then create a session with that agent and the same ANTHROPIC_ENVIRONMENT_ID you wrote into the webhook sandbox. Creating the session does not start work; the user.message event does.
export ANTHROPIC_AGENT_ID="agent_..."
Use a small shell task for the first smoke test:
Use bash to echo webhook-smoke-ok. Answer only with that text.
import Claude from '@anthropic-ai/sdk'const client = new Claude({ apiKey: process.env.ANTHROPIC_API_KEY,})const session = await client.beta.sessions.create({ agent: process.env.ANTHROPIC_AGENT_ID!, environment_id: process.env.ANTHROPIC_ENVIRONMENT_ID!, title: 'E2B webhook smoke',})await client.beta.sessions.events.send(session.id, { events: [ { type: 'user.message', content: [ { type: 'text', text: 'Use bash to echo webhook-smoke-ok. Answer only with that text.', }, ], }, ],})console.log(`Session ID: ${session.id}`)
import osfrom anthropic import Anthropic as Claudeclient = Claude(api_key=os.environ["ANTHROPIC_API_KEY"])session = client.beta.sessions.create( agent=os.environ["ANTHROPIC_AGENT_ID"], environment_id=os.environ["ANTHROPIC_ENVIRONMENT_ID"], title="E2B webhook smoke",)client.beta.sessions.events.send( session.id, events=[ { "type": "user.message", "content": [ { "type": "text", "text": "Use bash to echo webhook-smoke-ok. Answer only with that text.", }, ], }, ],)print(f"Session ID: {session.id}")
Router logs showing routing work and assigned session.
A session-to-sandbox assignment in the router’s assignment store.
The assigned worker sandbox’s worker.log showing the shell tool execution and successful results posted back to Claude.
The Claude Managed Agents session returning to session.status_idle.
The assignment store records the worker sandbox ID for each routed session. Connect to that sandbox and check /opt/anthropic-managed-agents-js/worker.log when you need the tool execution logs.If the session stays at requires_action, check /opt/anthropic-managed-agents-js/webhook.log in the router sandbox first, then check /opt/anthropic-managed-agents-js/worker.log in the assigned worker sandbox. Stale environment keys, missing signing keys, archived sessions, and failed tool-result posts show up there.
The worker sandbox runs tool calls with /mnt/session as its workdir. File tools are constrained to that workdir, skills are downloaded under /mnt/session/skills/<name>/, and generated artifacts should be written under /mnt/session/outputs.The webhook sandbox is the router. It keeps a session-to-sandbox assignment store and starts worker sandboxes with E2B auto-resume and pause-on-timeout settings.
By default, the public webhook template gives each Claude Managed Agents session its own E2B worker sandbox. Follow-up turns for the same session reconnect to the same worker and reuse its /mnt/session filesystem. The sandbox is the isolated execution environment, not the place where Claude’s reasoning loop runs.Use cloud buckets, Archil, or volumes when files need to outlive a sandbox or be shared across many sandboxes.If you want to run that router in your own service instead of in E2B, use the cookbook’s app-webhooks/ example. It receives webhooks in your app, claims work there, and routes each session to its own E2B sandbox by default.
Remove the webhook endpoint in the Claude Console before deleting the router sandbox. Then kill the router sandbox and any assigned worker sandboxes you no longer need.