Free

Guía completa de Claude Code Hooks: controla cada acción de Claude

Análisis completo del mecanismo de Claude Code Hooks: cinco tipos de eventos, control de códigos de salida y cuatro configuraciones reales para auditar, interceptar y automatizar acciones de IA.


Cada vez que Claude Code lee un archivo, escribe código o ejecuta un comando, hay un sistema de eventos funcionando en segundo plano. Los Hooks son la interfaz para conectarse a ese sistema — puedes inyectar tu propia lógica en cualquier momento: ejecutar linters automáticamente, registrar operaciones, interceptar acciones peligrosas o disparar cualquier comando de shell.

Este artículo cubre en su totalidad el mecanismo de Hooks, su configuración y uso práctico.


Qué son los Hooks

Los Hooks son comandos de shell configurados en settings.json que Claude Code ejecuta automáticamente cuando ocurren eventos específicos.

La analogía más directa: los git hooks. Git puede disparar scripts antes y después de operaciones como commit o push. Los Claude Code Hooks funcionan exactamente igual — la diferencia es que los puntos de disparo son las llamadas a herramientas de la IA.

¿Por qué importa esto?

Cuanto más capaz se vuelve Claude Code, más necesitas una capa de control determinista. Los Hooks proporcionan:
- Garantías de ejecución que no dependen del prompt (Claude puede ignorar instrucciones, pero los hooks siempre se ejecutan)
- Registros de operaciones auditables
- Comprobaciones de calidad automatizadas


Cinco tipos de Hooks

Tipo Disparador Uso típico
PreToolUse Antes de una llamada a herramienta Bloquear operaciones peligrosas, registrar intención
PostToolUse Después de una llamada a herramienta Auto-lint, ejecutar tests
PreCompact Antes de la compactación del contexto Guardar snapshot del estado actual
Notification Cuando Claude envía una notificación Alertas de escritorio, mensajes de Slack
Stop Cuando Claude termina de responder Resumir logs, disparar flujos posteriores

Los más usados son PreToolUse y PostToolUse, para interceptar y post-procesar llamadas a herramientas.


Formato de configuración

Los Hooks van en ~/.claude/settings.json (global) o en .claude/settings.json en la raíz del proyecto (nivel proyecto):

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npm run lint --silent"
          }
        ]
      }
    ]
  }
}

Tres campos clave:

  • matcher: Regex que coincide con nombres de herramientas, determina qué llamadas disparan este hook. "Write|Edit" se activa al escribir o editar archivos. Déjalo vacío o usa ".*" para coincidir con todas las herramientas.
  • type: Por ahora solo "command".
  • command: Cualquier comando de shell.

Referencia de nombres de herramientas

Nombres de herramientas que necesitas para escribir matchers:

Nombre Acción
Write Escribir un nuevo archivo
Edit Editar un archivo
Bash Ejecutar un comando de shell
Read Leer un archivo
Glob Búsqueda de archivos
Grep Búsqueda de contenido
TodoWrite Actualizar lista de tareas

Entorno de ejecución del Hook

Durante la ejecución, los datos se pasan como JSON por stdin:

{
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.rb",
    "content": "..."
  },
  "tool_response": "..."
}

PreToolUse recibe tool_input (los argumentos antes de la llamada). PostToolUse también recibe tool_response (el valor de retorno de la herramienta).

Ejemplo de hook con lógica condicional:

#!/bin/bash
input=$(cat)
file=$(echo "$input" | jq -r '.tool_input.file_path')

# Solo ejecutar rubocop en archivos .rb
if [[ "$file" == *.rb ]]; then
  rubocop "$file" --autocorrect-all --no-color
fi

Significado de los códigos de salida

El código de salida del hook controla el comportamiento posterior de Claude Code:

Código de salida Significado
0 Éxito, continuar ejecución
2 Bloquear: cancelar la llamada a herramienta actual, enviar stderr a Claude
Otros no-cero Registrar el error, pero continuar

El código de salida 2 es el más poderoso — te permite escribir lógica de intercepción en PreToolUse para detener a Claude de realizar una operación y explicarle por qué.


Práctica real: cuatro configuraciones de Hook

1. Auto-formato al escribir archivos

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" == *.rb ]] && rubocop -A \"$file\" --no-color -q || true'"
          }
        ]
      }
    ]
  }
}

2. Bloquear eliminación de directorios específicos

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'cmd=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .command); if echo \"$cmd\" | grep -qE \"rm.*/(migrations|seeds)\"; then echo \"No está permitido eliminar los directorios migrations o seeds\" >&2; exit 2; fi'"
          }
        ]
      }
    ]
  }
}

3. Log de auditoría de operaciones

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$(date '+%Y-%m-%d %H:%M:%S') $CLAUDE_TOOL_NAME: $(echo $CLAUDE_TOOL_INPUT | jq -c .)\" >> ~/.claude/audit.log"
          }
        ]
      }
    ]
  }
}

4. Notificación de escritorio al completar

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude ha terminado\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Global vs. nivel proyecto

Los Hooks pueden ir en dos lugares:

Global (~/.claude/settings.json): Reglas comunes a todos los proyectos — logs, notificaciones.

Nivel proyecto (.claude/settings.json): Comprobaciones específicas del proyecto. Los hooks de proyecto y los globales se combinan y ambos se ejecutan.

En proyectos de equipo, haz commit del settings.json del proyecto en git para que todos ejecuten los mismos hooks.


Depuración de Hooks

Pasos para resolver problemas cuando un hook no se activa:

  1. Verificar el matcher: Los nombres de herramientas distinguen mayúsculas de minúsculas — write no es Write
  2. Ejecutar el comando por separado: Copia el comando del hook y ejecútalo directamente en el terminal
  3. Revisar la salida de Claude Code: El stderr del hook aparece en la conversación
  4. Simplificar para probar: Empieza con echo "hook triggered" >> /tmp/hook.log para confirmar el disparo

Resumen

El valor central de los Hooks es conectar el comportamiento impredecible de la IA con los estándares de ingeniería deterministas. Claude puede olvidar ejecutar los tests, pero un PostToolUse hook no. Claude puede eliminar archivos por error, pero un interceptor PreToolUse no lo permitirá.

Empieza con un hook: auto-lint al escribir archivos. Una vez que funcione, agrega más.