Seu pipeline de agentes precisa de estados explícitos, não só de prompts
Um agente implementa a correção, outro revisa e um terceiro abre o app no navegador para percorrer o fluxo afetado. Parece uma automação bem organizada, até alguém perguntar qual commit passou por cada etapa.
O implementador escreveu "concluído" no chat e publicou uma branch. Enquanto o revisor lia o resumo, entrou mais um commit. O agente de QA abriu a branch que já estava no ambiente e encontrou tudo verde. No fim, implementação, revisão e teste podem ter usado três versões diferentes do código.
Nenhum prompt resolve essa confusão sozinho. O prompt explica o que uma etapa deve fazer; o protocolo entre etapas registra o artefato recebido, o resultado produzido e a condição que permite avançar.
Quando colocamos o segundo agente no fluxo, uma tarefa vira um pipeline e estado explícito deixa de ser detalhe de infraestrutura.
O segundo agente muda a natureza do trabalho
Uma execução isolada pode receber contexto, alterar arquivos e devolver uma resposta. Se ela falhar, uma pessoa olha o resultado e decide o que fazer. Já uma cadeia com implementação, revisão e QA precisa coordenar espera, trabalho parcial, interrupção e retomada sem depender de alguém reinterpretar a conversa inteira.
O Cobalt 1.0 tornou esse desenho bem visível ao separar tarefas de implementação, revisão independente e testes no navegador. Cada tarefa mantém seu ambiente e histórico, enquanto o handoff de código usa branch, commit ou pull request. Os workers publicam resultados, inclusive falhas, e o fluxo pode parar em pontos definidos para uma decisão humana.
Não é necessário adotar essa ferramenta para aproveitar a ideia. Um time pequeno consegue aplicar o mesmo princípio em um script, uma GitHub Action ou um serviço interno. A regra é simples: uma etapa só começa quando consegue localizar e validar a saída exata da etapa anterior.
"O revisor recebeu a mensagem" não é uma condição de transição. "O revisor recebeu o commit c94bd17, derivado da base 8f31c2a, com testes unitários e typecheck aprovados" já pode ser verificado.
Estado precisa comandar comportamento
O painel pode exibir vinte etiquetas e ainda assim não ter uma máquina de estados. Os nomes só ajudam quando cada um impõe regras ao runtime.
Eu começaria com poucos estados:
| Estado | O que significa | Comportamento esperado |
|---|---|---|
queued | há uma entrada válida aguardando execução | reservar a tentativa e iniciar uma única vez |
running | um worker assumiu a etapa | emitir atividade e respeitar o orçamento de tempo |
blocked | falta permissão, dependência ou decisão | parar e encaminhar o bloqueio; não repetir automaticamente |
failed | a etapa terminou com um resultado reprovado | registrar a classe da falha e devolver ao responsável |
ready_for_review | existe uma saída identificada para revisão | liberar somente a etapa de review |
approved | os checks exigidos passaram sobre uma referência exata | liberar a próxima etapa prevista para aquela referência |
As transições recusadas mostram se esses estados governam o processo. failed não pode escorregar para o QA porque algum campo do painel ficou verde. approved sem um hash deixa de ser aprovação e vira opinião. Se aparecer um commit novo, a revisão anterior continua registrada, mas não vale para a nova referência.
Também vale separar estágio de estado. review é uma fase do fluxo; running, blocked e approved descrevem a situação de uma tentativa naquela fase. Misturar os dois conceitos cria combinações difíceis de operar, como um genérico review_done que não informa se houve aprovação, reprovação ou interrupção.
O handoff mínimo cabe em um arquivo pequeno
Não passe a transcrição do chat para o próximo agente e espere que ele descubra o que importa. Passe um registro curto, estruturado e apontando para os artefatos completos.
task_id: checkout-form-42
attempt: 2
stage: implement
status: ready_for_review
input_ref: 8f31c2a
output_ref: c94bd17
checks:
- name: unit
result: passed
- name: typecheck
result: passed
blocked_by: null
next_allowed: review
Esse YAML não torna o processo confiável por conta própria. O próximo worker precisa rejeitar o handoff quando falta uma referência, quando o estado não permite a etapa pedida ou quando um check obrigatório não aparece. O coordenador também precisa impedir duas execuções com o mesmo task_id e attempt.
O registro pode incluir horário, executor, riscos restantes e um endereço para logs detalhados. Evite colocar secrets, tokens ou a conversa completa ali. Handoff é uma interface entre etapas, não um depósito para tudo o que aconteceu na sessão.
O revisor deve validar o endereço antes do código
Ao receber output_ref: c94bd17, o revisor busca esse commit e confirma que ele deriva da base esperada. Só depois abre o diff e roda os checks próprios da revisão. Se a branch avançar durante o processo, nada muda na referência já recebida.
Uma aprovação também deve carregar o commit revisado. O browser QA consome esse hash, prepara o app a partir dele e registra qual jornada executou. "Testei a branch" é ambíguo demais para servir de evidência porque branches se movem.
Esse cuidado evita uma falha comum em automações rápidas: cada agente faz seu trabalho corretamente sobre uma entrada diferente. O resultado local de cada etapa parece bom, mas a cadeia nunca validou um artefato único de ponta a ponta.
Um commit novo depois da revisão abre uma nova tentativa ou devolve o fluxo à fila. Não há motivo para apagar a aprovação anterior; ela continua útil para auditoria. O sistema apenas deixa de tratá-la como autorização para o código mais recente.
Cada tipo de falha pede uma resposta diferente
Retry automático é ótimo para uma queda transitória de rede e péssimo para uma operação que pode ter produzido efeito parcial. Antes de repetir, o coordenador precisa saber qual limite venceu, se o worker chegou a agir e se a operação tolera duplicidade.
O changelog do Cline SDK traz um caso concreto. Na versão 0.0.82, foi corrigida uma situação em que o timeout de 60 segundos de um servidor inacessível ultrapassava o teto de 30 segundos do hub e derrubava a sessão. Em uma cadeia, manda o menor orçamento de tempo. A etapa interna não pode prometer que esperará mais do que seu chamador suporta.
As classes de falha pedem respostas diferentes:
blockedespera uma permissão, dependência ou decisão humana;- um check reprovado volta ao implementador com o achado e a referência testada;
- um timeout anterior ao início pode permitir nova tentativa;
- um timeout com efeito desconhecido exige consulta ao recibo da operação ou uma chave de idempotência antes de repetir;
- uma entrada obsoleta invalida a tentativa e recomeça a partir da referência atual.
O teto de tentativas também deve ser explícito. Repetir cinco vezes o mesmo bloqueio não aumenta a chance de sucesso; só adia a pessoa que precisa decidir. Quando a mesma classe reaparece, o fluxo deve parar, chamar alguém e preservar o que já foi produzido.
Interrupção e retomada merecem o mesmo cuidado. A versão 0.0.72 do Cline SDK passou a preservar prompts enfileirados durante interrupções e a tornar a parada consistente entre hosts. Preservar a fila, porém, não autoriza reexecutar cegamente. Cada item retomado ainda precisa confirmar se o campo input_ref continua válido.
Log durável precisa ter limite e propósito
Uma máquina de estados sem histórico ajuda pouco quando algo trava às três da manhã. Cada transição deveria deixar um evento com task_id, tentativa, estado anterior, novo estado, ator, referências e horário. O evento responde o que avançou e por quê; detalhes extensos podem ficar em um artefato separado, com acesso e retenção próprios.
Retenção infinita parece cômoda até snapshots, saídas de ferramentas e mensagens começarem a se acumular. O Cline SDK limitou seu event log durável a 64 MiB na versão 0.0.79 depois de snapshots completos crescerem muito mais. Copiar esse número para qualquer runtime não faria sentido. Vale definir limite, compactação e descarte antes de depender do log para retomar sessões.
Um log gigantesco também aumenta a chance de guardar segredos e dados desnecessários. Para operação diária, um recibo pequeno costuma bastar. Quando a etapa falha, ele aponta para os detalhes protegidos em vez de copiá-los para todos os agentes seguintes.
Validação integrada ajuda, mas não decide sozinha
O Xcode 27 aproxima o agente de testes, experimentos em Playgrounds, previews e interação com simuladores pelo Device Hub. Esse tipo de integração encurta o ciclo entre mudar e observar. Também aumenta a importância de registrar qual build e qual estado do ambiente produziram a observação.
O agente que implementa pode rodar testes e encontrar boa parte dos próprios erros. Ainda assim, ele pode testar a mesma suposição errada que orientou a mudança. Para uma correção visual pequena, talvez o custo de uma revisão independente não compense. Em autenticação, cobrança ou migração de dados, separar produção e aprovação costuma ser um custo bem mais fácil de defender.
A decisão pode variar conforme o impacto. O contrato não precisa obrigar três agentes em todo PR; precisa deixar claro quando a checagem do próprio agente encerra a etapa e quando outra identidade deve revisar o mesmo commit.
Um piloto que cabe no próximo PR
Escolha uma correção pequena de frontend e salve o estado em um arquivo versionado ou registro durável. Rode a sequência implement → review → browser_qa → human_merge uma vez antes de adicionar paralelismo ou mais papéis.
Durante o piloto, force situações que o happy path esconderia:
- faça um teste reprovar e confirme que o fluxo volta à implementação;
- provoque um timeout e verifique se a tentativa seguinte consegue distinguir "não começou" de "resultado desconhecido";
- adicione um commit depois da aprovação e confirme que revisão e QA antigos deixam de autorizar o merge;
- remova uma permissão e veja se o estado termina em
blocked, sem uma sequência inútil de retries.
No fim, tente responder sem abrir o chat:
- qual commit cada etapa recebeu e qual devolveu?
- quais checks rodaram sobre cada referência?
- por que o fluxo avançou, parou ou voltou?
- quem pode liberar a próxima transição?
Se essas respostas estiverem no registro, o time já tem uma base útil. Depois vale medir quantas reexecuções foram evitadas, quanto tempo os bloqueios ficaram sem dono e quais eventos realmente ajudaram na investigação. A máquina de estados pode crescer quando surgir um caso operacional que justifique o novo estado.
Automatizar vários agentes sem esse contrato produz uma conversa movimentada e um histórico difícil de retomar. Comece com referências imutáveis, meia dúzia de estados e transições que o runtime saiba negar. Quando uma etapa falhar pela metade, o time poderá localizar o último commit válido, entender por que o fluxo parou e retomar sem reler a conversa.