← Todos los articulos

Claude Code Hooks: Por qué existe cada uno de mis 95 hooks

Construí 95 hooks para Claude Code. Cada uno existe porque algo salió mal primero. El git-safety-guardian existe porque Claude hizo force-push a main. El recursion-guard existe porque un subagente generó hijos infinitos. El blog-quality-gate existe porque publiqué un artículo con 7 oraciones en voz pasiva y una nota al pie colgante.1

TL;DR

Los hooks de Claude Code ejecutan comandos de shell en puntos específicos del ciclo de vida durante el desarrollo asistido por IA. Los hooks proporcionan garantías deterministas (bloquear comandos git peligrosos, inyectar contexto, imponer calidad) sobre un sistema probabilístico (el LLM). Después de construir 95 hooks a lo largo de mi infraestructura, he descubierto que los mejores hooks surgen de incidentes, no de la planificación. Este artículo cubre la arquitectura, las historias de origen detrás de mis hooks más críticos y los patrones que he aprendido en 9 meses de desarrollo de hooks.


La arquitectura

Claude Code expone eventos del ciclo de vida donde los hooks pueden interceptar, modificar o bloquear comportamiento:2

Eventos de sesión

Evento Cuándo se dispara Mis hooks
SessionStart Comienza una nueva sesión session-start.sh — inyecta fecha, valida venv, inicializa estado de recursión
SessionEnd La sesión termina Limpieza de archivos temporales

Eventos de ejecución de herramientas

Evento Cuándo se dispara Mis hooks
PreToolUse Antes de que cualquier herramienta se ejecute git-safety-guardian.sh, recursion-guard.sh, credentials-check.sh
PostToolUse Después de que la herramienta se completa post-deliberation.sh, log-bash.sh

Eventos de respuesta

Evento Cuándo se dispara Mis hooks
UserPromptSubmit El usuario envía un prompt Inyectores de contexto (fecha, rama, información del modelo)
Stop Claude termina de responder deliberation-pride-check.sh, reviewer-stop-gate.sh

Cada hook recibe JSON en stdin y se comunica a través de stdout:

{"decision": "block", "reason": "Force push to main is prohibited"}

O permite silenciosamente al salir con código 0.3


Historias de origen: los hooks que más importan

Hook 1: git-safety-guardian.sh (PreToolUse:Bash)

El incidente: Durante una sesión temprana de Claude Code, le pedí al agente que “limpiara el historial de git”. El agente ejecutó git push --force origin main. El force push sobrescribió tres días de commits en una rama compartida. Recuperé los datos desde un respaldo local, pero el proceso de recuperación de 4 horas me convenció de que el juicio probabilístico nunca debería controlar operaciones destructivas de git.

El hook:

#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

# Only check git commands
echo "$COMMAND" | grep -qE '\bgit\b' || exit 0

# Block force push to main/master
if echo "$COMMAND" | grep -qiE 'git\s+push\s+.*--force.*\b(main|master)\b'; then
    cat << EOF
{"decision": "block", "reason": "Force push to main/master blocked by safety hook"}
EOF
fi

La lección: El hook no intenta entender la intención. Hace coincidencia de patrones sobre la cadena del comando. Simple, determinista, imposible de eludir mediante prompts ingeniosos. El agente aún puede hacer force-push a ramas de funciones (a veces legítimo), pero main/master están permanentemente protegidas.4

Intercepciones en su vida útil: 8 intentos de force-push interceptados en 9 meses.

Hook 2: recursion-guard.sh (PreToolUse:Task)

El incidente: Mientras construía el sistema de deliberación, ejecuté una sesión que generó 3 subagentes de exploración. Cada subagente, sin límites de generación, creó sus propios subagentes. La recursión consumió tokens de API a 10 veces la tasa normal. Detuve la sesión manualmente después de notar la quema acelerada de tokens.

El hook:

#!/bin/bash
CONFIG_FILE="${HOME}/.claude/configs/recursion-limits.json"
STATE_FILE="${HOME}/.claude/state/recursion-depth.json"

MAX_DEPTH=2
MAX_CHILDREN=5
DELIB_SPAWN_BUDGET=2
DELIB_MAX_AGENTS=12

# Validate integers safely (((VAR++)) crashes with set -e when VAR=0)
is_positive_int() {
    [[ "$1" =~ ^[0-9]+$ ]] && [[ "$1" -gt 0 ]]
}

La decisión de diseño clave: Los agentes heredan un presupuesto de generación de su padre en lugar de incrementar la profundidad. Un agente raíz con budget=12 puede distribuir ese presupuesto en cualquier forma de árbol. Los límites basados en profundidad son demasiado rígidos (impiden cadenas profundas pero angostas que son perfectamente seguras).5

Bloqueos en su vida útil: 23 intentos de generación descontrolada.

Hook 3: blog-quality-gate.sh (Stop)

El incidente: Publiqué un artículo de blog con 7 oraciones en voz pasiva, una nota al pie referenciada en el texto pero ausente de la sección de referencias, y “fue implementado por el equipo” como línea de apertura. El artículo se veía pulido en mi editor, pero falló verificaciones básicas de calidad que cualquier revisor humano detectaría.

El hook: Ejecuta mi linter de blog de 12 módulos sobre cualquier archivo de contenido de blog modificado. Verifica voz pasiva, notas al pie colgantes, meta descripciones faltantes, bloques de código sin etiquetar e integridad de citas. Cada hallazgo es específico: “Línea 47: voz pasiva detectada en ‘fue implementado por el equipo.’ Sugerencia: ‘el equipo implementó.’”

El paralelo con la retroalimentación humana: El hook critica el trabajo, no al operador. Dice “la línea 47 tiene voz pasiva,” no “usted escribe mal.” El mismo principio que hace constructiva la retroalimentación humana hace útil la retroalimentación automatizada.


El patrón detrás de 95 hooks

La arquitectura basada en configuración

Mis hooks evolucionaron de valores codificados a comportamiento basado en configuración:

~/.claude/configs/
├── recursion-limits.json     # Depth, spawn budgets, timeouts
├── deliberation-config.json  # Consensus thresholds per task type
├── consensus-profiles.json   # security=85%, docs=50%
├── circuit-breaker.json      # Failure mode configurations
└── file-scope-rules.json     # Path-scoped hook application

Mover los umbrales a configuraciones JSON significó que podía ajustar el comportamiento sin editar scripts de bash. Cuando necesité consenso de seguridad al 85% pero documentación al 50%, el cambio de configuración tomó 30 segundos. Un cambio de código habría requerido edición, pruebas y redespliegue.6

El patrón de capas del ciclo de vida

Mis 95 hooks forman una red de seguridad con cuatro capas:

Capa 1: Prevención (PreToolUse) — Detener las cosas malas antes de que ocurran. git-safety-guardian, credentials-check, recursion-guard.

Capa 2: Contexto (UserPromptSubmit, SessionStart) — Inyectar información que el agente necesita. Fecha, rama, contexto del proyecto, entradas de memoria, principios de filosofía.

Capa 3: Validación (PostToolUse) — Verificar que las acciones completadas cumplan los estándares. Verificación de consenso post-deliberación, registro de salida.

Capa 4: Calidad (Stop) — Controlar la salida final. Pride check, quality gate, reviewer stop gate.

Cada capa es independiente. Si un hook PreToolUse falla silenciosamente, el hook Stop aún detecta problemas de calidad. Defensa en profundidad, aplicada al comportamiento de agentes de IA.


Configuración

Los hooks residen en .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "~/.claude/hooks/git-safety-guardian.sh",
        "timeout": 5000
      }
    ],
    "PreToolUse:Task": [
      {
        "command": "~/.claude/hooks/recursion-guard.sh"
      }
    ]
  }
}

El campo matcher filtra qué herramientas activan el hook. PreToolUse:Task es una abreviatura para un matcher que solo se dispara en invocaciones de la herramienta Task. Los hooks asíncronos (async: true) se ejecutan en segundo plano sin bloquear.7

Jerarquía de alcance

  1. Nivel de usuario (~/.claude/settings.json) — se aplica a todos los proyectos. Mis 95 hooks residen aquí.
  2. Nivel de proyecto (.claude/settings.json) — agrega hooks específicos del proyecto.
  3. Frontmatter de skill/subagente — alcance limitado al ciclo de vida de un componente específico.8

Qué haría diferente

Comenzar con 3 hooks, no 25. Mi primer mes produjo 25 hooks, muchos de los cuales agregaban contexto que el agente ya tenía. La sobrecarga de cargar 25 hooks en cada llamada de herramienta era medible. Eventualmente podé hasta los hooks que producían valor real (prevenían incidentes reales, detectaban problemas de calidad reales).

Basado en configuración desde el primer día. Pasé dos semanas refactorizando umbrales codificados en configuraciones JSON. Esa refactorización habría sido gratuita si hubiera comenzado con configuraciones.

Infraestructura de pruebas temprano. Los primeros 20 hooks no tenían pruebas. Cuando agregué el arnés de pruebas (48 pruebas de integración en bash), encontré 3 hooks que fallaban silenciosamente en casos límite. Las pruebas deberían haber sido parte del hook #1.


Conclusiones clave

Para desarrolladores que comienzan con hooks: - Comience con tres hooks: seguridad de git (PreToolUse:Bash), inyección de contexto (UserPromptSubmit) y compuerta de calidad (Stop); agregue más solo cuando tenga incidentes que los justifiquen - Use el marco de temporalidad de decisiones: la arquitectura de hooks es irreversible (95 hooks dependen de ella), así que invierta en el modelo de ciclo de vida antes de escribir hooks

Para equipos que estandarizan hooks: - Estandarice los hooks a nivel de usuario para que cada miembro del equipo reciba las mismas barandas de seguridad - Registre métricas de hooks (operaciones bloqueadas, incidentes interceptados) para justificar el costo de mantenimiento - Revise los registros de hooks mensualmente para identificar nuevos patrones que valga la pena automatizar


Referencias


  1. Infraestructura de hooks del autor. 95 hooks en 6 eventos del ciclo de vida, desarrollados durante 9 meses (2025-2026). 

  2. Anthropic, “Claude Code Documentation,” 2025. Eventos del ciclo de vida de hooks. 

  3. Anthropic, “Claude Code Documentation,” 2025. Formato JSON de entrada/salida de hooks. 

  4. git-safety-guardian.sh del autor. 8 intentos de force-push interceptados registrados en ~/.claude/state/

  5. recursion-guard.sh del autor. Modelo de herencia de presupuesto documentado en ~/.claude/configs/recursion-limits.json

  6. Arquitectura basada en configuración del autor. 14 archivos de configuración JSON que codifican todos los umbrales y reglas de hooks. 

  7. Anthropic, “Claude Code Documentation,” 2025. Configuración de hooks y ejecución asíncrona. 

  8. Anthropic, “Claude Code Documentation,” 2025. Jerarquía de alcance de hooks.