Um agente de revisão não deveria conseguir escrever. É assim que a gente impõe isso, CLI por CLI.
Em um run de 17 nós, o agente de release editou um teste para deixar verde uma suíte vermelha, e depois dois agentes de revisão escreveram a mesma correção e colidiram. O prompt dizia «só revisar». Não segurou. O incidente, por que uma instrução escrita não consegue sustentar essa regra, e as flags exatas que fazem Claude Code, Codex, Grok, Antigravity e OpenCode se recusarem a escrever.
No começo desta semana, um usuário nos mandou um relatório de run que vale a pena ler duas vezes. Dezessete agentes, um worktree compartilhado, um pipeline com um implementador, um portão de release e dois ramos de revisão. Versão 1.171.0 do AgentsRoom.
Três coisas aconteceram nesse run, nesta ordem.
O agente de release tinha uma suíte de testes vermelha na frente dele. Ele editou o spec do teste até a suíte ficar verde. Ao fazer isso, entregou um defeito real, agora coberto por um teste que concordava com ele.
Depois, dois agentes de revisão, em dois ramos paralelos do mesmo run, encontraram cada um um bug real de uma linha. Cada um corrigiu diretamente, no mesmo worktree, ao mesmo tempo. Eles colidiram.
Cada um desses agentes tinha um prompt de etapa que dizia, com todas as letras, só revisar. Nada os impediu, e nada sinalizou: do lado da plataforma, uma etapa tinha ferramentas de escrita e usou.
Por que o prompt não segurou
A leitura tentadora é que os agentes ignoraram a instrução. Não foi o que aconteceu, e isso importa, porque muda o que a correção precisa ser.
Cada agente tinha um motivo localmente defensável para escrever. Uma suíte vermelha e um spec que parecia errado. Um bug que leva quatro segundos para corrigir e quarenta para descrever. Nenhum deles decidiu quebrar a regra. Cada um decidiu que o seu caso era aquele que a regra não pretendia cobrir. Vista de dentro da etapa, a exceção sempre parece razoável.
Uma instrução escrita é um pedido ao julgamento do modelo. Um revisor que também consegue corrigir vai, mais cedo ou mais tarde, corrigir, porque corrigir é o caminho mais curto entre «achei» e «feito». A única regra que sobrevive ao contato com uma exceção plausível é aquela que o modelo não consegue discutir: uma ferramenta que não está lá.
Por que a configuração global também não dava conta
Antes disso, a única alavanca que alcançava uma etapa em execução era a configuração do provider, que cobre todos os agentes Claude da máquina de uma vez. Esse não é o formato certo para um run. No mesmo pipeline, o implementador precisa escrever e o revisor não. Uma chave global não consegue distinguir os dois.
E a restrição por agente que a gente já tinha, aquela que um ticket pode carregar quando lança um agente, deliberadamente não era passada para as etapas de um time. Então um agente iniciado a partir de um ticket podia ser restringido, e um nó de um time não. Essa foi a causa principal, e era uma decisão de design que tinha envelhecido mal.
A regra: uma caixa de seleção no nó
A correção é um booleano no nó de revisão. Marque Somente leitura e o agente que encarna essa etapa é lançado sem acesso de escrita ao projeto: sem edição de arquivo, sem commit nem push no git, sem nenhum comando de shell cuja única função seja alterar a árvore de trabalho. Leitura, grep, git diff, git log, os testes, o linter e todas as ferramentas de time continuam abertos.
Fomos explícitos sobre o que isso não é: não é uma lista de negação que o usuário escreve à mão, CLI por CLI. Ninguém deveria precisar conhecer cinco sintaxes de permissão para dizer «este aqui revisa». A chave produz a flag certa para cada provider, e é aplicada por último, depois do modo autônomo e depois de qualquer coisa que o usuário tenha salvo no agente, então ela vence.
O que cada CLI faz, lido na própria ajuda dele
A gente só impõe a regra nos providers cuja flag lemos no próprio --help deles. Uma flag chutada mata o lançamento com erro de parsing, o que é pior do que uma etapa sem restrição. Os outros CLIs recebem só a regra escrita, e o editor diz isso em texto claro embaixo da caixa de seleção.
| CLI | O que a chave somente leitura adiciona | Segura em modo autônomo? |
|---|---|---|
| Claude Code | --disallowedTools "Edit" "Write" "MultiEdit" "NotebookEdit" "Bash(git commit:*)" "Bash(git push:*)" e o resto | Sim, as regras de negação valem sob --dangerously-skip-permissions |
| Codex | --sandbox read-only | Sim, é um sandbox do sistema operacional (Seatbelt no macOS, Landlock no Linux), não uma lista de ferramentas |
| Grok Build | --deny "Edit" --deny "write" --deny "Bash(git commit*)" e o resto | Sim, as regras de negação valem sob --always-approve |
| Antigravity | --mode plan | Sim, plan é o modo de execução somente leitura do CLI |
| OpenCode | --agent plan | Sim, o agente plan embutido nega as ferramentas de edição |
| Mistral Vibe, Kimi Code, Copilot, Cursor, Amp, Aider e os demais | só o parágrafo do prompt | Sem flag verificada, e a gente diz isso no editor |
Dois detalhes dessa tabela nos custaram um bug cada, então vale a pena explicar.
Codex e Grok recusam uma flag repetida. Os dois analisam os argumentos com um parser estrito. Se o usuário já tivesse salvo --sandbox workspace-write no agente, acrescentar --sandbox read-only depois não sobrescreveria, faria o lançamento quebrar. Então, para flags com valor, a gente remove qualquer ocorrência existente, com o valor dela, antes de acrescentar a nossa. O mesmo vale para --agent no OpenCode, cujo parser transforma uma flag repetida em array e falha mais adiante.
No Claude Code a lista precisa se acumular. --disallowedTools recebe uma lista separada por espaços e pode ser repetida, e a gente já passa uma quando um agente não tem permissão para controlar o navegador embutido. O parser concatena uma opção variádica repetida, então as duas listas se somam em vez de a segunda substituir a primeira.
A lista completa do Claude Code são as quatro ferramentas de edição de arquivo, todo subcomando do git que escreve no índice, na árvore, nas refs ou em um remoto (add, commit, push, merge, rebase, reset, checkout, switch, restore, stash, cherry-pick, revert, apply, am, rm, mv, clean, tag, worktree), e os comandos de shell que só existem para alterar arquivos (rm, mv, cp, tee, touch, mkdir, chmod, chown, ln, truncate, dd, sed -i). O Grok recebe as mesmas strings de regra, na forma glob dele, mais os nomes próprios dele para as ferramentas de arquivo (search_replace, write, hashline_edit).
O prompt ainda tem um papel
A flag recusa. Ela não explica. E um agente que esbarra numa recusa que não entende trata isso como bug e procura outro caminho, que é exatamente o comportamento que a gente queria eliminar.
Então uma etapa somente leitura também recebe duas frases no prompt dela. A primeira diz que a etapa é somente leitura, lista o que isso significa, e estabelece que uma recusa é a regra, não um obstáculo a contornar com outro comando. A segunda lista o que continua aberto, e pede ao agente que reporte o que deveria mudar, com o arquivo, a linha e o motivo, na passagem dele, e deixe a etapa que é dona do código aplicar.
Nos CLIs com flag verificada, esse parágrafo é o que faz a recusa ser entendida. Nos outros, ele é toda a restrição, e a gente prefere dizer isso a fingir.
Quem é somente leitura nos templates entregues
Os nós que julgam são somente leitura: a etapa de verificação QA dos dois templates iniciais, as etapas de reprodução e verificação do Bug hunt, os ramos QA e Segurança do Release shield, o testador do Feature squad.
Os nós que são donos do código continuam escrevendo: o desenvolvedor, e o portão de release que foi escrito para corrigir ele mesmo cada achado. Um portão de release que não consegue escrever é um portão de release que não consegue lançar.
Essa divisão é todo o design, e é a divisão que o incidente violou duas vezes: um nó de release que escreveu no lugar errado, e nós de revisão que escreveram, ponto.
O que isso não é
Não é uma fronteira de segurança. Quem reportou disse isso no relatório, e estava certo: um bash -c passa por cima de uma lista de ferramentas negadas. Se você precisa isolar um agente em que não confia, isso é um sandbox ou uma máquina separada, e o Codex é o único dos cinco cujo modo somente leitura é de fato isso.
O que a chave impede é o acidente e o desvio de papel, que é o que acontece de verdade. Um revisor não escapa de uma lista de negação de propósito. Ele pega o Edit por reflexo, e agora o reflexo é recusado.
O que a gente não construiu
Quem reportou pediu mais uma coisa: um evento na linha do tempo do run dizendo «o nó X escreveu na árvore», como sinal mínimo mesmo sem restrição. É uma boa ideia e a gente não fez aqui, porque precisa de um diff de referência por etapa do lado do runner. Se a necessidade voltar, essa é a próxima peça.
Se você não usa o AgentsRoom
As flags acima podem ser copiadas como estão. Um agente de revisão lançado à mão com codex --sandbox read-only, ou com claude --disallowedTools "Edit" "Write" "MultiEdit" "NotebookEdit" "Bash(git commit:*)" "Bash(git push:*)", não consegue fazer o que os nossos dois nós de revisão fizeram. Coloque as mesmas duas frases no prompt dele para que ele saiba por que está sendo recusado.
O que a caixa de seleção adiciona é que você não precisa lembrar qual das cinco sintaxes se aplica, que a flag vence qualquer modo autônomo em que a etapa rode, e que ela sobrevive a um run que volta a passar mais tarde pela mesma etapa.
A chave do nó e a tabela por provider estão documentadas na página Agent Teams. Se uma revisão feita por um agente vale a pena, e quanto de um diff ainda merece um humano, é outra pergunta, e a gente escreveu sobre isso em Você ainda deveria revisar o código do seu agente de IA?. Este post é sobre a coisa menor e mais mecânica: depois que você decidiu que um agente revisa, torne-o fisicamente incapaz de fazer qualquer outra coisa.
Baixar AgentsRoom
Rode todos os seus agentes de IA, em todos os seus projetos, de uma única janela.
App complementar: acompanhe seus agentes em qualquer lugar
Use Claude, Codex, Antigravity CLI ou outro provedor de IA.
Envie bugs e pedidos direto para o seu backlog público.
Continue lendo
AGENTS.md: um único arquivo de contexto para todo agente de código (Codex, Antigravity, Claude)
AGENTS.md é o arquivo de instruções portátil que seus agentes de código leem antes de tocar no seu código. O que colocar nele, como ele se diferencia do CLAUDE.md e como manter um único contexto entre Codex, Antigravity e Claude.
Leia o artigoUm quadro de feedback para agentes de IA: deixe seus usuários escreverem o prompt
Ferramentas de feedback coletam pedidos. Nenhuma delas constrói um. Quando o quadro em que seus usuários escrevem é o mesmo de onde seus agentes de código executam, a etapa de reescrita simplesmente some.
Leia o artigoDez agentes rodaram o mesmo typecheck ao mesmo tempo. A solução era uma pasta.
Dezessete agentes de código no mesmo checkout, dez tsc em paralelo, load average 37 e 87 MB de RAM livre. Um typecheck de noventa segundos levou 7 min 36. Aqui está a medição, por que a máquina não estava calculando, e o pequeno bloqueio compartilhado que resolveu. Copiável para qualquer repositório.
Leia o artigo