Saltar al contenido

Hooks de Claude Code que en silencio no hacen nada

Para CTO y desarrolladoresHarness y controles

Filip PapranecFundador de Digitaliko

Todas las ejecuciones pasaron. El hook no hizo nada. Ilustración: un archivo de configuración cuyo comando de hook termina en 2>/dev/null || true, junto a una fila de checks verdes que no demuestran nada.Todas las ejecuciones pasaron. El hook no hizo nada. Ilustración: un archivo de configuración cuyo comando de hook termina en 2>/dev/null || true, junto a una fila de checks verdes que no demuestran nada.

Los equipos añaden hooks de Claude Code para que los agentes de IA no causen daños y después dan por hecho que funcionan. Un hook puede pasar en cada ejecución sin hacer nada. Un hook que en silencio no hace nada es peor que no tener ninguno, porque todo el mundo deja de mirar. La solución son cuatro comprobaciones baratas que cualquier equipo puede copiar.

La respuesta corta: un hook se queda mudo cuando su salida no llega a ninguna parte, cuando su ruta no existe o cuando alguien reescribe su código de salida. Compruebe las tres cosas en la CI. Y ponga el hook más importante en el evento Stop, para que el agente no pueda decir "terminado" mientras los tests están en rojo.

¿Cómo bloquean algo los hooks de Claude Code?

Un hook es un comando de shell que Claude Code ejecuta ante un evento. PreToolUse se ejecuta antes de llamar a una herramienta, Stop cuando el agente quiere terminar. El comando recibe el evento como objeto JSON por stdin.

Decide el código de salida:

  • Exit 0 deja pasar.
  • Exit 2 bloquea. Lo que el hook escribe en stderr vuelve al agente como motivo.
  • Cualquier otro código es un error no bloqueante. Claude Code sigue adelante.

Ese es todo el contrato. Todo lo que falla con los hooks falla dentro de él.

¿Por qué un hook no hace nada en silencio?

Un hook puede estar callado desde el primer día sin que nadie lo note. Normalmente por tres motivos, cada uno inofensivo por separado:

  • Silenciado. El hook escribe su único mensaje en stderr, pero el comando en la configuración termina en 2>/dev/null. El agente no oye nada.
  • Ausente. El hook usa una ruta relativa. En una sesión que arranca dentro de un repositorio anidado, esa ruta no existe. Exit 127, comando no encontrado.
  • Enmascarado. || true al final convierte 127 en 0. En un evento bloqueante convierte igualmente 2 en 0. Cada ejecución "pasa".
A la izquierda, el hook que se quedó callado: el comando bash tools/hooks/guard.sh 2>/dev/null || true y tres causas: una ruta relativa (exit 127), stderr a /dev/null y || true, que convierte el código de salida en 0. A la derecha, un hook Stop en cuatro pasos: stop_hook_active, typecheck, lint y tests, y en rojo decision: block con el log del fallo.A la izquierda, el hook que se quedó callado: el comando bash tools/hooks/guard.sh 2>/dev/null || true y tres causas: una ruta relativa (exit 127), stderr a /dev/null y || true, que convierte el código de salida en 0. A la derecha, un hook Stop en cuatro pasos: stop_hook_active, typecheck, lint y tests, y en rojo decision: block con el log del fallo.

Nadie lo nota, porque un hook mudo parece exactamente igual que uno sano. Solo lo encuentra un análisis de las sesiones de Claude Code o una comprobación en la CI.

El patrón roto, simplificado:

{ "type": "command", "command": "bash tools/hooks/guard.sh 2>/dev/null || true" }

El corregido, de nuestro starter público:

{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/push-gate.sh" }

¿Qué cuatro comprobaciones detectan un hook mudo?

Añada a su validador una comprobación que se ejecute en la CI de cada repositorio. Cuatro greps sobre .claude/settings.json, sin ejecutar nada:

ComprobaciónQué detectaSolución
El script existeUna ruta que no existe"$CLAUDE_PROJECT_DIR"/... o una ruta absoluta
El script es ejecutableUn hook que solo funciona por suertechmod +x
stderr no se descarta cuando el script escribe en élUn hook silenciadoQuitar 2>/dev/null
Un hook PreToolUse no termina en || trueUn bloqueo convertido en paso libreQuitar || true

Pruebe la comprobación con un fallo real: una configuración rota debe dar errores críticos y la corregida debe pasar.

No todo || true es un error. Un hook de bienvenida en SessionStart puede usar 2>/dev/null || true a propósito, porque una bienvenida nunca debe romper una sesión. La comprobación solo debe señalar los sitios donde se espera un bloqueo.

La lección en una frase, tal como está en nuestro hook contra las firmas de IA: "A rule is a request. This is the lock." Una regla es una petición, un hook es un candado. Y un candado necesita su propio test.

Hace poco el agente tenía sus reglas solo en archivos de reglas y a veces no las cumplía. Así que las convertimos en comprobaciones que no puede saltarse.

Filip Papranec
Filip Papranec
Fundador de Digitaliko

¿Qué hook bloquea de verdad?

El hook Stop. Un agente que dice "terminado" con los tests en rojo le cuesta a un sénior una ronda de revisión. Un hook Stop obliga al agente a arreglarlo antes.

Nuestra versión del starter público, ligeramente recortada:

#!/bin/bash
# Stop hook: the agent can't finish while the checks are red.
in=$(cat)
[ "$(printf '%s' "$in" | jq -r '.stop_hook_active // false')" = true ] && exit 0
cd "${CLAUDE_PROJECT_DIR:-.}" 2>/dev/null || exit 0
out=$(GATE_SKIP_INSTALL=1 GATE_SCRIPTS="typecheck lint test" bash scripts/gate.sh checks 2>&1) && exit 0
jq -n --arg r "Checks are red. Fix them before you say the task is done:
$out" '{decision: "block", reason: $r}'

Paso a paso, hace esto:

  1. Lee stop_hook_active

    Si es true, el agente ya está continuando por culpa de este hook. El hook lo deja pasar para que no entre en un bucle.

  2. Ejecuta las comprobaciones

    Typecheck, lint y tests, los mismos que en la CI.

  3. Bloquea con un motivo

    Si las comprobaciones están en rojo, devuelve decision: block con el log del fallo como motivo.

  4. El agente arregla la causa

    Lee el log, corrige el error e intenta terminar de nuevo.

Bloquea con JSON, no con un código de salida. El agente sigue trabajando y el motivo que recibe es exactamente lo que falló.

Es un aviso temprano, no el gate. La comprobación determinante debe volver a ejecutarse después de la sesión, en código que el agente no puede tocar. El hook solo ahorra una ronda.

¿Qué vigilar en un hook Stop?

Un hook Stop también puede tener un fallo silencioso propio. Un PATH fijo y mínimo, sin los directorios de herramientas del usuario, hace que en los repositorios con Bun falten las herramientas que necesitan las comprobaciones. Un gate que se busca en un sitio fijo solo funciona en una máquina. Defina el PATH completo y busque el gate en relación con el propio hook.

Hooks de Claude Code en un equipo: ¿por dónde empezar?

Repase qué tienen ya sus repositorios. Cada punto son unas pocas líneas en la configuración o en la CI:

El tercer punto es el más fácil de pasar por alto. Nuestro hook contra las firmas de IA lee su entrada con jq, recurre después a python3 y luego a sed. Que falte jq nunca debe convertir el candado en un permiso silencioso. Las rutas relativas, por su parte, se rompen en repositorios anidados y worktrees.

Puede empezar con el Claude Code production starter: un push gate, un escaneo de secretos y un hook Stop, con licencia MIT.

Dónde encajan los hooks junto a los archivos de reglas lo explicamos en Reglas para el código de IA en un equipo. Cómo implantarlo en todo el equipo está en Buenas prácticas de Claude Code para equipos: 7 reglas que se mantienen. Qué puede hacer el agente sin preguntar y cuándo es seguro saltarse los permisos está en Claude Code dangerously skip permissions.

¿Quiere hooks que aguanten en sus repositorios?

Configuramos hooks, gates y CI directamente en el repositorio del equipo dentro de AI-native SDLC para equipos de desarrollo. ¿A su equipo le faltan más manos que reglas? Vea un desarrollador sénior para su equipo. En Digitaliko la mayor parte del código la escribe la IA. Un sénior revisa cada cambio y responde de la producción. Desde 2023 hemos entregado más de 15 proyectos en producción.

Le respondemos en un plazo de dos días laborables con unas preguntas sobre su trabajo. Después acordamos qué abordamos primero.

Si prefiere hablar antes, reserve una llamada introductoria de 15 minutos.

¿Cuándo comprobó por última vez que sus hooks siguen bloqueando?

En resumen

  • Un hook se queda mudo cuando se descarta su stderr, su ruta no existe o || true reescribe su código de salida.
  • Cuatro greps sobre .claude/settings.json en la CI detectan las tres cosas.
  • Un hook Stop bloquea el "terminado" mientras los tests están en rojo, y solo bloquea una vez.
  • La comprobación determinante se ejecuta de nuevo en la CI, donde el agente no puede cambiarla.

Preguntas frecuentes

¿Qué son los hooks de Claude Code?

Comandos de shell que Claude Code ejecuta ante eventos, como PreToolUse antes de llamar a una herramienta o Stop cuando el agente quiere terminar. El hook recibe el evento como JSON por stdin y decide con su código de salida o con una respuesta JSON.

¿Cómo bloquea un comando un hook de Claude Code?

Con el código de salida 2. Claude Code bloquea entonces la acción y devuelve al agente, como motivo, lo que el hook escribió en stderr. El exit 0 la deja pasar. Cualquier otro código es un error no bloqueante y el agente sigue adelante.

¿Por qué no se ejecuta mi hook de Claude Code?

Lo más habitual es una ruta relativa que no existe en el directorio de la sesión, stderr descartado con 2>/dev/null o un || true al final que reescribe el código de salida. Empiece la ruta con "$CLAUDE_PROJECT_DIR" y compruebe la configuración de hooks en la CI.

¿Qué significa stop_hook_active?

Vale true cuando el agente ya está continuando porque un hook Stop lo bloqueó. Si es true, salga enseguida. De lo contrario, una comprobación que el agente no puede arreglar lo bloqueará sin fin.

¿Basta un hook Stop como quality gate?

No. Es un aviso temprano dentro de la sesión. Ejecute las mismas comprobaciones de nuevo en la CI y en la protección de ramas, donde el agente no puede cambiarlas.

Pregunte a una IA sobre este artículo

La IA también tiene en cuenta nuestros otros artículos y la experiencia de proyectos reales.

ChatGPTClaudePerplexity
Engineering

Más artículos

Harness y controles

Context engineering para agentes de programación: qué va en el repo

El context engineering decide qué ve un agente de programación con IA mientras trabaja. Qué va en AGENTS.md o CLAUDE.md, qué reglas se cargan solo donde aplican, cómo la tarea se convierte en contexto y cómo mantenerlo todo pequeño.

Harness y controles

Playwright MCP: que el agente de IA demuestre que funciona

Playwright MCP da a un agente de IA un navegador real. Cómo lo usamos para que el agente compruebe su propio cambio en la app en marcha y entregue PASS o FAIL con capturas, qué detecta que los tests unitarios no ven y cuándo son mejor herramienta los scripts de Playwright.

Harness y controles

Revisión de código con IA: Claude Code en CI y lo que no ve

Cómo ejecutamos la revisión de código con Claude Code en cada pull request con una única GitHub Action reutilizable: qué se le pide al revisor de IA, cómo se quedó en verde y en silencio, qué se le escapa y por qué solo una persona aprueba.