Pular para o conteúdo

Ciclo de vida do despacho de agentes

Um despacho é uma execução de um agente, em uma conversa, em um adaptador. Tudo nele acontece no cc_server: o cliente envia uma mensagem e depois observa os eventos chegando em fluxo. Não existe caminho de despacho em nenhum cliente.

Os agentes são despertados por seis motivos, que a execução carrega como seu contexto de despertar para que o agente saiba por que está acordado:

Motivo do despertar Gatilho
userMessage Alguém enviou uma mensagem em um espaço, ou mencionou o agente
assignment Um ticket foi atribuído ao agente
pipelineStep Uma etapa de pipeline o despachou
childCompleted Um ticket filho foi concluído
followUp Um heartbeat de acompanhamento agendado
recovery O caminho de recuperação redespachou após uma falha

O contexto de despertar carrega os ids que acompanham o motivo — ticket, espaço, mensagem, execução de pipeline — e eles são injetados no ambiente e no prompt do agente.

O prompt é montado em camadas, cada uma delas uma seção rotulada:

  • Identidade — o id, o nome e o id do espaço de trabalho do próprio agente, com uma instrução explícita para passar exatamente esses UUIDs às ferramentas com escopo de espaço de trabalho. O espaço de trabalho é intrínseco ao agente, então está sempre presente.
  • Catálogo de ferramentas e protocolos de recursos, depois o layout do espaço de trabalho.
  • Substituição do prompt de sistema, se o agente tiver uma, depois a persona (parametrizada pelo papel) e o briefing da equipe.
  • Skills — os nomes atribuídos ao agente.
  • Contrato de execução e procedimento do modo atual.
  • Contexto de despertar e contexto de menção: quem convocou o agente e a lista de participantes ao redor dele.
  • Bloco do modo — gerado a partir do perfil de capacidades do modo e da sua lista materializada de ferramentas, de modo que um prompt nunca consiga citar uma ferramenta que a execução de fato não tem.
  • Contexto de memória — fatos recuperados para a tarefa.
  • Contexto de conversa — histórico recente do espaço, limitado a 50.000 caracteres de janela literal, independentemente do tamanho de contexto configurado para o agente. O histórico mais antigo não é descartado: o agente o recupera sob demanda com get_messages, e mensagens mais antigas semanticamente relevantes ainda aparecem.

Os comandos se dividem em dois lugares. /todo e /compact são interceptados no composer e, de propósito, nunca são persistidos como mensagens nem enviados ao agente — persistir /compact empurraria o corte de compactação uma rodada para trás e poluiria a transcrição. /plan é tratado nos dois: o composer alterna o modo do espaço, e é isso que faz a superfície de ferramentas, a predefinição de guardrails e o prompt concordarem nesta rodada e em todas as seguintes. /goal, /loop e /skill:<name> são tratados dentro da própria execução e somente no harness integrado — /goal e /loop iniciam trabalho autônomo com um orçamento de custo, e um nome prefixado com skill: é procurado como uma skill cujo corpo do SKILL.md se torna a diretiva da rodada. É o namespace que mantém os dois vocabulários separados: resolver um nome puro contra as skills fazia com que uma skill chamada plan ou compact fosse permanentemente ofuscada pela embutida. Um nome puro que não seja embutido ainda é resolvido, para mensagens escritas antes de o namespace existir. Um nome não reconhecido simplesmente passa adiante como texto simples.

Antes de qualquer coisa ser executada, a conversa recebe sua própria raiz de trabalho, com uma worktree isolada com copy-on-write por repositório abaixo dela. Por padrão, isso abrange todos os repositórios vinculados ao espaço de trabalho; um espaço de PR — ou um espaço criado com uma seleção explícita — provisiona apenas os que estão na lista de permitidos, e uma conversa de revisão de PR fixa seu único repositório no head ref da pull request, enquanto os demais ficam no branch padrão. O checkout de origem nunca é alterado, e todo o diretório da conversa é liberado quando o espaço é excluído.

Copy-on-write é a única implementação onde quer que o rift seja distribuído, com apoio do nativo incluído no pacote. Um sistema de arquivos que não consegue fazer reflink — ou um diretório de dados em um volume diferente do repositório — faz o provisionamento falhar, em vez de recorrer a uma alternativa. No Windows, o backend é o git worktree, onde não há backend de copy-on-write a ser construído, e isso não é uma degradação silenciosa em outros hosts. Um rift ausente em uma plataforma que o distribui é uma instalação quebrada — o servidor se recusa a iniciar em vez de recorrer silenciosamente a uma alternativa, porque uma alternativa silenciosa esconde a quebra atrás de um caminho mais lento para sempre.

Duas identidades são resolvidas por execução, antes de qualquer processo ser iniciado.

Autoria no Git. Os commits feitos por um agente são atribuídos ao próprio agente — <Name> (agent) <agentId@agents.control-center.local> tanto em GIT_AUTHOR_* quanto em GIT_COMMITTER_* — nunca se passando por um humano. A parte local é o UUID do agente, não seu slug de nome. A pessoa que fez a solicitação é creditada com um trailer Co-Authored-By:, carregado no ambiente e instruído no prompt de sistema. Uma identidade definida explicitamente por quem chama sempre prevalece sobre as duas.

Identidade na forge. A credencial de GitHub da execução é sempre a do broker — um token de instalação do App com escopo de repositório, ou seu substituto PAT do ambiente — nunca o token armazenado do próprio membro solicitante. O actingUserId limita o substituto PAT, para que um membro que não seja o proprietário do servidor não herde o alcance do servidor; ele não sobrepõe um token pessoal ao ambiente do agente.

Credenciais de provedores de modelos são resolvidas em uma ordem fixa, e a ordem importa:

  1. uma substituição de ambiente por adaptador,
  2. o ambiente de quem chama,
  3. o armazenamento de credenciais do servidor (renovando um token OAuth se estiver perto de expirar),
  4. o ambiente do processo.

Como a substituição por adaptador vem primeiro, ela supera silenciosamente uma conta de provedor conectada no app. Se uma execução está cobrando na conta errada, essa substituição é o primeiro lugar a verificar. As credenciais de provedor são globais do host — compartilhadas entre todos os espaços de trabalho da instalação.

O token do GitHub da execução vem do broker de credenciais: um token somente leitura, com escopo do repositório da worktree. Um push passa pelo gateway de execuções de agentes, que pergunta à regra Fazer push para um remoto antes de encaminhá-lo, e nenhuma chave de tickets é injetada. Consulte Sandbox e segurança.

A execução é iniciada com sua worktree como diretório de trabalho e — no caso do Claude Code — com uma configuração MCP gerada, para que o agente alcance a superfície de ferramentas do Control Center. ACP e o bash do harness recebem um ambiente saneado; o Claude Code pelo NoSandboxAdapter herda o ambiente do host.

A execução transmite de volta uma sequência tipada de eventos, que o processador de stream persiste como deltas de mensagem, dobra em segmentos de transcrição e transforma em eventos de mensagens:

Evento O que carrega
thinking Saída de raciocínio, renderizada em linha
text Saída visível
toolCall Uma invocação de ferramenta, com seu id e argumentos estruturados
toolResult O resultado correspondente, sinalizado quando deu erro ou é um stream parcial
usage Contagens de tokens e custo de uma janela de medição
error Um erro, com o código estruturado do adaptador quando ele reportou um
sandboxViolation O sistema operacional negou uma syscall. Só é emitido onde um sandbox realmente envolve o processo — veja a nota acima
debug Diagnósticos de runtime (marcadores de inicialização, decisões dos guardrails, ajustes de contrato)
done A execução terminou

De propósito, não há teto de rodadas em lugar nenhum. Um número fixo de iterações mata trabalho longo legítimo (migrações, limpeza de fan-out) e não pega nada que as proteções abaixo não peguem antes. Uma execução termina quando:

  • o modelo para por conta própria;
  • uma pessoa a interrompe, ou assume o controle da conversa (o que pausa o harness integrado no próximo limite de rodada limpo — uma execução do Claude Code, que não tem um limite seguro, é interrompida em vez disso);
  • o watchdog de silêncio dispara. Sem saída pelo tempo limite e a sessão é encerrada com uma falha silentRun. O padrão é 15 minutos, caindo para 10 nos modos predominantemente de leitura (revisão e plano); um agente pode substituir esse valor entre 1 e 240 minutos. O watchdog é armado quando um processo filho reporta seu PID, então ele cobre a CLI do Claude Code — não o harness integrado, que não gera nenhum processo;
  • um limite de custo entra em vigor — mas somente para comandos autônomos.

A proteção contra loop infinito não é um terminador: três chamadas de ferramenta idênticas seguidas e o loop orienta o agente a mudar de abordagem.

Juntando tudo, uma rodada interativa comum no harness integrado não tem teto de rodadas, nem limite de custo, nem watchdog de silêncio. Ela termina quando o modelo para ou quando você a interrompe. É uma troca deliberada — as alternativas matam todo trabalho longo legítimo — mas significa mesmo que uma execução interativa sem supervisão não é limitada por nada além do próprio julgamento do modelo.

No meio da execução, uma mensagem enviada a um agente em execução é enfileirada como orientação e consumida no próximo limite de rodada, para que você possa ajustar uma execução sem matá-la. Orientação, pausa, subagentes e o contrato de conclusão são recursos do harness integrado; o Claude Code não tem nenhum deles.

Todo despacho grava um AgentRunLog: horário de início e fim, resumo, contagens de tokens e custo estimado (incluindo o custo consolidado dos subagentes), adaptador e modelo, id do processo e caminho do log, a conversa e qualquer ticket ou execução de pipeline a que pertença, além de dois campos de classificação que carregam a maior parte da verdade.

  • Status é grosseiro: pending, running, completed, error.
  • Vivacidade é a leitura mais fina: alive, productive, completed, blocked, empty, looping, failed, stalled, dead.
  • Família de erros agrupa as falhas de forma útil: transientUpstream, sandboxInfrastructure, budgetExceeded, processLost, silentRun, unknown.

Fechar a execução publica AgentRunCompleted, e muita coisa depende disso: a consolidação de custos do pipeline, a retomada de uma etapa de pipeline que esperava a execução, a conclusão do ticket de base, o mapeamento de uma orquestração para um estado terminal, a decisão de continuar ou parar do supervisor de metas, o papel de verificador e a avaliação de orçamento pós-execução. A lista de presença é atualizada separadamente, observando os logs de execução recentes em vez do evento. A notificação “agente finalizado” não está nessa lista: o evento dispara quando o stream do processo termina, antes de a resposta ser gravada, então a notificação é o MessageReceived da rodada, publicado assim que a mensagem é persistida.

A aplicação de orçamento é uma reação, não uma barreira. Quando uma execução é concluída, o avaliador compara os gastos do agente no mês até a data com seu teto efetivo (uma política de orçamento vinculada, se houver; caso contrário, o próprio valor mensal do agente; zero significa ilimitado). Cruzar o limite suave registra um incidente de aviso; esgotar o orçamento registra um incidente grave e muda o status de ciclo de vida do agente para paused no organograma. O despacho ainda aceita trabalho desse agente. Um gatilho de pipeline BudgetThresholdCrossed pode iniciar trabalho de acompanhamento a partir do mesmo evento.

Todo log de execução pode carregar uma linhagem de novas tentativas — um id de execução pai, um contador de tentativas e um resumo de continuação. A árvore de execuções da conversa exibe o número da tentativa quando ele não é zero. Um “tentar de novo” no chat é um novo despacho, com um log de execução novo.