Skip to main content
Claude Managed Agents splits an agent in two. Anthropic hosts the model, the agent loop, session state, and the work queue. A self-hosted environment moves the other half to you, so every bash, read, write, edit, glob, and grep call executes on infrastructure you own. Point that half at boxd and each session gets a full Linux VM with its own kernel, root, a persistent disk, and an HTTPS domain. The machine boots in milliseconds, freezes between turns, and wakes with its filesystem and processes exactly as the last turn left them.

A Claude Managed Agents session. Anthropic runs the agent, the tool calls run in a boxd machine that did not exist when the session started.

How it fits together

A worker inside the machine long-polls Anthropic’s work queue over plain outbound HTTPS. Nothing dials into your network, so the machine can keep every inbound port closed. Your app talks to Anthropic, which runs the model, the agent loop and a work queue. Your boxd machine runs a worker that long-polls that queue outbound and executes bash, read, write, edit, glob and grep. Three pieces, created once each:

Set up the Anthropic side

Install the ant CLI and sign in:
Define the agent and the environment as files you keep in version control:
Create both, and keep the ids:
Then open the environment in the Claude Console and click Generate environment key. That sk-ant-oat01-… value is the only credential the worker needs, and it is scoped to this one environment’s work queue.
The boxd environment page in the Claude Console, typed Self-hosted, showing one idle worker, the environment keys table, and the Generate environment key button

The environment in the Console. Generating the key is the one step that lives here, and the worker count shows when something is connected.

Keep your org API key off any machine that runs tool calls. The environment key is enough for the worker, and it grants nothing beyond this environment.

Quickstart, one machine

The fastest working setup is a single machine polling for work. Create it, install the worker, and give it a /workspace to operate in:
Start the worker with the environment key passed in on the command:
Confirm Anthropic can see it:
Now start a session from anywhere:
The file appears on the machine, and the agent’s tool calls show up in ~/worker.log.
Set --auto-hibernate-timeout=0 on any machine running a worker, and --auto-suspend-timeout=0 if your org turns auto-suspend on by default. The idle timers watch inbound traffic, and the worker’s poll is outbound, so a busy worker still looks idle. See Suspend, resume, and hibernate.

One machine per session

A single machine means every session shares one filesystem. Giving each session a machine of its own buys three things. Sessions cannot see each other’s files. A session that wrecks its machine wrecks only its own. And each machine sleeps on its own schedule. The shape is an orchestrator that turns each queued work item into a machine.

Build the image once

Every session machine boots from a snapshot, so the worker and your toolchain are already in place:
A machine created from this snapshot is ready in milliseconds, memory and all.

Run the orchestrator

The orchestrator receives Anthropic’s session.status_run_started webhook, drains the work queue, and runs each session’s worker in that session’s own machine. When the session ends, it deletes the machine. Put it on its own boxd machine, where the SDK authenticates automatically with no key to manage.
Create the orchestrator machine first, so the URL you register resolves:
Register https://cma-orchestrator.boxd.sh/webhook in the Console under Manage, then Webhooks, subscribed to session.status_run_started, session.status_terminated, and session.deleted. Put the whsec_ secret it shows next to the environment id and key, in a .env beside your orchestrator.py or orchestrator.ts:
Then deploy. The machine already has an HTTPS domain, so there is no TLS to arrange:
A signed delivery gets a 204 in ~/orchestrator.log. Anything unsigned gets a 401.

Resume instead of recreate

The worker exits a minute after the session goes idle, and the orchestrator pauses the machine. That takes it to standby, where it holds its memory and running processes and costs near nothing. When the next turn arrives, the same session resolves to the same machine name, and resuming takes under a millisecond. The agent finds /workspace as it left it, dependencies installed and caches warm. For a long conversation with gaps between turns, that is the difference between re-cloning a repo every time and picking up mid-thought. The machine is deleted when the session terminates or is deleted, so its state lives exactly as long as the session does.

Without an SDK

Anthropic’s poller can hand each work item to a script instead of running the tool loop itself. That script is the whole orchestrator:
The same lifecycle as the orchestrator above, in thirty lines, with no webhook to register. One difference. The poll model has no session-end event, so machines are paused but never deleted. Sweep the agent- machines of finished sessions yourself.
Run this poller on your laptop or a server, where the boxd CLI is signed in as you. The CLI that ships inside a machine authenticates as that machine, and a machine cannot reach an --isolated peer, so exec fails with “not found or not accessible”. The SDK does not have this restriction, which is why the orchestrator above runs happily on a boxd machine.

Credentials the agent can use but never read

Self-hosted environments do not support Anthropic’s vault environment-variable credentials, because the egress is yours. boxd covers the same ground at its own edge, and more tightly. Bind a secret to the hosts it may be sent to, and the machine only ever holds a placeholder:
The real value is substituted into requests to api.stripe.com on the way out. Inside the machine, env, shell history, and the agent’s own transcript contain nothing but an opaque bxds_… string. A prompt injection that talks the agent into printing every secret it can find gets placeholders. Set it once at the organization level and every session machine carries it. An isolated machine receives account-level variables through exec sessions, and exec is exactly how the orchestrator starts the worker. Pair it with a per-machine egress allowlist so the machine can only reach the hosts you name. A machine restored from a snapshot starts unrestricted, so set the list in ensure_machine right after create:
Both controls are enforced outside the machine, so code inside cannot lift them. See Env vars & secrets and Egress control.

Files and repositories

Self-hosted environments reject file and github_repository session resources, since Anthropic has no container to mount them into. Two boxd answers, depending on whether the data is shared or per-session: Shared across every session. Bake it into the snapshot. Clone the repo, install the dependencies, warm the caches, then save. Every session starts with it and pays nothing at boot. Per session. Copy it in from the orchestrator before starting the worker, using the session’s own metadata to decide what. Your app sets the metadata when it creates the session, with its org API key:
The orchestrator reads it back with the environment key, which can retrieve the sessions on its environment:
Session outputs work the same way in reverse. The agent writes to /workspace, and the orchestrator reads the file out with machines.files.download once the turn ends.

Parallel exploration

A fork copies a running machine’s disk, memory, and processes in under 200ms. Fork a session machine several times mid-task and each copy continues from the same live state, so an agent can try several approaches at once and keep the one that works:
Expose it to the agent as a small CLI it can call through bash, or drive it from the orchestrator. Agent swarm intelligence covers the fan-out and merge pattern in full.

What you own

Tool inputs and results still travel to Anthropic, because the model has to see them. Everything else stays on your machine.

FAQ

No. The worker polls outbound over HTTPS. Only the orchestrator needs an inbound URL, and only if you choose the webhook path over polling. Every machine already has one at name.boxd.sh.
The session stalls at requires_action, waiting for a tool result that will never arrive, and rejects new messages until you send user.interrupt. That abandons the dead call and returns the work item to the queue. The next message starts a turn, the webhook fires, and the orchestrator boots a fresh machine from the snapshot under the same name, since the old one is gone. A polling worker claims the returned item on its own.
Yes, that is the quickstart. One ant beta:worker poll handles sessions one after another in a single /workspace. It suits a trusted single-tenant workload. Give each session its own machine when the sessions should not see each other’s files.
They need the SDK’s EnvironmentWorker, which downloads each store to /mnt/memory and syncs it back. The ant CLI worker used here does not mount them. Swap the in-machine worker for a small Python or TypeScript entrypoint calling handle_item() if you need them, and see Anthropic’s notes on memory stores.
Whatever you set in agent.yaml. The environment has nothing to do with model choice, so a self-hosted sandbox costs the same per token as a cloud one.