conteúdo
Introdução
O Claude Code (v2.1.47) traz um recurso experimental chamado Agent Teams: várias sessões do Claude Code coordenam o trabalho compartilhado por meio de uma topologia com um líder e integrantes da equipe. Venho desenvolvendo o Hive, um orquestrador de programação com múltiplos agentes que tem objetivos semelhantes, mas uma arquitetura muito diferente, então eu queria entender como a abordagem da Anthropic funciona por dentro.
Este artigo documenta o que descobri ao:
- Ler a documentação oficial
- Examinar artefatos reais deixados em disco por sessões anteriores de equipes
- Deixar o Claude analisar o binário do Claude Code (v2.1.47) em busca de detalhes de implementação (haha!)
Índice
- 1. Visão geral da arquitetura
- 2. A lista de tarefas compartilhada
- 3. Comunicação entre agentes
- 4. Criação e ciclo de vida dos agentes
- 5. Controles de qualidade e hooks
- 6. Economia de tokens
- 7. Resumo da arquitetura
- Fontes
1. Visão geral da arquitetura
Uma equipe de agentes consiste em quatro componentes:
| Componente | Função |
|---|---|
| Líder da equipe | A sessão principal do Claude Code que cria a equipe e inicia seus integrantes |
| Integrantes | Instâncias separadas do Claude Code, cada uma com sua própria janela de contexto |
| Lista de tarefas | Itens de trabalho compartilhados armazenados como arquivos JSON individuais em disco |
| Caixa de mensagens | Arquivos de caixa de entrada por agente para entrega de mensagens |
Toda a camada de coordenação é baseada em arquivos. O sistema de arquivos em ~/.claude/ é a única base de coordenação:
~/.claude/
├── teams/{team-name}/
│ ├── config.json # team membership registry
│ └── inboxes/{agent-name}.json # per-agent mailbox
└── tasks/{team-name}/
├── .lock # flock() for concurrent task claiming
├── .highwatermark # auto-increment counter
├── 1.json # individual task files
├── 2.json
└── ...
Essa arquitetura é fundamentalmente descentralizada. O líder é apenas mais uma sessão do Claude com ferramentas extras (TeamCreate, TeamDelete, SendMessage). Não há nenhum processo em segundo plano. A coordenação surge do acesso compartilhado aos arquivos.
Em uma sessão ativa, se você pedir ao Claude para criar uma equipe para realizar algum tipo de tarefa e depois executar o seguinte em outra janela, poderá observar o sistema de arquivos sendo atualizado em tempo real.
watch -n 0.5 'tree ~/.claude/teams/ 2>/dev/null; echo "---"; tree ~/.claude/tasks/ 2>/dev/null'
Por exemplo, com o seguinte prompt:
can you spawn an agent team to examine this codebase?
- have one look for bugs
- have one look for complexity
- have one look for good things to call out and play devil's advocate against the other two agents
Observei isto:
teams
└── code-review
├── config.json
└── inboxes
├── bug-hunter.json
├── complexity-analyst.json
├── devils-advocate.json
└── team-lead.json
Configuração da equipe
A configuração da equipe em ~/.claude/teams/{team-name}/config.json contém um array members que os integrantes leem para descobrir uns aos outros:
{
"members": [
{ "name": "team-lead", "agentId": "abc-123", "agentType": "leader" },
{
"name": "researcher",
"agentId": "def-456",
"agentType": "general-purpose"
}
]
}
Os nomes são o principal mecanismo de endereçamento (há UUIDs, mas eles não são usados para roteamento). Toda a troca de mensagens e atribuição de tarefas usa o campo name.
2. A lista de tarefas compartilhada
Formato dos arquivos
Cada tarefa é armazenada como um arquivo JSON individual em ~/.claude/tasks/{team-name}/. Aqui está um exemplo real de uma sessão anterior:
{
"id": "1",
"subject": "Hunt for bugs across the codebase",
"description": "...",
"activeForm": "Hunting for bugs",
"owner": "bug-hunter",
"status": "completed",
"blocks": [],
"blockedBy": []
}
Esquema das tarefas:
| Campo | Tipo | Descrição |
|---|---|---|
id |
string | ID numérico, com incremento automático via .highwatermark |
subject |
string | Título no imperativo (por exemplo, "Execute os testes") |
description |
string | Requisitos detalhados e critérios de aceitação |
activeForm |
string | Forma no gerúndio para exibição no indicador de atividade ("Executando testes") |
status |
string | pending → in_progress → completed (ou deleted) |
blocks |
string[] | IDs das tarefas que esta tarefa bloqueia |
blockedBy |
string[] | IDs das tarefas que precisam ser concluídas antes que esta tarefa possa começar |
Controle de concorrência
Dois arquivos especiais permitem a coordenação:
.lock: Um arquivo de 0 bytes usado para exclusão mútua no nível do sistema de arquivos (flock()). Presente em todos os 42 diretórios de tarefas observados na minha máquina..highwatermark: Contém um único número inteiro (por exemplo,"3","13"). É o próximo ID de tarefa disponível para incremento automático.
Como assumir tarefas
O processo de assumir tarefas usa bloqueio de arquivos para evitar condições de corrida. Os integrantes dão preferência às tarefas com os menores IDs. Uma tarefa com um array blockedBy não vazio não pode ser assumida até que todas as tarefas que a bloqueiam estejam em um estado terminal.
Observação: a maioria dos diretórios de tarefas está vazia
Dos 42 diretórios de tarefas na minha máquina, apenas 5 continham arquivos JSON de tarefas propriamente ditos. Os outros 37 tinham apenas .lock e .highwatermark. Isso provavelmente significa que as tarefas são removidas após a conclusão, ou que essas foram sessões em que o Claude usou a lista de tarefas interna (disponível desde o lançamento do recurso de lista de tarefas) sem decompor o trabalho em arquivos de subtarefas.
3. Comunicação entre agentes
Padrão de caixas de mensagens
Cada agente tem um arquivo contendo um array JSON em ~/.claude/teams/{team-name}/inboxes/{agent-name}.json. Aqui está uma caixa de entrada real de uma sessão anterior em que um líder de equipe enviou trabalho para um controlplane-agent:
[
{
"from": "team-lead",
"text": "{\"type\":\"task_assignment\",\"taskId\":\"1\",\"subject\":\"Phase 2: Control-plane - remove participants/presence\",\"description\":\"Remove multiplayer code from the control-plane package...\",\"assignedBy\":\"team-lead\",\"timestamp\":\"2026-02-18T02:37:16.890Z\"}",
"timestamp": "2026-02-18T02:37:16.890Z",
"read": false
}
]
Observe a codificação JSON dentro de JSON: o campo text é uma string JSON que contém um objeto de mensagem serializado. O envelope externo tem os campos from, text, timestamp e read.
Tipos de mensagens
O campo type dentro do conteúdo de text aceita:
| Tipo | Direção | Finalidade |
|---|---|---|
task_assignment |
líder → integrante | Atribuir uma tarefa com todos os detalhes |
message |
qualquer agente → qualquer agente | Mensagem direta para um destinatário |
broadcast |
líder → todos | A mesma mensagem para todos os integrantes |
shutdown_request |
líder → integrante | Solicitar encerramento controlado |
shutdown_response |
integrante → líder | Aprovar ou rejeitar o encerramento |
plan_approval_request |
integrante → líder | Enviar um plano para revisão |
plan_approval_response |
líder → integrante | Aprovar ou rejeitar com feedback |
idle_notification |
integrante → líder | Enviada automaticamente quando o turno do integrante termina |
Mecanismo de entrega
Fluxo de escrita: O remetente adiciona uma nova entrada ao final do array JSON no arquivo de caixa de entrada do destinatário.
Fluxo de leitura: O destinatário consulta periodicamente seu próprio arquivo de caixa de entrada. Novas mensagens são injetadas como turnos sintéticos da conversa (elas aparecem como se um usuário as tivesse enviado).
Broadcast: Literalmente grava a mesma mensagem no arquivo de caixa de entrada de cada integrante. O custo de tokens cresce linearmente com o tamanho da equipe.
A comunicação se resume a adicionar dados ao final de um arquivo + ler um arquivo. A latência entre o envio e o recebimento depende do intervalo de consulta do destinatário.
Visibilidade das mensagens diretas entre pares
Quando um integrante envia uma mensagem direta para outro integrante, um breve resumo é incluído na notificação de inatividade enviada ao líder. Isso permite que o líder acompanhe a colaboração entre pares sem receber o conteúdo completo da mensagem.
4. Criação e ciclo de vida dos agentes
Como os integrantes são criados
Cada integrante é um processo separado da CLI claude. O líder os inicia por meio da ferramenta Task com os parâmetros team_name e name. Variáveis de ambiente são definidas no processo criado:
CLAUDE_CODE_TEAM_NAME: definida automaticamente nos integrantes criadosCLAUDE_CODE_PLAN_MODE_REQUIRED: definida comotruese a aprovação do plano for necessária
Inicialização do contexto
Os integrantes carregam o mesmo contexto do projeto que qualquer nova sessão:
- Arquivos
CLAUDE.mddo diretório de trabalho - Servidores MCP
- Skills
- O prompt de criação enviado pelo líder
O histórico da conversa do líder NÃO é transferido. Cada integrante começa do zero, tendo apenas o prompt de criação como contexto.
Implementação interna
A análise do binário do Claude Code v2.1.47 mostra que o contexto dos integrantes é gerenciado via AsyncLocalStorage com estes campos:
agentId,agentName,teamNameparentSessionId,colorplanModeRequired
Principais funções internas:
isTeammate()/isTeamLead(): detecção de papéiswaitForTeammatesToBecomeIdle(): primitiva de sincronização para o lídergetTeammateContext()/setDynamicTeamContext(): gerenciamento do contexto em tempo de execução
Detecção de inatividade
Após cada turno do LLM, um integrante entra automaticamente em estado de inatividade e envia uma idle_notification ao líder. Esse é o estado normal de repouso, e não uma condição de erro ou de falta de atualização. Enviar uma mensagem para um integrante inativo o desperta (o próximo ciclo de consulta detecta a mensagem na caixa de entrada).
Protocolo de encerramento
- O líder envia
shutdown_requesta um integrante - O integrante pode aprovar (encerra de forma controlada) ou rejeitar (continua trabalhando e apresenta uma explicação)
- A limpeza da equipe via
TeamDeleteremove~/.claude/teams/{team-name}/e~/.claude/tasks/{team-name}/ - A limpeza falha se algum integrante ainda estiver ativo; eles precisam ser encerrados primeiro
Herança de permissões
Os integrantes herdam o modo de permissão do líder no momento da criação. Se o líder executa --dangerously-skip-permissions, todos os integrantes também executam. Os modos individuais podem ser alterados após a criação, mas não podem ser configurados por integrante no momento da criação.
5. Controles de qualidade e hooks
O Agent Teams se integra ao sistema de hooks do Claude Code para garantir a qualidade:
Hook TeammateIdle
É acionado quando um integrante está prestes a entrar em estado de inatividade. O código de saída 2 envia o conteúdo de stderr como feedback e impede a inatividade, mantendo o integrante trabalhando.
{
"hook_event_name": "TeammateIdle",
"teammate_name": "researcher",
"team_name": "my-project"
}
Hook TaskCompleted
É acionado quando uma tarefa está sendo marcada como concluída. O código de saída 2 impede a conclusão e retorna o conteúdo de stderr como feedback.
{
"hook_event_name": "TaskCompleted",
"task_id": "task-001",
"task_subject": "Implement user authentication",
"task_description": "Add login and signup endpoints",
"teammate_name": "implementer",
"team_name": "my-project"
}
Isso ocorre em duas situações: (1) quando qualquer agente marca explicitamente uma tarefa como concluída via TaskUpdate, ou (2) quando um integrante de uma equipe de agentes termina seu turno com tarefas em andamento.
Tipos de handlers de hooks
| Tipo | Descrição |
|---|---|
command |
Script de shell. JSON em stdin, códigos de saída para decisões. |
prompt |
Avaliação por LLM em um único turno. Retorna {ok, reason}. |
agent |
Subagente com múltiplos turnos e ferramentas de leitura. Até 50 turnos. |
6. Economia de tokens
Equipes de agentes usam aproximadamente 7× mais tokens do que sessões padrão quando os integrantes operam no modo de planejamento. Cada integrante mantém sua própria janela de contexto completa como uma instância separada do Claude.
Valor de referência
- Uso médio do Claude Code: ~US$ 6/desenvolvedor/dia
- Equipes de agentes: custo aproximadamente proporcional ao tamanho da equipe, além do valor de referência
7. Resumo da arquitetura
| Dimensão | Agent Teams do Claude Code |
|---|---|
| Base de coordenação | Arquivos simples (~/.claude/tasks/, ~/.claude/teams/) |
| Formato das tarefas | Um arquivo JSON por tarefa + .lock para assumir tarefas |
| Troca de mensagens | Arquivos JSON de caixa de entrada (adição ao final + consulta periódica) |
| Ciclo de vida dos agentes | Processos de CLI com autogerenciamento |
| Isolamento do trabalho | Diretório de trabalho compartilhado |
| Estratégia de merge | Nenhuma (os agentes editam os arquivos diretamente) |
| Novas tentativas/escalonamento | Manual (o líder decide, ou o usuário intervém) |
| Topologia | Líder + pares no mesmo nível, mensagens entre pares |
| Agendamento | Autoatribuição (os integrantes assumem a próxima tarefa) |
| Persistência do estado | Apenas arquivos; sem retomada de integrantes dentro do processo |
| Controles de qualidade | Hooks de shell (TeammateIdle, TaskCompleted) |
| Contabilização de tokens | Apenas por sessão, sem agregação entre agentes |
| Detecção de paralisação | Manual (o usuário percebe que um integrante parou) |
| Controle de concorrência | Implícito (tamanho da equipe = número de integrantes) |
| Modelo de dependências | blocks/blockedBy nos arquivos de tarefas |
Fontes
Documentação oficial
- Equipes de sessões do Claude Code: arquitetura
- Modo interativo — Lista de tarefas
- Equipes de agentes — Atribuir e assumir tarefas
- Equipes de agentes — Contexto e comunicação
- Equipes de agentes — Encerrar integrantes
- Equipes de agentes — Limpar a equipe
- Equipes de agentes — Permissões
- Equipes de agentes — Limitações
- Equipes de agentes — Boas práticas
- Hooks
- Custos — Custos de tokens das equipes de agentes
- Configurações
- Subagentes
Artefatos em disco (Claude Code v2.1.47)
Observados em /Users/tau/.claude/:
- Diretórios de equipes com arquivos
config.jsoneinboxes/{agent-name}.json - Diretórios de tarefas com
.lock,.highwatermarke arquivos JSON individuais de tarefas - Exemplo de mensagem de atribuição de tarefa de
team-leadparacp-agent, com registro de data e hora2026-02-18T02:37:16.890Z
Análise do binário
Binário do Claude Code v2.1.47. Funções internas identificadas por meio da análise de strings: getTeamName, getAgentName, getAgentId, isTeammate, isTeamLead, waitForTeammatesToBecomeIdle, getTeammateContext, setDynamicTeamContext, createTeammateContext. Campos de contexto do AsyncLocalStorage: agentId, agentName, teamName, parentSessionId, color, planModeRequired.