Claude Platform Docs
Managed AgentsSandboxes auto-hospedadas

Sandboxes auto-hospedadas

Execute sessões do Claude Managed Agents em sandboxes auto-hospedadas, mantendo a execução de ferramentas, os arquivos e a saída de rede na sua própria infraestrutura.

Por padrão, o Managed Agents executa ferramentas e código dentro de sandboxes em nuvem gerenciadas pela Anthropic. As "self-hosted sandboxes" (sandboxes auto-hospedadas) mantêm a orquestração do lado da Anthropic, mas movem a execução de ferramentas para uma infraestrutura que você controla, de modo que o código, o sistema de arquivos e a saída de rede do agente nunca deixam o seu ambiente.

A execução de ferramentas permanece no seu host: o sistema de arquivos que o agente lê e grava, os processos que ele inicia e a rede que ele pode alcançar estão todos sob o seu controle. As entradas e saídas das ferramentas ainda fluem para o plano de controle da Anthropic (onde o Claude é executado) para que o modelo possa ver os resultados e determinar o que fazer em seguida. As skills do agente e o conteúdo de quaisquer memory stores anexados à sessão são armazenados pela Anthropic e copiados para a sua sandbox durante a sessão; as alterações que o agente faz nos arquivos de memória são sincronizadas de volta para o store. Consulte o modelo de segurança para ver o limite completo do fluxo de dados.

Como difere dos ambientes em nuvem

Ambiente em nuvemSandbox auto-hospedada
Onde as ferramentas são executadasSandboxes gerenciadas pela AnthropicSua infraestrutura
Alcance de redeControles de saída da AnthropicSua política de rede
Montagem de arquivos e repositórios GitHubGerenciada pela AnthropicGerenciada por você
Memory storesMontados pela Anthropic em /mnt/memory/Baixados para /mnt/memory/ e sincronizados pelo worker do SDK
Ciclo de vidaGerenciado pela AnthropicGerenciado por você

A auto-hospedagem é uma boa opção quando o agente precisa operar sobre dados que não podem sair do limite da sua rede, alcançar serviços internos que não são roteáveis publicamente ou ser executado sob os controles de conformidade e auditoria da sua própria organização.

Para elegibilidade a Zero Data Retention e HIPAA BAA, consulte API e retenção de dados.

Quando combinar com túneis MCP

A auto-hospedagem controla onde o código do agente é executado. Os túneis MCP controlam como a Anthropic alcança servidores MCP na sua rede. Eles são independentes: uma sessão executada nas sandboxes em nuvem da Anthropic ainda pode alcançar servidores MCP privados por meio de um túnel, e uma sessão auto-hospedada pode usar servidores MCP tunelados ou públicos. Use ambos quando quiser que a execução e o acesso a ferramentas permaneçam dentro do seu limite. Para dar ao agente ferramentas de um servidor MCP dentro da sua rede sem executar um túnel, você também pode encapsular o servidor como ferramentas personalizadas servidas pelo seu worker.

Worker de ambiente

Um "environment worker" (worker de ambiente) é um processo que você executa na sua própria infraestrutura. Ele recebe solicitações de execução de ferramentas da Anthropic e as executa localmente. O ambiente self_hosted atua como uma fila de trabalho: quando uma sessão é atribuída a ele, a Anthropic enfileira a sessão como um item de trabalho. Seu worker reivindica itens de trabalho dessa fila, cria um contexto de execução para cada um, baixa as skills do agente (recursos reutilizáveis, baseados em sistema de arquivos, que dão ao agente expertise específica de domínio), executa as chamadas de ferramentas e envia os resultados de volta.

Os itens de trabalho são reivindicados por meio de polling na fila do ambiente: seja por um worker sempre ativo que faz polling continuamente, ou por um handler acionado por webhook que desperta em session.status_run_started e começa a fazer polling.

Tanto a CLI quanto o SDK incluem workers pré-construídos. A CLI ant oferece suporte apenas ao padrão sempre ativo; o SDK oferece suporte tanto ao sempre ativo quanto ao acionado por webhook. Ambos são configuráveis: consulte Worker auto-hospedado na referência para as flags da CLI, e Helpers do SDK nesta página para as opções do SDK. Para mais controle, chame os endpoints Environments Work diretamente e implemente seu próprio worker.

Sistema de arquivos da sandbox

  • /workspace: o diretório de trabalho padrão do sistema para execução de ferramentas e download de skills. A flag --workdir da CLI usa por padrão o diretório atual; passe --workdir /workspace para corresponder ao padrão do sistema. As skills são baixadas para <workdir>/skills/<name>/. Se você usar um diretório de trabalho diferente, atualize o prompt do sistema do seu agente para que o Claude possa localizar os arquivos das skills.
  • Saídas: em ambientes auto-hospedados, o prompt do sistema da sessão omite a instrução /mnt/session/outputs usada nas sandboxes gerenciadas pela Anthropic, de modo que os entregáveis finais ficam onde quer que o agente os grave no sistema de arquivos da sua sandbox, normalmente sob o diretório de trabalho.
  • /mnt/memory/: os memory stores anexados à sessão são materializados aqui pelo worker do SDK, um diretório por store no mount_path do store (por exemplo, /mnt/memory/user-preferences/). O worker cria esses diretórios quando reivindica a sessão e os remove quando a sessão termina; consulte Usar memory stores.

Antes de começar

Você precisa de:

  • Um agente existente. Se você não tiver um, conclua primeiro o Início rápido e anote o ID do agente.
  • Um host Linux com /bin/bash exatamente nesse caminho. A ferramenta bash do worker o invoca diretamente, sem consultar o PATH. O SDK TypeScript requer adicionalmente unzip e tar no PATH e Node.js 22 ou posterior; os SDKs Python e Go usam suas bibliotecas padrão para extração de arquivos compactados e não têm requisitos adicionais de binários.
  • A CLI ant ou um SDK da Anthropic (Python, TypeScript ou Go) no host do worker.
  • Credenciais: uma chave de ambiente (gerada no Console nas etapas a seguir) autentica o worker na sua fila; sua chave de API do Claude cria sessões e lê estatísticas da fila de fora do host do worker. A geração de chaves é feita apenas pelo Console. Os itens de trabalho reivindicados também carregam um secret por sessão que o worker usa para montar memory stores; você não o gera, mas no padrão de sandbox por sessão você mesmo o encaminha para dentro da sandbox (consulte Executar uma sandbox por sessão).
  • Para memory stores, um host preparado. Se as sessões neste ambiente anexarem memory stores, prepare /mnt/memory no host do worker antes de iniciar o worker; consulte Preparar o host.
  1. Criar um ambiente auto-hospedado

    No Console: Workspace > Environments > New > Self-hosted

    Ou por meio da API:

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

    No Console, abra o ambiente e clique em Generate environment key. A geração de chaves é feita apenas pelo Console, independentemente de você ter criado o ambiente pelo Console ou pela API. Em seguida, exporte o ID e a chave do ambiente no host do worker:

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

Executar um worker

Escolha sempre ativo para a configuração mais simples: um processo de longa duração faz polling na fila continuamente e precisa apenas de HTTPS de saída. Escolha acionado por webhook para evitar executar um poller ocioso; isso requer um endpoint de webhook que a Anthropic possa alcançar (consulte Webhooks para configuração do endpoint e verificação de assinatura).

  1. Instalar a CLI ant

    Execute isto no host do worker.

    Para ambientes Linux, baixe o binário da release diretamente.

    VERSION=1.27.0
    OS=$(uname -s | tr '[:upper:]' '[:lower:]')
    case $(uname -m) in
      x86_64) ARCH=amd64 ;;
      aarch64) ARCH=arm64 ;;
    esac
    curl -fsSL "https://github.com/anthropics/anthropic-cli/releases/download/v${VERSION}/ant_${VERSION}_${OS}_${ARCH}.tar.gz" \
      | sudo tar -xz -C /usr/local/bin ant

    Você pode encontrar todas as releases na página de releases do GitHub.

  2. Executar o worker

    No processo

    ant beta:worker poll reivindica itens de trabalho atribuídos ao ambiente, baixa skills, executa chamadas de ferramentas no diretório de trabalho e envia os resultados de volta. Ele lê ANTHROPIC_ENVIRONMENT_KEY e ANTHROPIC_ENVIRONMENT_ID do ambiente.

    ant beta:worker poll --workdir "/workspace"

    O worker encerra de forma limpa em SIGTERM ou SIGINT: ele cancela qualquer chamada de ferramenta em andamento, envia seu resultado de erro e libera o item de trabalho antes de parar.

    Sandbox por sessão

    Se você precisar de isolamento mais forte (um sistema de arquivos novo, limites de recursos ou controles de rede por sessão), execute cada sessão em sua própria sandbox. Construa uma imagem com ant instalado e ant beta:worker run como entrypoint. A imagem base deve fornecer /bin/bash; curl é usado apenas no momento do build. Quando uma sandbox inicia, ela lê os detalhes da sessão das variáveis de ambiente, trata essa sessão e encerra:

    FROM your-base-image
    ARG ANT_VERSION=1.27.0
    ARG TARGETARCH
    RUN ARCH=$([ "$TARGETARCH" = "arm64" ] && echo arm64 || echo amd64) && \
        curl -fsSL "https://github.com/anthropics/anthropic-cli/releases/download/v${ANT_VERSION}/ant_${ANT_VERSION}_linux_${ARCH}.tar.gz" \
          | tar -xz -C /usr/local/bin ant
    WORKDIR /workspace
    VOLUME /workspace
    ENTRYPOINT ["ant", "beta:worker", "run"]

    Em seguida, escreva um script de spawn que encaminhe os detalhes da sessão para uma sandbox nova. O poller injeta ANTHROPIC_SESSION_ID, ANTHROPIC_WORK_ID, ANTHROPIC_ENVIRONMENT_ID e ANTHROPIC_ENVIRONMENT_KEY no ambiente do script e grava o item de trabalho reivindicado na entrada padrão do script como JSON, incluindo o secret por sessão do item de trabalho quando a Anthropic emitiu um. ANTHROPIC_BASE_URL é opcional e é repassado apenas se tiver sido definido no host do poller; ele substitui o endpoint padrão da API. No exemplo, /host/outputs é um diretório do host que você escolhe; ele é montado via bind no diretório de trabalho da sandbox (/workspace) para que você possa recuperar os entregáveis da sessão depois que a sandbox encerrar. Em ambientes auto-hospedados, o agente grava os entregáveis sob o diretório de trabalho em vez de /mnt/session/outputs (consulte Sistema de arquivos da sandbox), portanto montar o diretório de trabalho é o que os captura; a montagem também captura a árvore skills/ baixada e quaisquer arquivos intermediários que o agente criar.

    #!/bin/bash
    # spawn.sh: chamado uma vez por item de trabalho reivindicado
    mkdir -p "/host/outputs/$ANTHROPIC_SESSION_ID"
    exec docker run --rm \
      -e ANTHROPIC_SESSION_ID -e ANTHROPIC_ENVIRONMENT_KEY \
      -e ANTHROPIC_WORK_ID -e ANTHROPIC_ENVIRONMENT_ID -e ANTHROPIC_BASE_URL \
      -v "/host/outputs/$ANTHROPIC_SESSION_ID":/workspace \
      your-image

    O entrypoint ant beta:worker run não monta memory stores. Se as sessões neste ambiente anexarem memory stores, mantenha o poller, mas construa a imagem por sessão em torno do worker do SDK e estenda o script de spawn para encaminhar o secret do item de trabalho para dentro da sandbox, como mostrado em Executar uma sandbox por sessão.

    Inicie o poller apontando para o script:

    ant beta:worker poll --on-work ./spawn.sh

Helpers do SDK

O SDK fornece três helpers em diferentes níveis de controle. EnvironmentWorker cobre a maioria dos casos de uso; recorra aos helpers de nível mais baixo quando precisar iniciar seu próprio processo por sessão ou executar ferramentas em uma sessão já reivindicada.

  • EnvironmentWorker: o worker pronto para uso. Trata polling, configuração e execução de ponta a ponta.
    • .run(): executa indefinidamente, pegando sessões à medida que chegam.
    • .handle_item(): trata um único item de trabalho reivindicado e encerra. Passe os identificadores de trabalho, sessão e ambiente explicitamente, ou deixe que ele leia as variáveis ANTHROPIC_* que ant beta:worker poll --on-work define para o processo que ele inicia. Para permitir que a sessão monte seus memory stores, passe também o secret do item de trabalho como work_secret (workSecret em TypeScript, WorkSecret em Go) ou defina ANTHROPIC_WORK_SECRET; ant beta:worker poll --on-work não define essa variável, então leia o secret do JSON do item de trabalho que ele grava na entrada padrão do seu script, como mostrado em Executar uma sandbox por sessão.
    • memory_sync_interval (memorySyncIntervalMs em TypeScript, MemorySyncInterval em Go) e memory_sync_deletions (memorySyncDeletions, MemorySyncDeletions): com que frequência os memory stores anexados se reconciliam com o servidor enquanto a sessão é executada, e se os arquivos que o agente exclui localmente também são excluídos do store. Consulte Configurar a sincronização para unidades, padrões e como desativar o suporte a memória.
  • work.poller(): faz polling na fila de trabalho em seu nome e entrega a você cada sessão reivindicada. Use isto quando quiser decidir o que acontece para cada sessão, por exemplo iniciar uma sandbox em vez de executar ferramentas no processo.
    • drain: se deve parar o polling quando a fila estiver vazia em vez de aguardar novo trabalho.
    • block_ms: quanto tempo aguardar a chegada de trabalho antes de retornar, em milissegundos. Deve estar entre 1 e 999 (espera por poll; o helper refaz o poll automaticamente). Passe null (None em Python, param.Null[int64]() em Go) para uma verificação não bloqueante; omitir o parâmetro usa o long-poll padrão de 999 ms.
    • reclaim_older_than_ms: reivindica novamente itens de trabalho que foram reivindicados mas nunca confirmados dentro desse número de milissegundos.
    • auto_stop (autoStop em TypeScript, AutoStop em Go): se deve enviar um sinal de parada para cada item de trabalho quando o corpo do seu loop terminar com ele. Desative-o sempre que o que executa o item de trabalho enviar a parada por conta própria: handle_item() faz isso, então defina-o como false quando você entregar itens reivindicados a handle_item() como os handlers de webhook nesta página fazem, e o mesmo vale para uma sandbox que você inicia e que é responsável pela chamada de parada.
  • client.beta.sessions.events.tool_runner(): executa chamadas de ferramentas para uma única sessão, dados o ID da sessão e uma lista de ferramentas. Use quando você já reivindicou o trabalho e precisa apenas da camada de execução.

Use o work poller diretamente quando quiser iniciar seu próprio processo por sessão, por exemplo criando uma sandbox para cada sessão reivindicada:

import asyncio
import os

from anthropic import AsyncAnthropic
from anthropic.types.beta.environments import BetaSelfHostedWork

SANDBOX_ENV = (
    "ANTHROPIC_ENVIRONMENT_ID",
    "ANTHROPIC_ENVIRONMENT_KEY",
    "ANTHROPIC_WORK_ID",
    "ANTHROPIC_SESSION_ID",
    "ANTHROPIC_WORK_SECRET",
    "ANTHROPIC_BASE_URL",  # forwarded only when set on this host
)


async def launch_container(work: BetaSelfHostedWork) -> None:
    print(f"claimed session {work.data.id}")
    # Substitua `docker run` pelo seu próprio inicializador de sandbox. Encaminhe a chave do
    # ambiente (nunca sua chave de API) e o segredo por sessão do item de trabalho: o worker
    # interno precisa do segredo para montar os armazenamentos de memória da sessão.
    env = os.environ | {
        "ANTHROPIC_WORK_ID": work.id,
        "ANTHROPIC_SESSION_ID": work.data.id,
        "ANTHROPIC_WORK_SECRET": work.secret or "",
    }
    forward = [arg for name in SANDBOX_ENV for arg in ("-e", name)]
    launcher = await asyncio.create_subprocess_exec(
        "docker", "run", "--rm", "--detach", *forward, "your-sdk-worker-image", env=env
    )
    await launcher.wait()


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:
        async for work in client.beta.environments.work.poller(
            environment_id=environment_id,
            environment_key=environment_key,
            auto_stop=False,  # the launched sandbox owns the stop call
        ):
            await launch_container(work)


asyncio.run(main())

O que quer que inicie a sandbox deve encaminhar o secret do item de trabalho reivindicado para dentro dela (por exemplo como ANTHROPIC_WORK_SECRET) junto com os identificadores de sessão, trabalho e ambiente, para que o worker interno possa montar os memory stores da sessão; consulte Executar uma sandbox por sessão.

AgentToolContext é o contexto de execução para chamadas de ferramentas. Ele define o diretório de trabalho e a política de caminhos, e pode baixar as skills da sessão. As ferramentas de arquivo (read, write, edit, glob, grep) ficam confinadas ao diretório de trabalho mais quaisquer diretórios listados em allowed_roots (allowedRoots em TypeScript, AllowedRoots em Go), e write e edit adicionalmente recusam caminhos sob read_only_roots (readOnlyRoots, ReadOnlyRoots). EnvironmentWorker adiciona por conta própria os diretórios dos memory stores da sessão a essas listas. O confinamento é uma proteção apenas para as ferramentas de arquivo, não uma sandbox; ele não restringe bash. beta_agent_toolset_20260401(env) recebe um AgentToolContext e retorna as implementações padrão das ferramentas (bash, read, write, edit, glob, grep).

Com EnvironmentWorker: ambos são gerenciados automaticamente. Passe uma factory tools para personalizar a lista de ferramentas:

EnvironmentWorker(client, ..., tools=lambda env: [beta_bash_tool(env), my_custom_tool])

Com work.poller() e tool_runner(): passe uma lista de ferramentas como tools para client.beta.sessions.events.tool_runner(). Para construir essa lista, configure AgentToolContext você mesmo e chame beta_agent_toolset_20260401(env):

from anthropic.lib.tools.agent_toolset import (
    AgentToolContext,
    beta_agent_toolset_20260401,
)

async with AgentToolContext(
    workdir="/workspace", client=client, session_id=work.data.id
) as env:
    # skills baixadas para /workspace/skills/<name>/
    tools = beta_agent_toolset_20260401(env)

Verificar se o worker está conectado

A partir de um shell separado, com ANTHROPIC_API_KEY definida como sua chave de API do Claude (não a chave de ambiente), confirme que workers_polling é pelo menos 1:

ant beta:environments:work stats --environment-id "$ANTHROPIC_ENVIRONMENT_ID"

Se workers_polling permanecer em 0, o worker não está alcançando a fila: confirme que ANTHROPIC_ENVIRONMENT_KEY e ANTHROPIC_ENVIRONMENT_ID estão definidas no host do worker. Consulte Ler a profundidade da fila para a resposta completa de estatísticas e exemplos em outras linguagens.

Iniciar uma sessão

Quando seu worker estiver em execução, crie uma sessão que tenha como alvo o ambiente. Defina AGENT_ID como o ID do agente que você anotou em Antes de começar. A sessão entra na fila de trabalho do ambiente e aguarda lá até que um worker a reivindique; se nenhum worker estiver conectado, a sessão permanece na fila em vez de falhar.

A Anthropic não monta arquivos nem repositórios GitHub em sandboxes auto-hospedadas. Para disponibilizar arquivos específicos da sessão, passe referências de arquivos (como um caminho S3 ou um SHA de commit) no campo metadata da sessão. O item de trabalho reivindicado não carrega os metadados da sessão, mas carrega o ID da sessão: seu script de spawn ou handler --on-work recupera a sessão (GET /v1/sessions/{session_id}) para ler o campo metadata e, em seguida, prepara os arquivos no diretório de trabalho antes que a execução de ferramentas comece.

session = client.beta.sessions.create(
    agent=agent.id,
    environment_id=environment.id,
    metadata={"input_file": "s3://my-bucket/data.csv"},
)

Consulte Worker auto-hospedado na referência para a lista completa de flags da CLI, e Helpers do SDK para as opções dos helpers do SDK.

Usar memory stores

Sessões em um ambiente auto-hospedado anexam memory stores exatamente como as sessões em ambientes em nuvem: liste-os em resources ao criar a sessão, como mostrado em Anexar um memory store a uma sessão. Uma sessão aceita até 8 memory stores. Em um ambiente auto-hospedado, o worker do SDK, em vez da infraestrutura da Anthropic, materializa cada store para o agente, portanto memory stores ali requerem EnvironmentWorker (ou seu método handle_item()) do SDK Python, TypeScript ou Go.

O worker da CLI ant (ant beta:worker poll e ant beta:worker run) não monta memory stores. Para combinar o poller da CLI com memory stores, execute o worker do SDK dentro de uma sandbox por sessão, conforme descrito em Executar uma sandbox por sessão.

Memory stores não podem ser anexados a sessões em ambientes auto-hospedados no Claude Platform on AWS.

Como o worker trata a memória

Quando o worker reivindica um item de trabalho cuja sessão tem memory stores anexados, ele:

  1. Baixa cada store anexado para seu mount_path no host do worker, autenticando-se com o secret por sessão do item de trabalho. O mount_path é o mesmo diretório sob /mnt/memory/ que as sessões em nuvem usam (por exemplo, /mnt/memory/user-preferences/ para um store chamado "User Preferences"), e o prompt do sistema da sessão o descreve para o agente.
  2. Adiciona esses diretórios às raízes permitidas das ferramentas de arquivo, e os diretórios dos stores anexados com access: "read_only" às suas raízes somente leitura, para que o agente trabalhe nas memórias com as mesmas ferramentas read, write, edit, glob e grep que usa no diretório de trabalho.
  3. Reconcilia alterações locais e remotas após chamadas de ferramentas, no máximo uma vez por intervalo de sincronização (15 segundos por padrão): memórias que mudaram no store são gravadas em disco, e arquivos que o agente alterou são enviados para o store.
  4. Executa uma sincronização final quando a sessão termina, descarrega quaisquer uploads ainda pendentes por até 30 segundos e, em seguida, remove os diretórios que criou. Um worker que é cancelado enquanto uma sessão é executada pula a sincronização final, mas ainda envia os arquivos alterados e remove os diretórios antes de encerrar.

O memory store do lado da Anthropic continua sendo a fonte da verdade. Versões de memória, redação e visualização ou edição de memórias no Console funcionam como nas sessões em nuvem, e as leituras e gravações de memória do agente aparecem no stream de eventos como eventos de ferramenta comuns. Como cada worker sincroniza em um intervalo, uma alteração gravada em uma sessão torna-se visível para outra sessão em execução somente depois que ambas tiverem sincronizado, normalmente bem menos de um minuto no intervalo padrão; sessões em sandboxes em nuvem veem as alterações umas das outras quase imediatamente.

Cada diretório de store contém um arquivo marcador chamado .anthropic-memory-store que vincula o diretório ao seu store. Deixe-o no lugar: o worker não sincroniza um diretório cujo marcador esteja ausente ou alterado.

Preparar o host

Memory stores em sandboxes auto-hospedadas precisam de um sistema de arquivos POSIX no host do worker (o host Linux de Antes de começar); hosts Windows não são suportados, porque o worker requer O_NOFOLLOW ao abrir arquivos de memória. Recomenda-se um sistema de arquivos sensível a maiúsculas e minúsculas, para que caminhos de memória que diferem apenas em maiúsculas e minúsculas não colidam.

Antes de iniciar o worker, crie o diretório pai e torne-o gravável pelo usuário sob o qual o worker é executado:

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

Não crie os diretórios por store você mesmo. O worker cria o diretório mount_path de cada store (por exemplo, /mnt/memory/user-preferences) quando uma sessão inicia, recusa-se a iniciar o trabalho da sessão se algo já existir nesse caminho e remove o diretório quando a sessão termina. Seguem-se duas regras operacionais:

  • Execute uma sessão por sistema de arquivos quando as sessões anexarem o mesmo store. Duas sessões não podem montar o mesmo store em um host ao mesmo tempo, porque ambas precisam do mesmo caminho. Dar a cada sessão sua própria sandbox, conforme descrito em Executar uma sandbox por sessão, satisfaz essa regra.
  • Pare os workers de forma graciosa. Quando você para um worker enquanto uma sessão é executada, EnvironmentWorker envia os arquivos de memória alterados da sessão e remove seus diretórios de store somente se for cancelado em vez de morto: um processo morto não executa nenhum teardown, e o worker não instala handlers de sinal por conta própria. Conecte SIGTERM e SIGINT ao cancelamento no processo que o executa: aborte o signal que você passa ao worker em TypeScript, cancele o context em Go e, em Python, cancele a task que executa run() ou handle_item(). Faça isso a partir de um handler de sinal quando seu worker for o processo, como os workers independentes nesta página fazem, ou a partir do hook de desligamento do seu próprio servidor quando o worker for executado dentro de um handler de webhook, que não deve assumir os sinais do servidor. Em seguida, pare os workers com SIGTERM e dê a eles pelo menos 30 segundos para encerrar antes de qualquer kill forçado, porque o upload final pode levar esse tempo. Se um worker for morto antes que seu teardown seja executado, remova o diretório de store remanescente sob /mnt/memory/ antes da próxima sessão que anexar esse store; quaisquer edições nele que não tenham sido sincronizadas são perdidas.

Execute um sandbox por sessão

O padrão de sandbox por sessão em Execute um worker dá a cada sessão um sistema de arquivos novo, que é o que Prepare o host exige quando as sessões anexam o mesmo store. Mantenha ant beta:worker poll --on-work (ou o work poller do SDK) como o poller no host.

O entrypoint ant beta:worker run mostrado ali não monta memory stores, então construa a imagem por sessão em torno do worker do SDK: seu entrypoint constrói EnvironmentWorker e chama handle_item() (handleItem em TypeScript, HandleItem em Go), que lê os identificadores de sessão, trabalho e ambiente das variáveis ANTHROPIC_* e o secret por sessão do item de trabalho de ANTHROPIC_WORK_SECRET. Você também pode passar o secret explicitamente como work_secret (workSecret em TypeScript, WorkSecret em Go).

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


async def main() -> None:
    async with AsyncAnthropic(auth_token=os.environ["ANTHROPIC_ENVIRONMENT_KEY"]) as client:
        worker = EnvironmentWorker(client, workdir="/workspace")
        # Sem argumentos, handle_item() lê as variáveis ANTHROPIC_* que o script de spawn
        # encaminhou, incluindo ANTHROPIC_WORK_SECRET.
        task = asyncio.create_task(worker.handle_item())
        # Cancelar a tarefa quando o contêiner é parado permite que o worker envie
        # os arquivos de memória alterados e remova os diretórios de armazenamento antes de sair.
        loop = asyncio.get_running_loop()
        for signum in (signal.SIGINT, signal.SIGTERM):
            loop.add_signal_handler(signum, task.cancel)
        with contextlib.suppress(asyncio.CancelledError):
            await task


asyncio.run(main())

ant beta:worker poll --on-work não define ANTHROPIC_WORK_SECRET para o script que ele inicia, então o script de spawn lê o secret do JSON do item de trabalho em sua entrada padrão e o passa para dentro do sandbox:

#!/bin/bash
# spawn.sh: chamado uma vez por item de trabalho reivindicado
# O item de trabalho reivindicado chega como JSON no stdin. Seu secret é a
# credencial por sessão que os endpoints do memory store exigem.
ANTHROPIC_WORK_SECRET="$(jq -r '.secret // empty')"
export ANTHROPIC_WORK_SECRET
mkdir -p "/host/outputs/$ANTHROPIC_SESSION_ID"
exec docker run --rm \
  -e ANTHROPIC_SESSION_ID -e ANTHROPIC_ENVIRONMENT_KEY \
  -e ANTHROPIC_WORK_ID -e ANTHROPIC_ENVIRONMENT_ID -e ANTHROPIC_BASE_URL \
  -e ANTHROPIC_WORK_SECRET \
  -v "/host/outputs/$ANTHROPIC_SESSION_ID":/workspace \
  your-sdk-worker-image

Se, em vez disso, você reivindicar trabalho com o work poller do SDK, passe o secret de cada item reivindicado para dentro do sandbox que você inicia da mesma forma. Passe-o apenas para o sandbox que atende àquela sessão e nunca o registre em log.

A imagem do sandbox também precisa de um /mnt/memory gravável (consulte Prepare o host). Como cada sandbox atende a uma sessão e é descartado depois, nenhum diretório remanescente precisa de limpeza, e os diretórios de memória não precisam ser montados via bind no host: o worker faz upload de seu conteúdo para o store antes de o sandbox encerrar. Se você parar um contêiner antes de sua sessão terminar, envie um sinal que o entrypoint transforme em cancelamento (consulte Prepare o host) em vez de matá-lo, para que esse upload ainda seja executado. Dê também ao contêiner tempo para concluir o upload: o Docker segue o sinal de parada com SIGKILL após 10 segundos por padrão, então aumente esse limite para pelo menos os 30 segundos que Prepare o host exige, com --stop-timeout em docker run ou o período de tolerância de encerramento do seu orquestrador.

Configure a sincronização

Duas opções de EnvironmentWorker controlam o comportamento de memória:

  • memory_sync_interval (Python, em segundos; memorySyncIntervalMs em TypeScript, em milissegundos; MemorySyncInterval em Go, uma duração): com que frequência os stores anexados se reconciliam com o servidor enquanto a sessão é executada. O padrão é 15 segundos; o mínimo é 5 segundos. Um intervalo mais curto reduz a janela em que outra sessão vê memórias desatualizadas, ao custo de mais requisições ao memory store. None em Python, null em TypeScript ou uma duração negativa em Go desativa totalmente o suporte a memória: o worker não baixa nem sincroniza stores, e uma sessão com memory stores anexados é executada sem eles, embora seu prompt do sistema ainda os descreva; portanto, desative o suporte a memória apenas em workers cujas sessões não anexam memory stores. Enquanto o suporte a memória estiver ativado, um item de trabalho que chega sem um secret por sessão para uma sessão com stores anexados falha em vez de ser executado sem memória (consulte Solucione problemas de montagens de memória).
  • memory_sync_deletions (memorySyncDeletions em TypeScript, MemorySyncDeletions em Go): se um arquivo que o agente exclui localmente também é excluído do store. O valor é um de "enabled" (o padrão), "log_only" ou "disabled" em Python e TypeScript, e uma das constantes environments.MemorySyncDeletionsEnabled (o valor zero), environments.MemorySyncDeletionsLogOnly ou environments.MemorySyncDeletionsDisabled em Go. Quando ativado, o worker exclui a memória do store assim que uma sincronização posterior confirma que o arquivo ainda está ausente; no modo somente log, ele executa as mesmas verificações, mas apenas registra o que teria excluído, o que permite observar o que seus workers excluiriam antes de confiar no modo ativado; quando desativado, ele nunca exclui do store. Uploads e downloads não são afetados por essa configuração.

Defina essas opções onde você constrói o worker, seja por meio do construtor EnvironmentWorker ou, em Python e TypeScript, da factory client.beta.environments.work.worker() que o handler de webhook usa.

Por exemplo, para sincronizar a cada 10 segundos e apenas registrar em log as exclusões que o worker teria feito:

worker = EnvironmentWorker(
    client,
    environment_id=environment_id,
    environment_key=environment_key,
    workdir="/workspace",
    memory_sync_interval=10,  # seconds
    memory_sync_deletions="log_only",
)

Stores somente leitura e conflitos

Para um store anexado com access: "read_only", as ferramentas write e edit se recusam a alterar arquivos dentro de seu diretório, e o worker nunca faz upload de nada dele. Alterações feitas por meio de bash, ou por meio de uma ferramenta personalizada ou servidor MCP que você serve a partir do sandbox, não são bloqueadas localmente: elas nunca são sincronizadas com o store, e a próxima alteração remota nessa memória as sobrescreve. Se você precisa que a própria cópia local permaneça inalterada durante a sessão, desative a ferramenta bash para esse agente e não lhe dê nenhuma ferramenta personalizada que grave no sistema de arquivos do sandbox; não monte o caminho do store como somente leitura, porque o próprio worker precisa criar o diretório e gravar nele as memórias baixadas.

Conflitos são resolvidos a favor do store. Quando o agente altera um arquivo de memória que também foi alterado no store desde a última vez que a sessão o sincronizou, o worker mantém a versão do store na próxima sincronização, sobrescreve o arquivo local com ela e registra um aviso; as próprias ferramentas write e edit têm sucesso e nenhum erro chega ao agente. Se a alteração do agente ainda se aplica, ele pode reler o arquivo após a sincronização e fazer a alteração novamente.

Solucione problemas de montagens de memória

O worker registra em log falhas de montagem e de sincronização em segundo plano em vez de reportá-las à sessão; apenas recusas de somente leitura chegam ao agente, como erros de ferramenta (consulte Stores somente leitura e conflitos). Se um memory store não puder ser montado quando o worker reivindica uma sessão, o worker falha o item de trabalho: a sessão não emite nenhum evento de erro e permanece ociosa.

SintomaCausaCorreção
O log do worker contém the work item carried no sessions token (em Go, o erro ErrSessionMemoryNoToken) e o item de trabalho falha.O secret por sessão do item de trabalho não chegou ao worker: memory stores em sandboxes auto-hospedados não estão ativados para sua organização, ou seu script de spawn não encaminhou o secret para dentro do sandbox.No padrão de sandbox por sessão, encaminhe ANTHROPIC_WORK_SECRET para dentro do sandbox como mostrado em Execute um sandbox por sessão. Se o worker faz polling e executa sessões em um único processo e ainda registra isso, entre em contato com o suporte.
O log do worker contém something already exists at the memory store's path.Um diretório remanescente de uma sessão anterior, geralmente uma cujo worker foi morto antes de seu teardown ser executado.Remova o diretório remanescente que a linha de log nomeia. Edições nele que não haviam sido sincronizadas são perdidas.
O log do worker contém cannot create the memory store's folder e the worker host must make this mount path writable.O usuário com o qual o worker é executado não pode criar diretórios em /mnt/memory.Crie /mnt/memory e faça chown dele para esse usuário; consulte Prepare o host.
A sessão fica idle com um stop reason requires_action e nenhum evento de erro logo após um worker reivindicá-la.O worker falhou o item de trabalho porque não conseguiu montar um memory store, por um dos motivos anteriores.Corrija a causa no host e então envie um evento user.interrupt: o trabalho da sessão é enfileirado novamente e o próximo worker que o reivindicar tenta a montagem novamente.

Sirva ferramentas personalizadas a partir do seu sandbox

Ferramentas personalizadas são ferramentas que seu próprio código executa: o agente emite um evento agent.custom_tool_use e aguarda um user.custom_tool_result correspondente. O worker pode ser esse código e, como ele é executado dentro do seu sandbox, a ferramenta alcança os serviços internos, credenciais e saída de rede que você configurou para o sandbox, e nada mais. A chave de ambiente autoriza a publicação de resultados de ferramentas personalizadas, então sua chave de API do Claude fica fora do host do worker.

  1. Declare a ferramenta no agente

    Adicione uma entrada custom às tools do agente cujo name corresponda à ferramenta que seu worker registra. Consulte Ferramentas personalizadas para o formato completo da declaração.

    {
      "type": "custom",
      "name": "get_order_status",
      "description": "Look up an order in the internal fulfillment system by order ID.",
      "input_schema": {
        "type": "object",
        "properties": {
          "order_id": { "type": "string", "description": "The order ID" }
        },
        "required": ["order_id"]
      }
    }
  2. Registre a implementação no worker

    Passe a ferramenta por meio da factory tools do worker (consulte Helpers do SDK), junto com o conjunto de ferramentas integrado:

    import asyncio
    import os
    from anthropic import AsyncAnthropic, beta_async_tool
    from anthropic.lib.environments import EnvironmentWorker
    from anthropic.lib.tools.agent_toolset import beta_agent_toolset_20260401
    
    
    @beta_async_tool
    async def get_order_status(order_id: str) -> str:
        """Look up an order in the internal fulfillment system by order ID."""
        # Executa no host do worker: chame qualquer coisa que o sandbox possa alcançar.
        return f"Order {order_id}: shipped"
    
    
    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:
            await EnvironmentWorker(
                client,
                environment_id=environment_id,
                environment_key=environment_key,
                workdir="/workspace",
                tools=lambda env: [*beta_agent_toolset_20260401(env), get_order_status],
            ).run()
    
    
    asyncio.run(main())

O worker responde apenas às ferramentas registradas nele. Uma ferramenta personalizada que é declarada no agente, mas não registrada em nenhum worker ou cliente, deixa a sessão pausada com um stop reason requires_action até que algo publique seu resultado; consulte Tratando chamadas de ferramentas personalizadas para o fluxo de eventos.

Encapsule um servidor MCP como ferramentas personalizadas

O conector MCP se conecta a servidores MCP a partir do lado da Anthropic, então um servidor precisa expor um endpoint HTTP que a Anthropic possa alcançar, diretamente ou por meio de um túnel MCP. Para usar um servidor que apenas sua rede pode alcançar, torne o worker o cliente MCP e declare as ferramentas do servidor como ferramentas personalizadas. O servidor MCP não precisa de conectividade de entrada de fora da sua rede; a Anthropic recebe as definições de ferramentas que você declara no agente, a entrada de cada chamada e o resultado que seu worker publica de volta. Em tempo de execução, o modelo chama uma ferramenta encapsulada como qualquer outra ferramenta personalizada:

  1. O agente emite um evento agent.custom_tool_use.
  2. O worker, dentro do seu sandbox, encaminha a chamada por sua sessão MCP aberta para o servidor na sua rede.
  3. O worker publica a resposta do servidor como o user.custom_tool_result.

Os helpers MCP do lado do cliente dos SDKs convertem as ferramentas do servidor nas ferramentas executáveis que o worker aceita; instale um SDK MCP junto com o SDK da Anthropic (pip install "anthropic[mcp]" "mcp>=1.24", npm install @modelcontextprotocol/sdk, go get github.com/modelcontextprotocol/go-sdk). Os exemplos se conectam sem autenticação; para enviar credenciais, configure o cliente HTTP ou as opções de requisição que você entrega ao transporte MCP (http_client em Python, requestInit em TypeScript, HTTPClient em Go).

  1. Declare as ferramentas do servidor no agente

    Liste as ferramentas do servidor MCP e declare cada uma como uma ferramenta custom; os campos MCP name, description e inputSchema mapeiam um a um para os campos da ferramenta personalizada. Se o servidor paginar sua lista de ferramentas, declare todas as páginas; o worker precisa listar as mesmas páginas.

    import asyncio
    from typing import Any, cast
    from anthropic import AsyncAnthropic
    from anthropic.types.beta import BetaManagedAgentsCustomToolParams
    from mcp import ClientSession, types
    # Requer mcp >= 1.24, que renomeou streamablehttp_client para streamable_http_client.
    from mcp.client.streamable_http import streamable_http_client
    
    MCP_SERVER_URL = "http://mcp.internal.example.com:8000/mcp"
    
    
    def to_custom_tool(tool: types.Tool) -> BetaManagedAgentsCustomToolParams:
        # Os campos MCP mapeiam um a um para uma declaração de ferramenta personalizada. O cast
        # entrega o dicionário do schema ao parâmetro tipado do SDK sem alterações.
        return {
            "type": "custom",
            "name": tool.name,
            "description": tool.description or tool.name,
            "input_schema": cast(Any, tool.inputSchema),
        }
    
    
    async def main() -> None:
        # Execute isto onde você cria agentes, não no host worker: ele
        # autentica com sua chave de API do Claude (ANTHROPIC_API_KEY).
        async with (
            streamable_http_client(MCP_SERVER_URL) as (read, write, _),
            ClientSession(read, write) as mcp_session,
            AsyncAnthropic() as client,
        ):
            await mcp_session.initialize()
            listed = await mcp_session.list_tools()
            agent = await client.beta.agents.create(
                name="Internal tools agent",
                model="claude-opus-5",
                tools=[
                    {"type": "agent_toolset_20260401"},
                    *[to_custom_tool(tool) for tool in listed.tools],
                ],
            )
            print(agent.id)
    
    
    asyncio.run(main())
  2. Sirva as ferramentas a partir do worker

    Conecte-se ao mesmo servidor MCP na inicialização, converta suas ferramentas com os helpers MCP e registre-as junto com o conjunto de ferramentas integrado. Mantenha uma sessão MCP aberta durante toda a vida do worker.

    import asyncio
    import os
    from datetime import timedelta
    from anthropic import AsyncAnthropic
    from anthropic.lib.environments import EnvironmentWorker
    from anthropic.lib.tools.agent_toolset import beta_agent_toolset_20260401
    from anthropic.lib.tools.mcp import async_mcp_tool
    from mcp import ClientSession
    # Requer mcp >= 1.24, que renomeou streamablehttp_client para streamable_http_client.
    from mcp.client.streamable_http import streamable_http_client
    
    MCP_SERVER_URL = "http://mcp.internal.example.com:8000/mcp"
    
    
    async def main() -> None:
        environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"]
        environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"]
        # Conecta ao servidor MCP uma vez na inicialização e mantém a sessão aberta durante
        # toda a vida do worker. O timeout transforma uma chamada de ferramenta travada em um
        # resultado de erro em vez de uma chamada paralisada.
        async with (
            streamable_http_client(MCP_SERVER_URL) as (read, write, _),
            ClientSession(read, write, read_timeout_seconds=timedelta(seconds=60)) as mcp_session,
            AsyncAnthropic(auth_token=environment_key) as client,
        ):
            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()
    
    
    asyncio.run(main())

Tenha o seguinte em mente ao encapsular um servidor MCP:

  • As ferramentas são declaradas, não descobertas em tempo de execução. O worker lista as ferramentas do servidor MCP uma vez na inicialização e não pode adicionar ferramentas a uma sessão em execução. Quando as ferramentas do servidor mudarem, declare-as novamente, no agente ou em uma sessão ociosa por meio de Atualizando a configuração do agente, e reinicie o worker.
  • Nomes e descrições precisam se adequar à API Managed Agents. Nomes de ferramentas personalizadas são únicos por agente e usam letras, dígitos, sublinhados e hífens (1–128 caracteres); uma descrição não vazia é obrigatória; e o array tools de um agente aceita no máximo 128 entradas (cada ferramenta encapsulada é uma entrada, e o conjunto de ferramentas integrado é mais uma). A API rejeita uma declaração que reutilize um nome de ferramenta, nomeie uma ferramenta personalizada com o nome de uma ferramenta de agente integrada como bash ou read, ou use o prefixo reservado mcp__. Os helpers MCP mantêm os nomes e descrições do servidor, então renomeie ou reduza onde necessário. Quando dois servidores expõem o mesmo nome de ferramenta, defina o wrapper você mesmo sob um nome com prefixo e faça-o chamar o nome original da ferramenta do servidor.
  • A maioria dos schemas passa sem alterações. A API aceita as palavras-chave de JSON Schema que servidores MCP comumente emitem, como additionalProperties e title. Ela rejeita palavras-chave de referência como $ref em qualquer lugar do input_schema de uma ferramenta personalizada, então incorpore inline os schemas que geradores como pydantic fatoram em $defs. Ela também rejeita oneOf, anyOf e allOf no nível superior, e nomes de propriedades fora de letras, dígitos, sublinhados, pontos e hífens (1–64 caracteres).
  • Falhas de ferramentas aparecem como resultados de ferramenta com erro. Quando o servidor MCP reporta um erro de ferramenta, o worker publica um resultado de ferramenta com erro ao qual o modelo pode reagir. Conteúdo MCP sem equivalente em resultado de ferramenta, como blocos de áudio e links de recursos, também aparece como erro. Defina um timeout no cliente MCP para uma falha mais rápida e clara, como o exemplo de worker em Python faz com read_timeout_seconds. Sem um, uma chamada travada se torna um resultado de erro apenas quando o timeout de requisição padrão do SDK MCP de TypeScript dispara (cerca de um minuto) ou quando o próprio backstop do worker o faz: cerca de dois minutos e meio em Python, e dois minutos em Go, onde o worker cancela uma chamada de ferramenta que ultrapassa seu padrão de 120 segundos e publica um resultado de erro.
  • Encapsule servidores que você opera ou em que confia. O nome, a descrição e os resultados de uma ferramenta encapsulada entram no contexto do modelo como os de qualquer outra ferramenta: entrada não confiável que pode influenciar o que o agente faz com suas outras ferramentas, incluindo bash no host do worker. Declare apenas as ferramentas que você pretende que o agente use.
  • Políticas de permissão não se aplicam a ferramentas personalizadas. Políticas de permissão governam os conjuntos de ferramentas integrado e MCP; o worker executa toda chamada de ferramenta encapsulada que o modelo faz, então coloque qualquer etapa de aprovação no código da sua própria ferramenta.

Monitoramento e operações

Essas chamadas são executadas a partir das suas ferramentas de monitoramento ou operações, autenticadas com sua chave de API do Claude, para observar e gerenciar a frota de workers. O loop de reivindicação e keep-alive é tratado dentro dos helpers do worker, então você não chama esses endpoints diretamente.

Leia a profundidade da fila

work.stats retorna o estado da fila para um ambiente:

  • depth é o número de itens aguardando para serem reivindicados. Escale sua frota de workers ou alerte sobre backlog com base nesse valor.
  • pending é o número de itens reivindicados por um worker, mas ainda não confirmados. Os helpers do worker confirmam cada item antes de processá-lo, então esse valor fica próximo de zero em operação normal; um valor diferente de zero sustentado significa que um worker travou entre reivindicar e confirmar.
  • oldest_queued_at é o timestamp do item mais antigo ainda na fila, aguardando para ser reivindicado ou reivindicado mas ainda não confirmado, ou null quando não há nenhum.
  • workers_polling é o número de workers que fizeram polling nos últimos 30 segundos. Use isso para alertas de liveness.
import os

import anthropic

client = anthropic.Anthropic()

stats = client.beta.environments.work.stats(os.environ["ANTHROPIC_ENVIRONMENT_ID"])
print(f"depth={stats.depth} pending={stats.pending}")
{
  "type": "work_queue_stats",
  "depth": 0,
  "pending": 0,
  "oldest_queued_at": null,
  "workers_polling": 0
}

Pare uma sessão graciosamente

Use work.stop para pedir ao worker que está tratando uma sessão específica que a encerre. Por padrão, o item de trabalho passa para stopping: o worker percebe em seu próximo heartbeat de lease, cancela a chamada de ferramenta em andamento da sessão e confirma o encerramento, momento em que o item de trabalho se torna stopped. Passe force: true no corpo da requisição (com a CLI, passe --force) para marcar o item de trabalho como stopped imediatamente em vez de aguardar a confirmação do worker.

Como essas chamadas são executadas a partir das suas ferramentas de operações e não do host do worker, ANTHROPIC_WORK_ID não é definido automaticamente. Defina-o com o ID do item de trabalho alvo antes de executar os exemplos a seguir. Para encontrar o ID de um item de trabalho, liste os itens de trabalho do ambiente por meio dos endpoints Environments Work.

import os

import anthropic

client = anthropic.Anthropic()

work = client.beta.environments.work.stop(
    os.environ["ANTHROPIC_WORK_ID"],
    environment_id=os.environ["ANTHROPIC_ENVIRONMENT_ID"],
)
print(work.state)

Próximos passos

Modelo de responsabilidade compartilhada para ambientes de sandbox auto-hospedados.

Crie uma sessão para executar seu agente e começar a executar tarefas.

Conecte o Claude com segurança a servidores MCP em execução na sua rede privada sem abrir portas de entrada ou expor serviços à internet pública.

Was this page helpful?