La escalera de feedback
Si la primera señal que recibe un agente es una ejecución de CI en rojo veinte minutos después del push — o una revisión humana al día siguiente — cada error cuesta un viaje de ida y vuelta completo. El mismo error se vuelve más barato cuanto antes se detecta. Las propias buenas prácticas de Claude Code lo ponen primero en la lista: "Dale a Claude una comprobación que pueda ejecutar: tests, un build, una captura de pantalla para comparar. Es la diferencia entre una sesión que vigilas y una de la que puedes alejarte." [1]
Esto no es nuevo. La integración continua siempre ha tratado sobre feedback rápido — Martin Fowler llama a un build de diez minutos "perfectamente razonable" [9] y DORA describe CI como obtener feedback en cuestión de minutos. [10] Los agentes solo hacen el viaje de ida y vuelta más frecuente. Organiza las comprobaciones como una escalera:
En cada edición — agent hooks
Formatea y pasa el linter al archivo modificado en el momento en que se escribe: el hook afterFileEdit de Cursor, el hook PostToolUse de Claude Code.
Cuando el agente cree que ha terminado — un stop hook
Ejecuta las comprobaciones; si fallan, devuelve al agente al trabajo. El stop hook de Cursor puede devolver un followup_message; el hook Stop de Claude Code puede bloquear la finalización.
Al hacer commit — un git pre-commit hook
Build, comprobación de tipos, comprobación de formato, comprobación de complejidad. Falla rápido y bloquea el commit.
Al hacer push / pull request — CI
Tests completos con umbrales de cobertura, linting de workflows.
Antes del merge — la parte cara
Suites end-to-end, revisión automatizada, luego un humano.
Tanto Cursor como Claude Code documentan estos hooks. [3] [2] El recorrido de GitButler es un buen repaso de cómo se disparan los hooks de Cursor en la práctica. [4]
Las instrucciones son consejos, los hooks son garantías
Una regla en AGENTS.md, CLAUDE.md o las reglas de Cursor es algo que el agente debería hacer. Un hook que bloquea el commit es algo que no puede evitar. La documentación de Claude Code lo dice sin rodeos:
"A diferencia de las instrucciones de CLAUDE.md, que son consultivas, los hooks son deterministas y garantizan que la acción ocurra." [1]
Así que pon las reglas de "siempre" en hooks. Reserva el archivo de instrucciones para el criterio — cómo nombras las cosas, qué patrones prefieres — y deja que el código imponga el resto. Y di en las instrucciones de tu agente que --no-verify nunca está permitido, con CI como último filtro para lo que aun así se cuele.
Escribe mensajes de error para el agente
Una comprobación que falla debería decir qué hacer, no solo qué está mal. "El formateo falló" manda al agente a investigar; "Ejecuta npm run format y añade los cambios al stage" se resuelve en un solo paso.
Un ejemplo de nuestros propios repositorios: nuestra comprobación de complejidad usa FTA, el Fast TypeScript Analyzer, con un umbral de 60. La propia escala de FTA etiqueta las puntuaciones como "OK", "Podría ser mejor" y "Necesita mejorar" — su documentación muestra 64.17 como "Necesita mejorar". [8] Cuando un archivo supera el umbral, la comprobación no solo falla: imprime un informe de refactorización listo para usar que señala el peor archivo:
✖ FTA score 71.4 > 60 in src/billing/invoice.ts
Refactor brief:
1. Plan first: list the responsibilities in this file.
2. Separate routing, business logic and data access.
3. Keep behavior unchanged — no new features.
4. Re-run: npm run complexity
5. Then: npm run format && npm run typecheckEl agente lee eso y corrige el problema en la misma ejecución. El mensaje es el prompt más barato que escribirás jamás, porque llega justo cuando hace falta.
Mantén rápido el commit hook
Segundos, no minutos. Un hook lento enseña a los agentes — y a las personas — a saltárselo. Pasa lint y formato solo a los archivos que se van a commitear: para eso está exactamente lint-staged, que ejecuta tareas solo sobre los archivos en staging. [7] Gestores de hooks como Husky hacen que el hook forme parte del repositorio, de modo que se instala junto con el proyecto. [6]
Empuja todo lo lento más arriba en la escalera. En CI, cancela las ejecuciones que un push más reciente ha dejado obsoletas con cancel-in-progress: true [11] e impón la cobertura con umbrales — pon un umbral de líneas en 90 y la ejecución falla por debajo del 90 %. [12]
Asegúrate de que los hooks realmente se ejecutan en el entorno del agente
Git busca hooks en .git/hooks por defecto, pero core.hooksPath puede apuntarlo a otro sitio. [5] Lo descubrimos de la manera difícil: en nuestros entornos de Cursor Cloud Agent, core.hooksPath apuntaba al directorio de hooks propio del agente, que a su vez encadenaba con .git/hooks. Husky también depende de core.hooksPath — así que nuestra puerta de pre-commit dejó de ejecutarse en silencio.
Nuestra solución fue un pequeño script que escribe .git/hooks/pre-commit para encadenar con el hook de Husky, ejecutado al instalar y de nuevo cada vez que arranca el entorno. Cursor ahora también ejecuta hooks del proyecto en los cloud agents: "Cloud agents run command-based hooks from your repository" a través de .cursor/hooks.json. [3]
Sea cual sea la vía que elijas, verifícala: dentro del entorno del agente, haz un commit que debería fallar y comprueba que falla.
Ejemplo: una configuración gate-zero
Así es como lo montamos en cada repositorio. Una puerta de pre-commit de build → comprobación de tipos → comprobación de formato → comprobación de complejidad, que falla en el primer error con una pista de arreglo de una línea. Luego CI ejecuta lint, tests con umbrales de cobertura (95 % de statements, lines y functions) y linting de workflows. Los tests end-to-end solo se ejecutan en pull requests etiquetados como listos para mergear.
{
"version": 1,
"hooks": {
"afterFileEdit": [{ "command": "./scripts/hooks/format-changed.sh" }],
"stop": [{ "command": "./scripts/hooks/gate.sh", "loop_limit": 3 }]
}
}Un stop hook devuelve al agente imprimiendo un followup_message, no fallando; loop_limit limita cuántas veces puede hacerlo (el valor por defecto de Cursor es 5). [3]
#!/bin/sh
# Cursor stop hook: run the checks; if they fail, send the agent back with the output.
if ! out=$(npm run --silent check 2>&1); then
msg=$(printf 'Checks failed. Fix these before finishing:\n%s' "$out")
jq -n --arg msg "$msg" '{followup_message: $msg}'
fiafterFileEdit recibe la ruta del archivo editado como JSON por stdin (file_path), así que format-changed.sh debería leerla de ahí — por ejemplo con jq -r .file_path.
npm run build || { echo "Build failed. Fix the errors above."; exit 1; }
npm run typecheck || { echo "Type errors. Fix them before committing."; exit 1; }
npm run format:check || { echo "Run \"npm run format\" then stage the changes."; exit 1; }
npm run complexity # prints a refactor brief when a file scores > 60Nuestra puerta ejecuta un build y una comprobación de tipos de todo el proyecto porque ambos son rápidos en nuestros repositorios. Si los tuyos tardan más de unos segundos, muévelos al stop hook o a CI y mantén el pre-commit limitado a los archivos en staging.
Trata los scripts como un punto de partida, no como algo listo para copiar. El patrón importa más que las herramientas: las mismas comprobaciones, en cada peldaño, cada vez más lentas y exhaustivas a medida que subes.
Dónde encaja Aerunit
Las comprobaciones rápidas deciden cuántos viajes de ida y vuelta necesita un pull request, y los viajes de ida y vuelta deciden cuántos agentes puedes mantener ocupados. Las stories de Aerunit llevan la definición de hecho — incluyendo qué comprobaciones deben pasar — así que el agente conoce el listón antes de empezar. Cuando el agente abre un PR, Aerunit lo revisa automáticamente y puede enviar los hallazgos de vuelta a la sesión del agente: el último peldaño automatizado antes de que lo mire una persona.
Las convenciones del equipo — como "nunca uses --no-verify" o "ejecuta la comprobación de complejidad antes de commitear" — viven una sola vez en el contexto y las skills compartidas de Aerunit y se incorporan a cada story y ejecución. Más sobre ese último peldaño en nuestra guía sobre revisar pull requests de agentes.
Hecho, definido
Las stories indican qué comprobaciones deben pasar antes de que el agente empiece.
Revisión automática
Cada PR de agente se revisa, y los hallazgos vuelven a la misma sesión.
Convenciones compartidas
Reglas como "nunca uses --no-verify" escritas una sola vez e incorporadas a cada story y ejecución.
Preguntas frecuentes
¿No ralentizan los pre-commit hooks al agente?
Solo si son lentos. Mantén el commit hook en segundos: revisa únicamente los archivos en staging y deja la suite de tests completa para CI. Un hook rápido ahorra tiempo, porque el agente corrige el problema en la misma ejecución en vez de esperar una CI en rojo y volver a hacer push. [7]
¿Pre-commit hook o agent hook — cuál usar?
Ambos, para trabajos distintos. Los agent hooks (afterFileEdit y stop de Cursor, PostToolUse y Stop de Claude Code) dan feedback durante la ejecución. Un git pre-commit hook protege el commit para cualquier autor, humano o agente. CI es el último filtro para todo lo que se salte ambos. [3] [2]
¿Qué nunca debería ir en un pre-commit hook?
Nada lento, inestable o que dependa de la red: suites end-to-end, builds completos de paquetes no relacionados, llamadas a servicios externos. Eso pertenece a un peldaño superior — a CI, o solo cuando un pull request se marca listo para mergear.
¿Cómo hago que las mismas comprobaciones funcionen para personas y agentes?
Pon las comprobaciones en el repositorio, no en una herramienta concreta: scripts de package, un git hook instalado al configurar el proyecto, y CI ejecutando los mismos comandos. Así los agent hooks y los commits humanos llaman a los mismos scripts, y nadie tiene una versión privada de las reglas.
Fuentes
- [1]Claude Code Docs — Best practices
- [2]Claude Code Docs — Hooks guide
- [3]Cursor Docs — Hooks
- [4]GitButler (vendor blog) — Cursor hooks deep dive
- [5]Git — githooks documentation
- [6]Husky — Git hooks made easy
- [7]lint-staged — Run tasks against staged files
- [8]FTA — Fast TypeScript Analyzer
- [9]Martin Fowler — Continuous Integration
- [10]DORA — Continuous integration capability
- [11]GitHub Docs — Control workflow concurrency
- [12]Vitest — Coverage configuration