New to Claude Skills? Learn how to install them →

Claude Managed Agents: Self-Hosted Sandboxes vs Cloud Environments

Claude Managed Agents can run tool execution in an Anthropic-managed cloud sandbox or on your own infrastructure. Here is what a self-hosted sandbox actually gives up, and what it buys you.

August 27, 2026
Get Claude Skills
9 min read

Two ways to run the same agent

A Claude Managed Agent always has its model calls served by Anthropic. What varies is where the agent's tools actually execute. An environment can be type: cloud, an Anthropic-provisioned sandbox, or type: self_hosted, a sandbox running on infrastructure you control while Anthropic still orchestrates the model and the conversation.

This is not a minor deployment detail. It changes what resources a session can attach, how memory stores behave, what your compliance story looks like, and how much setup work lands on you before an agent can run its first tool call.

AspectCloud environmentSelf-hosted sandbox
Tool executionAnthropic-managed sandboxYour own infrastructure
Network reachAnthropic's egress controlsYour network policy
File and GitHub mountingManaged by AnthropicNot supported at all
Memory storesMounted by Anthropic at /mnt/memory/Downloaded and synced by an SDK worker you run
LifecycleManaged by AnthropicManaged by you

What a self-hosted sandbox actually is

Model access stays cloud-based either way: tool inputs and outputs still flow to Anthropic's control plane, where Claude reads them and decides what to do next. What moves is execution. In a self-hosted sandbox, an environment worker, a process you run, polls Anthropic's work queue for claimed sessions, downloads the agent's skills, executes each tool call locally on your infrastructure, and posts the results back.

This suits agents that need to operate on data that cannot leave your network boundary, reach internal services that are not publicly routable, or run under your organisation's own compliance and audit controls, rather than Anthropic's.

What you give up: file and GitHub resources

Self-hosted sessions cannot include file or github_repository resources. If you try, the API returns a 400:

Environment env_... is a self-hosted environment.
`resources` are not supported with self-hosted environments.

Two concrete consequences follow. First, repository skill discovery, which scans a mounted repository's .claude/skills directory at session start, only works in cloud sandboxes. A self-hosted agent that needs skills has to attach them through the agent's skills array instead, uploaded ahead of time, rather than pulled live from a repo. Second, there is no native way to hand a session a specific file at creation.

The workaround: metadata plus a staging script

Pass file references, an S3 path, a commit SHA, whatever your storage layer uses, through the session's metadata field instead:

curl https://api.anthropic.com/v1/sessions \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-beta: managed-agents-2026-04-01" \
  -H "content-type: application/json" \
  -d '{
    "agent": "'"$AGENT_ID"'",
    "environment_id": "'"$ANTHROPIC_ENVIRONMENT_ID"'",
    "metadata": {"input_file": "s3://my-bucket/data.csv"}
  }'

Your own environment worker's spawn script retrieves the session, reads metadata, and stages the actual file into the working directory before tool execution starts. This is genuinely a workaround, not a native resource type, and it means every self-hosted deployment needs a bit of custom staging logic that a cloud environment gets for free.

Setting up a self-hosted environment

1. Create the environment

Through the Console (Workspace > Environments > New > Self-hosted), the API, or an SDK:

client = anthropic.Anthropic()
environment = client.beta.environments.create(
    name="self-hosted",
    config={"type": "self_hosted"},
)
print(environment.id)

2. Generate an environment key

Open the environment in the Console and select Generate environment key, a Console-only action, then export both values where your worker runs:

export ANTHROPIC_ENVIRONMENT_KEY="sk-ant-oat01-..."
export ANTHROPIC_ENVIRONMENT_ID="env_..."

3. Prepare the worker host

The worker host needs to be Linux, with /bin/bash at exactly that path, and either the ant CLI or an Anthropic SDK (Python, TypeScript or Go) installed. If you plan to use memory stores, prepare a writable mount point ahead of time:

sudo mkdir -p /mnt/memory && sudo chown "$USER" /mnt/memory

4. Run an environment worker

Two deployment patterns:

  • Always-on: a long-running process continuously polling the work queue. Needs only outbound HTTPS, nothing inbound.
  • Webhook-triggered: a process that wakes on session.status_run_started events instead of polling continuously. Needs an inbound webhook endpoint.

An always-on worker with the Python SDK:

import asyncio
import os
from anthropic import AsyncAnthropic
from anthropic.lib.environments import EnvironmentWorker

async def main() -> None:
    environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"]
    environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"]
    async with AsyncAnthropic(auth_token=environment_key) as client:
        worker = EnvironmentWorker(
            client,
            environment_id=environment_id,
            environment_key=environment_key,
            workdir="/workspace",
        )
        await worker.run()

asyncio.run(main())

Memory stores: supported, but SDK-only

Self-hosted sessions can attach up to 8 memory stores, the same ceiling as cloud, but only through the SDK's EnvironmentWorker. The ant CLI's ant beta:worker poll command does not mount memory stores at all, so if a workload needs them, plan for the SDK worker from the start rather than discovering the gap mid-project.

When a work item is claimed, the worker downloads each attached store to /mnt/memory/<store_name>/, reconciles changes with the server on an interval (15 seconds by default), and on a graceful shutdown uploads final changes and removes the local directories:

worker = EnvironmentWorker(
    client,
    environment_id=environment_id,
    environment_key=environment_key,
    workdir="/workspace",
    memory_sync_interval=10,  # seconds, default 15
    memory_sync_deletions="log_only",  # "enabled", "log_only", or "disabled"
)

Constraints worth knowing before you rely on this in production:

  • One session per store per host. Two sessions cannot mount the same memory store simultaneously.
  • Shutdown must be graceful. Send SIGTERM or SIGINT, not SIGKILL, so the worker has a chance to sync before exiting. A killed worker can lose changes made since the last sync interval.
  • Changes are not instantly visible across sessions. With the default 15-second interval, another session reading the same store typically sees updates within about a minute, not immediately.
  • Not available on Claude Platform on AWS at all, cloud or self-hosted.

Sandbox filesystem layout

/workspace
├── skills/
│   └── <skill_name>/        # Downloaded agent skills
└── <agent output files>     # Final deliverables

/mnt/memory/
└── <store_name>/            # Synced memory store directories
    └── .anthropic-memory-store  # Marker file, do not modify

One structural difference from cloud worth knowing if you are porting an agent over: there is no /mnt/session/outputs instruction in the system prompt on self-hosted sandboxes. Final deliverables land wherever the agent actually writes them in your filesystem, so your own tooling needs to know where to look rather than relying on a fixed output path.

Networking: self-hosting and MCP tunnels are independent controls

It is easy to conflate these two, but they solve different problems. Self-hosting controls where code executes. MCP tunnels control how Anthropic reaches your MCP servers over a private network path, independent of where the agent's tools themselves run. You can combine them in any of three ways:

  • Cloud sandbox with an MCP tunnel: execution stays with Anthropic, but private tools stay reachable without exposing them publicly.
  • Self-hosted sandbox with a public MCP server: execution and tool access both stay simple, nothing private to route.
  • Self-hosted sandbox plus an MCP tunnel: both execution and tool access sit inside your own network boundary.

Serving custom tools directly from your worker

A self-hosted worker can also serve its own tools, useful for reaching internal services an MCP server was never built for:

from anthropic import beta_async_tool
from anthropic.lib.environments import EnvironmentWorker

@beta_async_tool
async def get_order_status(order_id: str) -> str:
    """Reaches internal fulfillment system from your sandbox."""
    return f"Order {order_id}: shipped"

worker = EnvironmentWorker(
    client,
    environment_id=environment_id,
    environment_key=environment_key,
    workdir="/workspace",
    tools=lambda env: [*beta_agent_toolset_20260401(env), get_order_status],
)

Wrapping a private MCP server as a custom tool

If an MCP server sits on your internal network with no public endpoint, the worker can keep an open MCP session and expose its tools to the agent as custom tools, forwarding calls and posting results back:

from anthropic.lib.tools.mcp import async_mcp_tool
from mcp.client.streamable_http import streamable_http_client

MCP_SERVER_URL = "http://mcp.internal.example.com:8000/mcp"

async with streamable_http_client(MCP_SERVER_URL) as (read, write, _):
    async with ClientSession(read, write) as mcp_session:
        await mcp_session.initialize()
        listed = await mcp_session.list_tools()
        mcp_tools = [async_mcp_tool(tool, mcp_session) for tool in listed.tools]

        await EnvironmentWorker(
            client,
            environment_id=environment_id,
            environment_key=environment_key,
            workdir="/workspace",
            tools=lambda env: [*beta_agent_toolset_20260401(env), *mcp_tools],
        ).run()

What self-hosting does not fix

It is tempting to reach for a self-hosted sandbox as a compliance shortcut, and it genuinely helps with data residency, egress control and audit trails, since code execution never leaves your infrastructure. But it does not change Managed Agents' platform-level data handling. As covered in our wider look at Managed Agents, the product as a whole is not currently eligible for Zero Data Retention or a HIPAA Business Associate Agreement, regardless of environment type, because sessions are stateful by design and Anthropic's control plane still retains conversation history, session state and events. If ZDR or a BAA is a hard requirement, self-hosting the sandbox does not clear that bar on its own; the Messages API remains the route for that.

Choosing between them

Reach for a cloud environment when you want the least setup: no worker process to run, GitHub repository mounting and skill discovery available out of the box, and Anthropic managing the sandbox lifecycle end to end. Most agents that do not have a specific compliance or network-locality requirement belong here.

Reach for a self-hosted sandbox when tool execution genuinely needs to happen inside your own network boundary, against data or services that cannot be exposed to an external sandbox, and you are prepared to run and monitor a worker process, plan for SDK-only memory stores, and build a small metadata-based staging step in place of native file and repository mounting.

Troubleshooting

A session creation request returns a 400 naming the environment as self-hosted. You included a file or github_repository resource. Neither is supported on self-hosted environments; switch to the metadata-and-staging workaround, or move the workload to a cloud environment if repository mounting is a hard requirement.

Memory stores are not syncing on a self-hosted deployment. Confirm you are using the SDK's EnvironmentWorker, not ant beta:worker poll, which does not mount memory stores at all. Also confirm you are not on Claude Platform on AWS, where memory stores are unsupported regardless of worker type.

The worker loses in-progress memory changes on redeploy. Check your shutdown signal. A SIGKILL gives the worker no chance to run its final sync; use SIGTERM or SIGINT and give it time to complete before the process is forcibly removed.

Two workers keep fighting over the same memory store. Only one session can mount a given store on a given host at a time. If your deployment scales workers horizontally, route sessions that use the same store to the same host, or serialise access at your own queue layer.

Final outputs are not where I expected them. Self-hosted sandboxes do not get the /mnt/session/outputs instruction cloud sessions have in their system prompt. Check your agent's actual working directory writes instead of assuming a fixed output path.

Where to go next

For the full Managed Agents concept model, agents, environments, sessions and events, see Claude Managed Agents explained. For running several agents in one session regardless of environment type, see multiagent orchestration in Claude Managed Agents. For the comparable self-hosting decision on the Claude Code side rather than the API, see how to self-host Claude Code runners. The ant CLI commands referenced throughout are covered in full in Anthropic's ant CLI. Browse the wider catalogue at getclaudeskills.com/skills or by category.

Verified 27 August 2026 directly against Anthropic's self-hosted sandboxes documentation at platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes, read in full.

Frequently asked questions