Laboratorio de gobernanza con Antigravity: los límites del control

Comprobando la efectividad real de las reglas de gobernanza definidas en Markdown.

En el artículo anterior dejé pendiente una cuestión para la fase de construcción: comprobar qué tal se comportaban en la práctica las reglas de gobernanza que había definido explícitamente para Antigravity en el archivo GEMINI.md.

Control de permisos

La idea inicial para empezar a construir era, antes que nada, actualizar las dependencias desactualizadas (Next.js 12, React 18, TypeScript 4.7) y cambiar la base de Next 12 a una arquitectura hexagonal antes de dar el salto a Next 16.

En el proceso de actualizar las dependencias pude comprobar el primer fallo en la aplicación de mis instrucciones en el archivo GEMINI.md. Las reglas respecto al control de permisos definían qué instrucciones de terminal estaban permitidas y cuáles requerían validación humana. Sin embargo, la herramienta ignora este texto. El control recae en la interfaz: cuando el agente intenta ejecutar algo, salta un prompt. Si haces clic en "permitir siempre en este proyecto", el comando se añade a una allowlist en los settings internos.

Cambio de planes: la entrega de valor manda

Como ocurre en cualquier proyecto real, mi plan técnico chocó de frente con las prioridades de la stakeholder. Yo quería preparar la arquitectura y mejorar la calidad del código legacy escrito hace unos cuatro años, pero a mi hija no le importan esos temas: quería ver a todos los Pokémon, no solo a los primeros 151.

La entrega de valor manda. Aparqué el rediseño interno, abrí OpenSpec e implementé un scroll infinito. Eso sí, la red de seguridad no era negociable: antes de escribir una sola línea del scroll infinito, añadí una cobertura mínima con tests e2e. Con esa red lista, implementé la funcionalidad. El requisito quedó entregado y el cambio ya está en producción (v1.0.0).

Durante la fase de implementación detecté que el agente había tomado un atajo técnico: inyectó un comentario para deshabilitar la regla del linter que prohíbe los cambios de estado dentro de un useEffect, aunque como se trataba de un problema de rendimiento menor decidí no bloquear la entrega de valor y asumirlo temporalmente como deuda técnica.

Selección del modelo

Con la funcionalidad ya en producción, quise saldar esa deuda técnica antes de retomar el cambio a arquitectura hexagonal. Y fue al pedirle a la IA que refactorizara el código cuando se confirmó mi segunda sospecha: el archivo GEMINI.md tampoco servía para dictar qué modelo debía ejecutar la tarea.

Debido a mi propia necesidad de control, en mi GEMINI.md tengo una regla estricta llamada Status Notice. Obliga al agente a notificarme al inicio de cada interacción su rol, la tarea actual, el modo de ejecución y, clave aquí, el modelo asignado. Fue al leer estos avisos como me di cuenta de que para un problema puramente de arquitectura, el agente me estaba reportando que usaba Gemini Flash. Y esto no me cuadró.

La intención con la que escribí las reglas relacionadas con la selección del modelo no se corresponde a cómo funciona el agente de Antigravity. Estaba intentando solucionar un problema de infraestructura (enrutamiento de modelos) con un archivo de texto (el Markdown).

De forma parecida a lo que comenté en el artículo sobre infraestructura de agentes autónomos al hablar de limitar las herramientas usando el Modo Plan, la responsabilidad de cambiar al modelo adecuado en cada turno es de la persona que pilota al agente.

No hacerlo tiene un coste directo en el código. Al dejar que Flash refactorizara el código para eliminar la excepción del linter, el modelo envolvió el cambio de estado en un requestAnimationFrame dentro del useEffect. Engañaba al linter, pero mantenía el doble renderizado en el cliente.

Tras varios turnos forzando el razonamiento, llegamos a la solución extendida en el ecosistema: usar next/dynamic con ssr: false para inicializar el estado perezosamente.

Esto es un ejemplo de que usar un modelo rápido para una tarea de profundidad estructural te hace perder tiempo, la calidad o ambas cosas.

Antigravity y Antigravity IDE

Google ha dividido su ecosistema Antigravity en cuatro herramientas independientes. Entre ellas, Antigravity (2.0), que sirve para gestionar proyectos y orquestar agentes y Antigravity IDE, que es el editor de código (lo que venía siendo Antigravity antes de la versión 2.0).

Ambos permiten interactuar con la IA, lo que da a entender que ofrecen la misma experiencia. Sin embargo, hice algunas pruebas y, lejos de lo que podía imaginar, me dí cuenta que ésto no es así. Antigravity IDE se salta reglas que Antigravity sí respeta. Esto es lo que observé:

Escenario 1

La regla es:

- Use **Plan Mode** for any task that modifies files under `src/`, adds dependencies, or touches `.gitlab-ci.yml`, `AGENTS.md`, `GEMINI.md`, or `openspec/config.yaml`

Lancé un prompt pidiendo una optimización urgente de caché, saltándome el Plan Mode deliberadamente.

Escenario 2

La regla es:

- OpenSpec manages the change lifecycle via /opsx:propose → /opsx:apply → /opsx:archive.

Combiné la directiva /goal ("no te detengas hasta acabar") con OpenSpec.


Viendo este comportamiento, considero que es un error de diseño grave por parte de Google mantener el panel del agente en Antigravity IDE.

Lo que me llevé

Como ya comenté en uno de los artículos anteriores para definir aspectos relativos a la seguridad, los archivos Markdown no son el enfoque adecuado para fijar los límites al agente sobre cómo debe operar. Con esta práctica deliberada he podido comprobar que para obtener los resultados esperados en el desarrollo asistido por IA, es necesario conocer cómo cada herramienta aplica sus límites.

Honestamente, la decisión de Google sobre separar responsabilidades en aplicaciones distintas no me convence. Resulta mucho más intuitivo el estándar que marcan herramientas como Claude Code, donde defines de forma declarativa el modelo en un Frontmatter o YAML: desde (model: sonnet) hasta los permisos de ejecución (tools: Read, Glob, Bash, Edit). El CLI se encarga del resto.

Dejo abierta la exploración sobre si con Antigravity SDK podría resolver estos problemas que me he encontrado, pero mi stakeholder está esperando más funcionalidades en el catalogo de Pokémon, y la entrega de valor manda.

Explora el código

Ver Repositorio en GitLab →

Conceptos aplicados