Ocho hooks que garantizan la confiabilidad de un agente de IA
Las reglas en CLAUDE.md se siguen más o menos el 80% del tiempo. Los hooks se siguen el 100%. Después de seis meses probando, estos son los ocho que nunca saqué.
CLAUDE.md es una sugerencia. Si escribís “correr Prettier antes de hacer commit”, el agente se lo va a saltar más o menos una de cada tres veces. Afinar las instrucciones no resuelve el problema. Una tasa de cumplimiento del 80% no es un problema de calidad del modelo. Es una limitación estructural de poner reglas dentro de la ventana de contexto y esperar que el modelo las siga.
Los hooks operan en un plano completamente distinto. Son scripts que se ejecutan automáticamente en puntos específicos del ciclo de vida, independientemente de lo que el modelo decida hacer. PreToolUse se dispara justo antes de que el agente modifique un archivo o corra un comando. PostToolUse se dispara justo después. El modelo no elige si los corre o no. Simplemente corren.
La diferencia práctica es inmediata. Agregar diez líneas de reglas a CLAUDE.md y agregar un hook a .claude/settings.json se sienten como intervenciones completamente distintas. El código de salida 2 bloquea la acción del agente de raíz. El código 0 la deja pasar. Cualquier otro código registra una advertencia pero no bloquea. Y como los hooks viven en settings.json, los commiteas una vez y todo el equipo los recibe por git.
Los cuatro guardias antes de ejecutar
Llevo más de seis meses usando hooks. Estos cuatro hooks de PreToolUse sobrevivieron en todos mis proyectos sin que los haya sacado ni una vez.
Block Dangerous Commands atrapa patrones destructivos como rm -rf, git reset --hard y DROP TABLE mediante regex, y devuelve el código de salida 2 para matar la acción antes de que ocurra. He visto agentes intentar rm -rf en directorios que no deberían tocar. Sin este hook, el daño hubiera sido real.
Protect Sensitive Files bloquea cualquier intento de modificar .env, package-lock.json, *.pem y archivos similares. El agente nunca tiene la oportunidad de sobreescribir tu lockfile ni filtrar credenciales en un commit.
Require Tests Before PR condiciona la creación de pull requests a que pasen las pruebas. Configurás el matcher en mcp__github__create_pull_request y el agente literalmente no puede abrir un PR hasta que los tests pasen. Se acabó el “arreglo los tests en un follow-up”.
Log Every Command escribe cada comando bash que corre el agente en .claude/command-log.txt con timestamps. Tres días después, cuando algo parece raro, podés rastrear exactamente qué pasó.
Los tres inspectores después de ejecutar
Los hooks de PostToolUse corren inmediatamente después de que el agente modifica un archivo. Los encadeno en secuencia.
Auto-Format corre Prettier sobre cada archivo modificado. Para proyectos Python, reemplazalo con Black. Para Go, usá gofmt. El formateador corre haya o no se acordado el agente de formatear.
Auto-Lint corre ESLint justo después del formateo. Si ESLint encuentra errores, el agente los ve de inmediato y los corrige en el mismo turno. Los problemas de lint que llegan a la revisión humana de código caen a casi cero.
Auto-Test corre el test suite relevante después de cada cambio de archivo. Cuando un test falla, el agente lo sabe en segundos e intenta una corrección. Paso el output por tail -5 para quedarme solo con el resumen, lo que evita que el output de los tests inunde la ventana de contexto.
El orden importa. Prettier primero, luego ESLint, luego los tests. Para cuando un humano mira el código, el formateo y el lint ya pasaron. Los comentarios de estilo en la revisión de código desaparecen.
Preservar el trabajo cuando el agente se detiene
Un hook de Stop se encarga de esto: Auto-Commit corre git add -A && git commit cada vez que el agente termina una respuesta. Cada unidad de trabajo tiene su propio commit. Dos tareas nunca se mezclan en un solo commit.
Combinalo con git worktrees y obtenés commits automáticos por rama en tus feature branches. Si el agente se cuelga o lo interrumpís, nunca perdés el último bloque de trabajo.
Lo que no funcionó tan limpio
El encadenamiento de hooks suena elegante, pero debuggear una cadena que falla es más difícil que debuggear un script solo. Cuando el hook de auto-test empezó a fallar silenciosamente porque el test runner no estaba instalado en un proyecto nuevo, me pasé una hora rastreando por qué el agente seguía produciendo código sin pruebas. El hook devolvía el código de salida 0 (paso) porque el script de tests directamente no se encontraba, y el shell trató “command not found” como una condición no bloqueante. Tuve que agregar una verificación explícita de la existencia del test runner antes de invocarlo.
El rendimiento es la otra restricción. La preocupación habitual es que muchos hooks enlentecen todo, pero eso no es del todo correcto. La pregunta real es si cada hook individual termina en menos de 200 milisegundos. Un run de Prettier sobre un solo archivo tarda unos 50ms. Un chequeo de ESLint tarda unos 80ms. Los tests varían, pero acotar el scope a los archivos afectados mantiene la mayoría de los runs rápidos. Si algún hook individual tarda más de un segundo, el ciclo de feedback del agente empieza a sentirse lento.
Por qué esto responde a un patrón más amplio
El blog de Harness Engineering de OpenAI hizo una observación que resuena: los agentes funcionan mejor dentro de límites rígidos y una estructura predecible. La filosofía de diseño de React dice lo mismo sobre los componentes: unidades componibles con fases de ciclo de vida definidas y estado.
Los hooks en Claude Code siguen la misma abstracción. El estado corresponde a sesiones y memoria. Los hooks son las funciones que intervienen en los límites del ciclo de vida. PreToolUse fija los límites. PostToolUse hace que la estructura sea predecible. Stop preserva el resultado.
La línea “correr Prettier” que antes tenía en CLAUDE.md ya no está. El hook lo corre cada vez, sin que nadie se lo pida.
Unite al boletín
Recibí insights sobre la IA más reciente.