---
title: "Self-hosted sandbox for Claude Managed Agents"
description: "Give each Claude Managed Agents session its own exe.dev VM: a small dispatcher claims sessions from your self-hosted environment and starts their workers."
url: https://exe.dev/deploy/claude-managed-agents
category: "AI agents"
updated: 2026-10-23
---

# Self-hosted sandbox for Claude Managed Agents

Anthropic runs the agent. Each session's tools run on a VM of its own.

- **Software:** Claude Managed Agents (https://platform.claude.com/docs/en/managed-agents/overview)
- **Source:** https://github.com/anthropics/anthropic-cli
- **License:** MIT (the ant CLI)
- **Time:** 5 minutes
- **Example VM name:** `my-claude-dispatcher` (yours will differ; on the VM, `hostname` prints it)
- **Machine-readable:** https://exe.dev/deploy/claude-managed-agents/manifest.json
- **File:** https://exe.dev/deploy/claude-managed-agents/dispatcher.py

## What you get

- The claude-dispatcher service, which gives each session in the environment a VM of its own
- The service restarted on failure and after a reboot
- The environment key and exe.dev API key in /etc/claude-dispatcher.env, mode 600
- `exe.dev key works` and `environment key works` in `journalctl -u claude-dispatcher`

Running on the VM:

- **Dispatcher**: dispatcher.py, run by uv as the claude-dispatcher systemd service, data in `/etc/claude-dispatcher.env`

## Deploy with Shelley

Open https://exe.dev/new?prompt=ANTHROPIC_ENVIRONMENT_ID%3D%3Cfill-this-in%3E%0AANTHROPIC_ENVIRONMENT_KEY%3D%3Cfill-this-in%3E%0AEXE_TOKEN%3D%3Cfill-this-in%3E%0A%0ASet%20up%20Claude%20Managed%20Agents%20on%20this%20VM%20by%20following%20the%20exe.dev%20recipe%20at%20https%3A%2F%2Fexe.dev%2Fdeploy%2Fclaude-managed-agents.md%20from%20top%20to%20bottom.%0A%0AThe%20values%20at%20the%20top%20of%20this%20message%20are%20mine%3A%0A-%20ANTHROPIC_ENVIRONMENT_ID%3A%20your%20self-hosted%20environment%27s%20ID%2C%20%60env_...%60%0A-%20ANTHROPIC_ENVIRONMENT_KEY%3A%20its%20key%2C%20%60sk-ant-oat01-...%60%0A-%20EXE_TOKEN%3A%20the%20exe.dev%20API%20key%20that%20%60ssh%20exe.dev%20ssh-key%20generate-api-key%60%20printed%2C%20%60exe1....%60%0AAsk%20me%20for%20any%20that%20still%20say%20%3Cfill-this-in%3E%20before%20you%20need%20them.%0A%0AThe%20recipe%27s%20example%20VM%20name%20is%20my-claude-dispatcher.%20This%20VM%27s%20name%20is%20the%20output%20of%20%60hostname%60%3A%20use%20it%20wherever%20the%20recipe%20writes%20my-claude-dispatcher.%20Skip%20the%20step%20that%20creates%20the%20VM%3B%20you%20are%20on%20it.%0A%0AYou%20are%20done%20when%20all%20of%20these%20are%20true.%20Check%20each%20one%20yourself%3A%0A-%20The%20claude-dispatcher%20service%2C%20which%20gives%20each%20session%20in%20the%20environment%20a%20VM%20of%20its%20own%0A-%20The%20service%20restarted%20on%20failure%20and%20after%20a%20reboot%0A-%20The%20environment%20key%20and%20exe.dev%20API%20key%20in%20%2Fetc%2Fclaude-dispatcher.env%2C%20mode%20600%0A-%20%60exe.dev%20key%20works%60%20and%20%60environment%20key%20works%60%20in%20%60journalctl%20-u%20claude-dispatcher%60%0A%0ARun%20%22Set%20up%20the%20dispatcher%20by%20hand%22%20from%20%22On%20the%20VM%22%2C%20skipping%20VM%0Acreation%20and%20SSH.%20The%20three%20inputs%20are%20secrets%3A%20put%20them%20only%20in%0A%2Fetc%2Fclaude-dispatcher.env%2C%20and%20never%20print%20them.%20Don%27t%20start%20a%20session%0Aor%20run%20the%20owner%27s%20commands%3A%20they%20need%20the%20owner%27s%20own%20keys.%20If%20the%20log%0Ashows%20%60401%60%20or%20%60invalid%20token%60%2C%20tell%20the%20owner%20which%20key%20was%20refused.%0AFinish%20by%20pointing%20the%20owner%20to%20%22Give%20it%20a%20task%22.%0A%0AFinish%20with%20the%20URLs%20I%20should%20open.%0A to create a VM whose agent, Shelley, follows this recipe. From a terminal:

```sh
curl -fsSL https://exe.dev/deploy/claude-managed-agents/prompt.txt | ssh exe.dev new --prompt=/dev/stdin
```

Or follow the steps below by hand.

[Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview)
runs Claude's agent loop on Anthropic's servers. In a
[self-hosted environment](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes),
the agent's tools run on machines you choose, which claim each session from
the environment's queue.

This page makes each session's machine an exe.dev VM: a whole Ubuntu
machine with sudo and Docker, ready in a few seconds and private by
default. [dispatcher.py](https://exe.dev/deploy/claude-managed-agents/dispatcher.py),
a short Python program, runs on a VM of its own (or on your computer) and,
for each session it claims:

- finds the VM whose comment is the session's ID, or creates one, with
  exe.dev's [Python SDK](https://github.com/boldsoftware/exe-sdk-python);
- installs Anthropic's `ant` CLI there, and starts `ant beta:worker run`
  with that session's own secret, as a systemd unit;
- moves on to the next session. The worker runs the session's tools in
  `/workspace` and exits a minute after the session goes idle. A reply
  starts a new worker on the same VM, with the same files and packages.

## Before you start

- A self-hosted environment and its key. In the
  [Claude Console](https://platform.claude.com/environments), click
  **Create environment**, choose **Self-hosted** under **Hosting**, then
  open it and click **Generate environment key**. Note its ID (`env_...`)
  too.
- An exe.dev API key that can make and reach session VMs, and nothing
  else. On your computer:

  ```bash
  ssh exe.dev ssh-key generate-api-key --label=claude-dispatcher \
    --tag=claude-session --cmds=new,ls,ssh --exp=1y --json | jq -r .token
  ```

  It sees only VMs tagged `claude-session`, and the VMs it creates get that
  tag. `ssh exe.dev ssh-key remove claude-dispatcher` revokes it.

## Run the dispatcher

Deploy sets it up on a new VM. To do it yourself:

<details id="create-the-vm" data-manual-setup class="dp-details">
<summary>Set up the dispatcher by hand</summary>

On your computer:

```bash
ssh exe.dev new --name=my-claude-dispatcher
ssh my-claude-dispatcher.exe.xyz
```

On the VM, download the dispatcher and write its settings, filling in your
values:

```bash
sudo curl -fsSL -o /usr/local/bin/claude-dispatcher \
  https://exe.dev/deploy/claude-managed-agents/dispatcher.py
sudo chmod 755 /usr/local/bin/claude-dispatcher
sudo install -m 600 /dev/null /etc/claude-dispatcher.env
sudo tee /etc/claude-dispatcher.env > /dev/null <<'EOF'
ANTHROPIC_ENVIRONMENT_ID=env_...
ANTHROPIC_ENVIRONMENT_KEY=sk-ant-oat01-...
EXE_TOKEN=exe1....
EOF
```

Run it as a service:

```bash
sudo tee /etc/systemd/system/claude-dispatcher.service > /dev/null <<'EOF'
[Unit]
Description=Claude Managed Agents dispatcher (one exe.dev VM per session)
Wants=network-online.target
After=network-online.target

[Service]
User=exedev
EnvironmentFile=/etc/claude-dispatcher.env
ExecStart=/usr/local/bin/uv run --script /usr/local/bin/claude-dispatcher
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now claude-dispatcher
sleep 10; journalctl -u claude-dispatcher -n 5 --no-pager
```

Expect `exe.dev key works` and `environment key works`. To update the
dispatcher later, run the `curl` line again and
`sudo systemctl restart claude-dispatcher`.

</details>

### Or run it on your computer

With [uv](https://docs.astral.sh/uv/getting-started/installation/), fill in
the same three values and leave it running in a terminal:

```bash
export ANTHROPIC_ENVIRONMENT_ID=env_...
export ANTHROPIC_ENVIRONMENT_KEY=sk-ant-oat01-...
export EXE_TOKEN=exe1....
uv run https://exe.dev/deploy/claude-managed-agents/dispatcher.py
```

Sessions wait in the queue while it isn't running. Run one dispatcher per
environment.

## Give it a task

Start sessions as you always do, with the self-hosted environment's ID.
For example, with an agent (the
[quickstart](https://platform.claude.com/docs/en/managed-agents/quickstart)
makes one), the `ant` CLI, and `ANTHROPIC_API_KEY` set to your Claude API
key, on your computer:

```bash
ant beta:sessions create --agent agent_... --environment-id env_... \
  --transform id -r --initial-event '
    type: user.message
    content: [{type: text, text: "Write the output of hostname to hello.txt."}]'
```

Within seconds the dispatcher logs `sesn_...: worker started on <vm>`.
Once the session goes idle, `ssh <vm>.exe.xyz cat /workspace/hello.txt`
prints that VM's name.

## Clean up

On your computer, `ssh exe.dev ls` lists each session's VM with the
session's ID as its comment. Delete one with `ssh exe.dev rm <vm>`; a
session that comes back after its VM is gone gets a new, empty one. To
delete every VM tagged `claude-session` (its first two lines alone list
them):

```bash
ssh exe.dev ls --json |
  jq -r '.vms[] | select(.tags // [] | index("claude-session")) | .vm_name' |
  xargs -r ssh exe.dev rm
```

## Troubleshooting

The dispatcher's log is `journalctl -u claude-dispatcher` on its VM:

- `Error code: 401` or `404`: the environment key or ID is wrong.
- `invalid token`: the exe.dev API key is wrong or has expired; make a new
  one.
- `during new: ...` and `giving up`: exe.dev refused a VM, often because the
  plan's VM limit is reached. Delete old session VMs.

A session's own log is on its VM:
`ssh <vm>.exe.xyz journalctl -t claude-worker`.

## Frequently asked questions

### What runs where?

Anthropic runs Claude, the agent loop, sessions, and memory stores. Each session's VM runs its tools (`bash`, `read`, `write`, `edit`, `glob`, and `grep`) as `exedev`, with sudo, in `/workspace`. The dispatcher only claims work and starts workers. Tool inputs and outputs still pass through Anthropic; see its [security model](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-security).

### Which keys reach the session VMs?

Normally just each work item's secret, which authorizes that one session. A work item that comes without one gets the environment key instead, as in Anthropic's own example, and the dispatcher logs a warning. The exe.dev API key stays with the dispatcher, and your Claude API key with you.

### What does it cost?

Anthropic bills sessions and model usage to your Claude account. Session VMs share your exe.dev plan's CPU, memory, and disk rather than being billed one by one, but each counts toward the plan's VM limit (50 on [Personal](/docs/billing/personal)). Delete them as sessions finish.

### Can Claude show me a web app it built?

Yes. Anything it serves on `0.0.0.0`, on a port from 3000 to 9999, is at `https://<vm>.exe.xyz:<port>/`, behind exe.dev login. The session's worker stops a minute after each turn, and everything it started stops with it, even with `nohup` or `setsid`. So say in the agent's system prompt to start servers with `sudo systemd-run --uid=exedev --working-directory=$PWD <command>`, and to run `hostname` for the VM's name.

### Can Claude work on my GitHub repositories?

Not through a session's `github_repository` resource, which self-hosted environments reject. Attach exe.dev's [GitHub integration](/docs/integrations-github) to every session VM by their tag instead, on your computer: `ssh exe.dev integrations add github --name myapp --repository you/myapp --attach tag:claude-session`. Claude then clones `https://github.int.exe.xyz/you/myapp.git`, and no GitHub token reaches a VM.

### Can sessions get bigger VMs, or another image?

Bigger, yes: add `EXE_NEW_FLAGS=--cpu=4 --memory=16GB` (or `--disk=50GB`) to /etc/claude-dispatcher.env and run `sudo systemctl restart claude-dispatcher`. New session VMs get them. Another image works if, like exe.dev's default, it is Debian-based with systemd and a sudo user `exedev`.

### Can all sessions share one VM instead?

Yes, and then you don't need the dispatcher: on that VM, install `ant` and run `ant beta:worker poll`, which runs every session there in turn, in the same `/workspace`. Anthropic's [worker guide](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-workers) covers it.


## Related

- [Create sandboxes from TypeScript](https://exe.dev/deploy/typescript-sandboxes.md): Full VMs as sandboxes. Create, control, and destroy them from your code.
- [Host a Claude Agent SDK app in a sandbox VM](https://exe.dev/deploy/claude-agent-sdk.md): Claude Code as a library, with a whole computer to run on.
- [Running Agents](https://exe.dev/deploy/agents.md): Use exe.dev VMs as a sandbox
- [Run Claude Code on a remote server](https://exe.dev/deploy/claude-code.md): A computer for Claude. A breather for your laptop.
- [Host OpenClaw](https://exe.dev/deploy/openclaw.md): An AI sidekick with its own computer. Your laptop can take a nap.
- [Run Codex on a remote server](https://exe.dev/deploy/codex.md): A computer for Codex. An early night for your laptop.
