Un agente de revisión no debería poder escribir. Así lo imponemos, CLI por CLI.
En un run de 17 nodos, el agente de release editó un test para poner en verde una suite roja, y luego dos agentes de revisión escribieron la misma corrección y chocaron entre sí. El prompt decía «solo revisar». No aguantó. El incidente, por qué una instrucción escrita no puede sostener esa regla, y los flags exactos que hacen que Claude Code, Codex, Grok, Antigravity y OpenCode se nieguen a escribir.
A principios de esta semana, un usuario nos envió un informe de run que merece leerse dos veces. Diecisiete agentes, un worktree compartido, un pipeline con un implementador, una puerta de release y dos ramas de revisión. Versión 1.171.0 de AgentsRoom.
En ese run pasaron tres cosas, en este orden.
El agente de release tenía delante una suite de tests roja. Editó el spec del test hasta que la suite se puso en verde. Al hacerlo, entregó un defecto real, ahora cubierto por un test que le daba la razón.
Después, dos agentes de revisión, en dos ramas paralelas del mismo run, encontraron cada uno un bug real de una línea. Cada uno lo corrigió directamente, en el mismo worktree, al mismo tiempo. Chocaron.
Cada uno de esos agentes tenía un prompt de paso que decía, con todas las letras, solo revisar. Nada los detuvo, y nada lo señaló: desde el lado de la plataforma, un paso tenía herramientas de escritura y las usó.
Por qué el prompt no aguantó
La lectura tentadora es que los agentes ignoraron la instrucción. No es lo que pasó, y eso importa, porque cambia lo que tiene que ser la corrección.
Cada agente tenía una razón localmente defendible para escribir. Una suite roja y un spec que parecía equivocado. Un bug que tarda cuatro segundos en corregirse y cuarenta en describirse. Ninguno decidió romper la regla. Cada uno decidió que su caso era el que la regla no contemplaba. Vista desde dentro del paso, la excepción siempre parece razonable.
Una instrucción escrita es una petición al criterio del modelo. Un revisor que además puede corregir acabará, tarde o temprano, corrigiendo, porque corregir es el camino más corto entre «lo encontré» y «hecho». La única regla que sobrevive al contacto con una excepción plausible es la que el modelo no puede discutir: una herramienta que no está.
Por qué el ajuste global tampoco podía hacerlo
Antes de esto, la única palanca que llegaba a un paso en ejecución era la configuración del proveedor, que cubre de golpe a todos los agentes Claude de la máquina. Esa no es la forma correcta para un run. En el mismo pipeline, el implementador debe escribir y el revisor no. Un interruptor global no puede distinguirlos.
Y la restricción por agente que ya teníamos, la que un ticket puede llevar cuando lanza un agente, deliberadamente no se pasaba a los pasos de un equipo. Así que un agente lanzado desde un ticket podía restringirse, y un nodo de un equipo no. Esa fue la causa principal, y era una decisión de diseño que había envejecido mal.
La regla: una casilla en el nodo
La corrección es un booleano en el nodo de revisión. Marca Solo lectura y el agente que encarna ese paso se lanza sin acceso de escritura al proyecto: sin edición de archivos, sin commit ni push de git, sin ningún comando de shell cuyo único trabajo sea cambiar el árbol de trabajo. La lectura, grep, git diff, git log, los tests, el linter y todas las herramientas de equipo siguen abiertos.
Fuimos explícitos sobre lo que no es: no es una lista de denegación que el usuario escribe a mano, CLI por CLI. Nadie debería necesitar conocer cinco sintaxis de permisos para decir «este revisa». El interruptor produce el flag correcto para cada proveedor, y se aplica al final, después del modo autónomo y después de cualquier cosa que el usuario haya guardado en el agente, así que gana.
Qué hace cada CLI, leído en su propia ayuda
Solo imponemos la regla en los proveedores cuyo flag leímos en su propio --help. Un flag adivinado mata el lanzamiento con un error de parseo, lo que es peor que un paso sin restricción. Los demás CLI reciben solo la regla escrita, y el editor lo dice en texto claro debajo de la casilla.
| CLI | Qué añade el interruptor de solo lectura | ¿Aguanta en modo autónomo? |
|---|---|---|
| Claude Code | --disallowedTools "Edit" "Write" "MultiEdit" "NotebookEdit" "Bash(git commit:*)" "Bash(git push:*)" y el resto | Sí, las reglas de denegación se aplican bajo --dangerously-skip-permissions |
| Codex | --sandbox read-only | Sí, es un sandbox del sistema operativo (Seatbelt en macOS, Landlock en Linux), no una lista de herramientas |
| Grok Build | --deny "Edit" --deny "write" --deny "Bash(git commit*)" y el resto | Sí, las reglas de denegación se aplican bajo --always-approve |
| Antigravity | --mode plan | Sí, plan es el modo de ejecución de solo lectura del CLI |
| OpenCode | --agent plan | Sí, el agente plan integrado deniega las herramientas de edición |
| Mistral Vibe, Kimi Code, Copilot, Cursor, Amp, Aider y los demás | solo el párrafo del prompt | Sin flag verificado, y lo decimos en el editor |
Dos detalles de esa tabla nos costaron un bug cada uno, así que vale la pena explicarlos.
Codex y Grok rechazan un flag repetido. Ambos analizan sus argumentos con un parser estricto. Si el usuario ya había guardado --sandbox workspace-write en el agente, añadir --sandbox read-only detrás no lo sobrescribiría, haría fallar el lanzamiento. Así que, para los flags con valor, eliminamos cualquier ocurrencia existente, con su valor, antes de añadir la nuestra. Lo mismo para --agent en OpenCode, cuyo parser convierte un flag repetido en un array y falla más adelante.
En Claude Code la lista tiene que acumularse. --disallowedTools acepta una lista separada por espacios y puede repetirse, y ya pasamos una cuando un agente no tiene permiso para manejar el navegador integrado. El parser concatena una opción variádica repetida, así que las dos listas se suman en lugar de que la segunda sustituya a la primera.
La lista completa para Claude Code son las cuatro herramientas de edición de archivos, cada subcomando de git que escribe en el índice, el árbol, las refs o un remoto (add, commit, push, merge, rebase, reset, checkout, switch, restore, stash, cherry-pick, revert, apply, am, rm, mv, clean, tag, worktree), y los comandos de shell que solo existen para cambiar archivos (rm, mv, cp, tee, touch, mkdir, chmod, chown, ln, truncate, dd, sed -i). Grok toma las mismas cadenas de reglas, en su forma glob, más sus propios nombres para las herramientas de archivos (search_replace, write, hashline_edit).
El prompt sigue teniendo un trabajo
El flag rechaza. No explica. Y un agente que se topa con un rechazo que no entiende lo trata como un bug y busca otro camino, que es exactamente el comportamiento que queríamos eliminar.
Así que un paso de solo lectura recibe también dos frases en su prompt. La primera dice que el paso es de solo lectura, enumera lo que eso significa, y establece que un rechazo es la regla, no un obstáculo que rodear con otro comando. La segunda enumera lo que sigue abierto, y le pide al agente que reporte lo que debería cambiar, con el archivo, la línea y el motivo, en su entrega, y que deje que el paso que posee el código lo aplique.
En los CLI con un flag verificado, ese párrafo es lo que hace que el rechazo se entienda. En los demás, es toda la restricción, y preferimos decirlo antes que fingir.
Quién es de solo lectura en las plantillas incluidas
Los nodos que juzgan son de solo lectura: el paso de verificación QA de las dos plantillas de inicio, los pasos de reproducción y verificación de Bug hunt, las ramas QA y Seguridad de Release shield, el tester de Feature squad.
Los nodos que poseen el código siguen escribiendo: el desarrollador, y la puerta de release que está escrita para corregir ella misma cada hallazgo. Una puerta de release que no puede escribir es una puerta de release que no puede publicar.
Esa separación es todo el diseño, y es la separación que el incidente violó dos veces: un nodo de release que escribió en el lugar equivocado, y nodos de revisión que escribieron, sin más.
Lo que esto no es
No es una frontera de seguridad. Quien lo reportó lo dijo en su informe, y tenía razón: un bash -c se salta una lista de herramientas denegadas. Si necesitas aislar un agente en el que no confías, eso es un sandbox o una máquina separada, y Codex es el único de los cinco cuyo modo de solo lectura es realmente eso.
Lo que el interruptor detiene es el accidente y la deriva de rol, que es lo que pasa de verdad. Un revisor no se salta una lista de denegación a propósito. Agarra Edit por reflejo, y ahora el reflejo se rechaza.
Lo que no construimos
Quien lo reportó pidió una cosa más: un evento en la línea de tiempo del run que dijera «el nodo X escribió en el árbol», como señal mínima incluso sin restricción. Es una buena idea y no la hicimos aquí, porque necesita un diff de referencia por paso del lado del runner. Si la necesidad vuelve, esa es la siguiente pieza.
Si no usas AgentsRoom
Los flags de arriba se pueden copiar tal cual. Un agente de revisión lanzado a mano con codex --sandbox read-only, o con claude --disallowedTools "Edit" "Write" "MultiEdit" "NotebookEdit" "Bash(git commit:*)" "Bash(git push:*)", no puede hacer lo que hicieron nuestros dos nodos de revisión. Pon las mismas dos frases en su prompt para que sepa por qué se le está rechazando.
Lo que añade la casilla es que no tienes que recordar cuál de las cinco sintaxis aplica, que el flag gana sobre el modo autónomo en el que corre el paso, y que sobrevive a un run que vuelve a pasar más tarde por el mismo paso.
El interruptor del nodo y la tabla por proveedor están documentados en la página Agent Teams. Si una revisión hecha por un agente merece la pena, y qué parte de un diff sigue mereciendo a un humano, es otra pregunta, y escribimos sobre ella en ¿Deberías seguir revisando el código de tu agente de IA?. Este artículo trata de la cosa más pequeña y más mecánica: una vez que has decidido que un agente revisa, hazlo físicamente incapaz de hacer cualquier otra cosa.
Descargar AgentsRoom
Ejecuta todos tus agentes de IA, en todos tus proyectos, desde una sola ventana.
App complementaria: supervisa tus agentes en movimiento
Usa Claude, Codex, Antigravity CLI u otro proveedor de IA.
Envía bugs y peticiones directamente a tu backlog público.
Seguir leyendo
¿Deberías seguir revisando el código de tu agente de IA?
Tus agentes escriben mejor código que la mitad de las solicitudes de extracción que solías fusionar. Entonces, ¿todavía lees cada línea? El caso honesto para ambos lados, las 10 señales que te dicen que un agente cometió un error y cuánto merece realmente cada cambio una revisión.
Leer el artículoUn tablero de feedback para agentes de IA: deja que tus usuarios escriban el prompt
Las herramientas de feedback recogen peticiones. Ninguna sabe construirlas. Cuando el tablero donde escriben tus usuarios es el mismo desde el que ejecutan tus agentes de código, el paso de reescritura desaparece.
Leer el artículoDiez agentes lanzaron el mismo typecheck a la vez. La solución fue una carpeta.
Diecisiete agentes de código en el mismo checkout, diez procesos tsc a la vez, load average 37 y 87 MB de RAM libre. Un typecheck de noventa segundos tardó 7 min 36. Aquí está la medición, por qué la máquina no calculaba, y el pequeño bloqueo compartido que lo resolvió. Copiable en cualquier repositorio.
Leer el artículo