Muitos Agentes, Uma Arquitetura: O Que Acontece Quando Dois Deles Mudam o Mesmo Sistema

Três agentes, três pull requests, três opiniões razoáveis sobre onde a lógica de retry deveria ficar.

Um coloca o retry no cliente HTTP. Um embrulha o handler. Um adiciona uma queue e a esvazia. Leia qualquer uma das três sozinha e você aprovaria. Leia as três na mesma tarde e você percebe que o sistema agora tenta de novo em três lugares, com três políticas de backoff diferentes, e ninguém decidiu isso.

Essa é a forma do problema assim que mais de um agente trabalha numa base de código ao mesmo tempo. Cada agente está localmente correto. A incoerência é global, e ela só fica visível para quem revisa por último.

Por que o arquivo de regras não arbitra isso

A resposta padrão é um arquivo de regras: CLAUDE.md, AGENTS.md, .cursor/rules. Já escrevemos sobre por que esses arquivos ficam desatualizados, e ficar desatualizado é o menor dos problemas aqui. O maior é que um arquivo de regras não consegue arbitrar.

Ele é prosa. Dois agentes que recebem o mesmo parágrafo vão produzir duas leituras diferentes dele, ambas defensáveis, e não existe nenhum ponto em que essas leituras se encontrem. Ele vive por repositório, então uma regra sobre uma fronteira de serviço fica num repo enquanto o serviço do outro lado da fronteira fica em outro. E ele não tem estado: não tem como saber que outro agente propôs algo quarenta minutos atrás, porque ele é um arquivo, e arquivos não sabem de nada.

O que você precisa para arbitrar não é prosa melhor. É uma coisa compartilhada que os dois agentes leem e escrevem, que consegue guardar uma decisão, e que consegue perceber uma discordância.

O que um modelo dá e um documento não dá

Um modelo de arquitetura são elementos e relações que você pode consultar. Sistemas, containers, components, as arestas entre eles, e penduradas nessas arestas as coisas que fazem de um design um design: a decisão que tornou uma fronteira deliberada, o owner a ser avisado, o contrato do qual um consumer depende.

Disso saem três coisas, e cada uma delas é um mecanismo, não uma intenção.

Todo agente pode ler os mesmos bytes. A action generate-context escreve um archyl.txt a partir do modelo, em markdown por padrão, opcionalmente com commit automático no repositório. Nove agentes lendo um arquivo gerado é uma situação diferente de nove agentes parafraseando cada um um documento em prosa. Não é esperto. É só compartilhado.

A discordância pode ser pega na entrada. A action conformance-check roda regras de arquitetura contra os arquivos que uma pull request mudou, anota as violações inline, e reprova o check na severidade que você escolher. fail-on aceita error, warning ou none. Se "retries ficam no cliente" for uma regra em vez de uma frase, os dois agentes que os colocaram em outro lugar descobrem na CI em vez de na revisão.

Uma decisão tem onde morar. ADRs se prendem aos elementos C4 que elas restringem. O motivo pelo qual a queue existe está na queue, não numa thread do Slack de março que agente nenhum jamais viu.

A parte que erramos

Aqui é onde isso deixou de ser um post de blog sobre uma ideia bonita.

Agentes não mudam o modelo diretamente. Eles abrem um Change Request: uma proposta, revisada e mergeada por uma pessoa. Quando um Change Request é criado, o archyl registra a versão do modelo contra a qual ele foi construído. Quando ele é mergeado, a versão é incrementada. Essa é exatamente a maquinaria que você iria querer para esse problema.

Nós nunca tínhamos ligado as duas coisas.

A versão base era escrita na criação e lida de volta em lugar nenhum. O que significava que esta sequência funcionava, silenciosa e completamente:

  1. O agente A e o agente B leem o modelo. Os dois veem a versão 7.
  2. A abre um Change Request. B abre um Change Request. Os dois são baseados na versão 7.
  3. O Change Request de A é mergeado. O modelo está agora na versão 8.
  4. O Change Request de B é mergeado. Ele foi escrito contra um modelo que não existe mais.

Nenhum aviso, nenhum conflito, nenhuma nota no histórico. O segundo conjunto de mudanças cai em cima do primeiro, e se eles se contradizem, a contradição agora é a arquitetura documentada. Isso é um merge com a detecção de conflitos removida, e é exatamente a falha que toda a história dos "muitos agentes" deveria evitar.

Então corrigimos. Mergear um Change Request cuja versão base não bate mais com o projeto agora falha com um 409 Conflict e uma mensagem que nomeia as duas versões:

architecture request is based on version 7 but the model is now at version 9;
rebase the request and merge again

Só que o que torna isso seguro não é a comparação. Dois merges chegando no mesmo instante passariam os dois por uma comparação e os dois seguiriam adiante. O que fecha essa brecha é tornar o próprio incremento de versão condicional: o merge avança o modelo apenas se o modelo ainda estiver na versão contra a qual o Change Request foi construído. Se ele já mudou, o merge não encontra nada para avançar, tudo faz rollback, e nenhuma mudança é aplicada. A comparação anterior existe só para que a mensagem de erro consiga dizer o quanto você está atrasado.

409 em vez de 400 importa mais do que parece. Um agente que tenta de novo em cima de um 400 fica em loop para sempre, porque uma requisição malformada continua malformada. 409 diz o contrário: o que você mandou estava certo e deixou de ser aplicável. Busque o modelo atual e tente de novo.

O que isso ainda não faz

Quatro limites, todos verificáveis.

Nenhum agente mergeia nada. Não existe tool MCP que mergeie um Change Request. Agentes propõem; uma pessoa revisa e mergeia. Essa é uma fronteira deliberada e não temos planos de removê-la, mas quer dizer que o loop não é totalmente automático e você não deveria projetar como se fosse.

A detecção de conflitos é grossa. A versão é por projeto, não por elemento. Dois agentes mexendo em cantos genuinamente sem relação do mesmo projeto vão colidir na versão do mesmo jeito. Essa é a direção segura para se errar, e é errado.

A recuperação de contexto é lexical. find_relevant_context pontua elementos por sobreposição de palavras em nomes, descrições, tags e caminhos. Não há embedding e não há expansão por sinônimos, então uma tarefa sobre "checkout" não vai trazer à tona um component chamado OrderProcessor. A vantagem é real (determinístico, sem custo de tokens, sem código enviado para lugar nenhum), mas é correspondência, não compreensão.

Regras não se escrevem sozinhas. Tudo acima pressupõe que alguém expressou "retries ficam no cliente" como uma regra de conformidade. Um conjunto de regras vazio não pega nada, por mais agentes que estejam rodando.

O que fazer com isso esta semana

Você não precisa comprar nada para descobrir onde está.

Pegue a última semana em que seu time mergeou mais de uma pull request escrita por agente. Leia todas juntas em vez de em sequência. Pergunte se duas delas tomaram a mesma decisão de formas diferentes, e depois pergunte o que, no seu setup atual, teria avisado você.

Se a resposta for "o revisor percebeu", isso funciona até o dia em que o revisor estiver lendo nove.


Change Requests, regras de conformidade e o modelo C4 fazem parte do archyl. As GitHub Actions e os agent skills são open source. Leitura relacionada: por que seus agentes têm um arquivo de regras e não um modelo, como funcionam os Change Requests, e como o modelo é mantido honesto.