Construí 11 Hooks de Código para Claude. Seis Murieron en 24 Horas.

8 min read

Tenía un solo hook en Claude Code. Uno. Un verificador de TypeScript que ejecutaba npx tsc en un proyecto que usa Bun, y enviaba la salida a través de head -20. Así que cuando había 12 errores, yo veía tres. Excelente sistema.

Mientras tanto, mi agente podía hacer force-push a main, filtrar mis API keys, y rm -rf el repo sin que nada lo detuviera. Donde perdí los estribos fue cuando desplegó a producción en el SaaS. Le había dicho explícitamente que no lo hiciera. Lo hizo de todas formas.

Escribo sobre las mejores prácticas de Claude Code. Mi propia configuración no tenía ninguna.

Así que hice lo que hace todo desarrollador cuando se da cuenta de que su red de seguridad está hecha de cartón: construí once hooks de una vez. Tres días después, seis estaban deshabilitados. Los otros cinco, me olvidé de que existían. Así es exactamente como debería funcionar si quieres programar (sin leer tu propio código) y dormir por las noches. Casi.

TLDR: Los hooks que sobreviven son los que olvidas que existen (seguridad, secretos, operaciones destructivas). Los hooks que mueren son los que te molestan en cada edición. Audité los míos durante tres días, maté 6 de 11, y los 5 supervivientes ya atraparon 2 casi-filtraciones y un force-push. Audita los tuyos esta noche. Toma 20 minutos.

Cómic mostrando desarrollador abrumado en escritorio desordenado con cajas de alarma, luego héroe confiado con monitor limpio y escudos de seguridad, estilo satírico de los años 70
Construyendo integraciones como un fundador de startup: 11 hooks, 6 bajas, cero sobrevivientes.

El Único Hook Que Se Suponía Me Salvaría

Antes de la auditoría, toda mi configuración de hooks era un solo trigger PostToolUse en operaciones Edit y Write. Ejecutaba npx tsc para verificar errores de TypeScript después de cada cambio de archivo. Dos problemas con eso.

Primero, el proyecto corre en Bun. Ejecutar npx en un proyecto Bun es como pedirle a tu vecino francés que revise tu tarea de japonés. Medio funciona. A veces. Cuando se alinean las estrellas. Segundo, enviaba la salida a través de head -20, que corta el output. TypeScript grita sobre 12 tipos rotos, yo veo los primeros 3, Claude ve los primeros 3, y ambos asentimos y seguimos adelante. Mi verificador de tipos no estaba verificando tipos.

Pero esa es la parte graciosa. Ese hook roto era lo único que se interponía entre mi agente y acceso completo a todo. Sin protección en git push --force. Sin bloqueo en rm -rf. Sin escaneo de secretos. Sin protección de deploy. El agente podía nukear el repo, pushear a main, y filtrar cada API key en el proyecto. Lo único que no podía hacer (en teoría) era escribir TypeScript que no compilara. Y hasta eso, lo estaba haciendo mal.

Había estructurado mi CLAUDE.md como un archivo de configuración real, con reglas, con límites, con cuatro líneas de principios de integridad. Pero CLAUDE.md es una sugerencia. El agente lo lee, lo considera, y a veces decide que sabe mejor. Un hook es una pared. Exit code 2, llamada de herramienta bloqueada, sin negociación.

La pared existía. Solo estaba rota.

Mi red de seguridad era un verificador de tipos que no podía verificar tipos.

5,000 Likes por No Tener Barreras

El 31 de marzo, alguien publicó un fork de Claude Code. El código fuente se había filtrado a través del paquete npm unos días antes (Fortune y CNBC lo cubrieron, es registro público). El fork eliminó las barreras de seguridad de los prompts, removió la telemetría, desbloqueó características experimentales, y se subió a IPFS. Obtuvo aproximadamente cinco veces más tracción que un hilo educativo sólido sobre hooks que un desarrollador llamado Akshay publicó la misma semana.

Esa proporción te dice algo, y no es que los desarrolladores odien la seguridad.

Los desarrolladores odian el ruido.

Piénsalo. Instalas un hook de lint que se dispara en cada edición de archivo. Instalas un test runner que agrega 4 a 8 segundos por guardado durante una refactorización de 15 archivos. Instalas una advertencia de contexto que aparece cada 20 minutos diciéndote que la conversación se está volviendo larga (sí, lo sé, soy yo quien la está teniendo). Después de un día de esto, empiezas a ignorar toda salida de hooks. Cada notificación. Cada advertencia. Incluyendo las reales.

El problema del detector de humo de la cocina. La cosa suena cada vez que haces tostadas. Así que le quitas la batería. Y la única noche que hay un incendio real, no hay detector.

De eso se trata la brecha de tracción. No "no queremos barreras." Más bien "no queremos tus barreras, las que nos interrumpen 47 veces al día para no decir nada útil."

La conclusión del proyecto de código libre está equivocada, sin embargo. Cero barreras no es la respuesta. La respuesta es matar las seis que hacen ruido y mantener las cinco que te salvan.

No he usado free-code yo mismo. Estoy leyendo esos números como señal de mercado, no como endorso. Pero la señal es clara: cuando haces que los desarrolladores elijan entre seguridad ruidosa y silencio, eligen silencio cada vez.

3 Días, 11 Hooks, 6 Bolsas para Cadáveres

Te ahorraré el recorrido hook por hook. (De nada.) Lo que importa es el patrón, y fue obvio para el día dos: los hooks que sobrevivieron son invisibles, los hooks que murieron eran ruidosos.

Los cinco que vivieron:

El verificador de TypeScript fue una corrección de 30 segundos. Cambiar npx por bunx, cambiar head -20 por tail -5 (quieres los últimos errores, no los primeros, porque los primeros usualmente son ruido en cascada de una ruptura real). Inmediatamente atrapó un error de tipo que Claude había introducido tres ediciones antes.

El guard de git fue el que debería haber construido primero. PreToolUse en Bash, coincidencia de patrones contra push --force, push.*-f, y reset --hard. Día uno, bloqueó un force-push real. Claude estaba tratando de arreglar un conflicto de merge forzando bruto el remoto. Si hubiera pasado, habría borrado un commit que realmente necesitaba. Fusioné los patrones de operaciones peligrosas en este mismo hook (rm -rf, chmod 777, curl | bash). Un hook, una lista de regex, cada operación donde "ups" es permanente.

El escáner de secretos corre PreToolUse en Edit y Write. Regex para patrones de API key, bearer tokens, credenciales codificadas en base64. En tres días, marcó dos veces: un bearer token hardcodeado en un archivo de test, y un console.log que volcaba un header de auth completo. Ambos habrían sido commiteados sin hacer ruido. Estos son el mismo tipo de secretos que había encontrado sentados en texto claro en .claude/settings.local.json unas semanas antes. El escáner los atrapa antes de que lleguen al repo.

El guard de deploy y el logger de llamadas MCP completan los cinco. Guard de deploy: cero triggers en tres días, que es todo el punto (no juzgas un cinturón de seguridad por qué tan seguido se dispara). Logger MCP: reveló que Claude estaba obteniendo el mismo recurso cuatro veces por conversación. No es una herramienta de seguridad, es un diagnóstico de ventana de contexto. Ambos se quedan porque cuestan cero fricción.

Los seis que murieron:

Ruido. Tres de ellos. El test runner agregaba 4 a 8 segundos por guardado de archivo. Durante una refactorización tocando 15 archivos, eso son dos minutos mirando la terminal. Deshabilitado después de medio día. El hook de lint era redundante con el verificador de TypeScript (mismos errores, formato diferente, el doble de interrupciones). La advertencia de ventana de contexto se disparaba cada 20 minutos. Después de la décima vez, estaba entrenado para ignorar toda salida de hooks. Esa última es la cosa más peligrosa que puede hacer un hook.

Inutilidad. Dos de ellos. El verificador de tamaño de bundle medía el directorio equivocado para la herramienta de build equivocada. El enforcer de mensajes de commit rechazaba mensajes "genéricos", pero Claude ya escribe mensajes de commit decentes por defecto. Resolviendo un problema que ya no existe.

Redundancia. Uno. Un hook separado de comandos peligrosos que coincidía con los mismos patrones que el guard de git. Mismo regex, mismo exit code, dos hooks haciendo un trabajo. Fusionado y eliminado.

Seis abajo. Cinco en pie.

Un Buen Hook Es Uno Que Olvidas Que Existe

Esto es lo que separa a los supervivientes de los muertos: los supervivientes nunca me hicieron pensar en ellos. Corren en cada llamada de herramienta, verifican lo que verifican, se quedan callados cuando las cosas están bien. Solo los noto cuando bloquean algo. Y cuando bloquean algo, siempre es algo que me alegra que haya sido bloqueado.

Los hooks muertos hicieron lo opuesto. Interrumpían, ralentizaban las cosas, molestaban. Y después de suficiente de eso, los deshabilitaba. Ahí es cuando empieza el problema real.

Un hook deshabilitado es peor que ningún hook. Porque aún piensas que estás protegido. El escáner de secretos está corriendo, ¿verdad? Bueno no, lo apagaste el martes pasado cuando te hartaste del ruido del lint, y olvidaste que el escáner estaba en la misma configuración.

Este es el modo de falla del que nadie habla. Los hooks malos no solo fallan. Envenenan a los buenos. Un hook ruidoso te entrena para ignorar toda salida de hooks, y eso incluye el que acaba de atrapar las credenciales de tu base de datos de producción en un console.log.

Hay una escala para esto. Las cuatro líneas de integridad en mi CLAUDE.md ("Nunca mentir, Nunca ocultar, Nunca encubrir, Nunca fallar silenciosamente") cambiaron cómo se comporta el agente, pero siguen siendo sugerencias que un agente bajo presión puede esquivar. Cuando el agente optimiza para "terminado," trata las reglas de CLAUDE.md como consultivas. Un hook no negocia. Exit code 2, operación bloqueada. Punto.

Pero los hooks no reemplazan CLAUDE.md. Cubren las operaciones donde el fallo es irreversible: un secreto filtrado, un force-push, un deploy accidental. Para todo lo demás (estilo de código, decisiones de arquitectura, convenciones de nombres), CLAUDE.md es la herramienta correcta. No construyes una pared de ladrillo para hacer cumplir el nombrado de variables.

Las cosas que necesitan una pared, sin embargo, realmente necesitan una pared.

La Brecha

Antes de la auditoría: un hook. Roto. Cero seguridad. El agente podía desplegar, eliminar, y filtrar sin hacer ruido.

Después: cinco hooks. Funcionando. Cubriendo las tres cosas que realmente importan (seguridad de tipos, secretos, operaciones destructivas). Silenciosos cuando las cosas están bien. Ruidosos cuando no lo están.

La brecha entre "escribo sobre las mejores prácticas de Claude Code" y "sigo las mejores prácticas de Claude Code" era exactamente de cuatro hooks de ancho.

¿Cómo se ven los tuyos?

Si auditas tus propios hooks después de leer esto, quiero saber qué encuentras. Los peores descubrimientos hacen las mejores historias 😅

Fuentes

Hilo de Akshay sobre el ciclo de vida y configuración de hooks de Claude Code (Marzo 2025, X/Twitter).

(*) La portada es generada por IA. Los hooks en la imagen se ven limpios porque nunca han visto una base de código real.