Biblioteca · Hooks y agentes auxiliares

Hooks: reglas automáticas de Claude Code

Creador50 minActualizado: octubre de 2026
35 de 105 en la biblioteca

Módulo: 7. Hooks: autonomía a nivel de sistema | Tiempo: ~30 min de teoría + 20 min de práctica


Lo esencial

Los skills los llamas tú, cuando los necesitas. Los hooks funcionan sin ti, siempre. Son como las reglas de un contrato de trabajo: el empleado las sigue de forma automática, sin esperar a que se las recuerden cada vez. Un hook se dispara con un evento concreto (antes de una acción, después, ante un error, al terminar) y ejecuta lo que tú le indicaste.

En esta lección está el panorama completo: unos 30 tipos de eventos, 5 tipos de manejadores y el formato exacto de los datos. Empecemos por lo principal.


Conceptos clave

  • Hook: una regla automática que se dispara con un evento concreto en Claude Code
  • Evento (event): un momento en el ciclo de vida de Claude Code: inicio de sesión, llamada a una herramienta, final, etcétera
  • Manejador (handler): qué se ejecuta exactamente con el evento: un script de bash, una solicitud HTTP, una herramienta MCP, un prompt o un agente
  • Matcher: un filtro: a qué herramientas o eventos reaccionar exactamente
  • settings.json: el archivo de configuración de los hooks (.claude/settings.json para el proyecto, ~/.claude/settings.json para todo)
  • Exit code: cómo comunica el hook su decisión: 0 = todo bien, 2 = bloquear

Teoría

Skills vs Hooks: cuál es la diferencia

No compiten: son herramientas distintas.

Skills Hooks
Activación Tú los llamas de forma explícita Automática con un evento
Alcance Proyecto o global Proyecto o global
Dónde viven .claude/skills/<name>/SKILL.md .claude/settings.json o ~/.claude/settings.json
Para qué Instrucciones de cómo hacer una tarea Reglas de seguridad y automatización
Analogía Una receta Las reglas del contrato de trabajo

🎨 Imagínalo así: un hook es el guardia de la entrada y de la salida. Un skill es el especialista que contratas para una tarea concreta. El guardia trabaja siempre. El especialista, cuando lo necesitas.


Tipos de eventos (events): cuándo se disparan los hooks

Claude Code admite unos 30 tipos de eventos (la lista exacta crece de versión en versión; consulta la documentación oficial). Para empezar necesitas 6 principales. Los demás son para escenarios avanzados.

Los 6 eventos principales (80% del uso)

Evento Cuándo Para qué
PreToolUse ANTES de ejecutar una herramienta Bloquear acciones peligrosas, revisar condiciones
PostToolUse DESPUÉS de una ejecución exitosa Registro, auditoría, notificaciones
Stop Claude terminó su respuesta Aviso de "listo", limpieza, correr pruebas
Notification Claude manda una notificación Reaccionar a eventos intermedios
SessionStart Inicio o reanudación de la sesión Cargar contexto, revisar el entorno
UserPromptSubmit El usuario envió una solicitud Validar, agregar contexto antes de procesar

Eventos avanzados (cuando los principales te queden chicos)

Evento Cuándo Ejemplo
SubagentStart Arranca un subagente Registrar qué agentes se lanzan
SubagentStop Un subagente terminó Revisar el resultado del subagente
PostToolUseFailure Una herramienta terminó con error Mandar una alerta ante el error
PostToolBatch Terminó un lote de llamadas en paralelo Revisión después de operaciones en lote
FileChanged Un archivo cambió en el disco Recargar .env cuando cambia
ConfigChange Cambió la configuración Reaccionar a una actualización de settings
PreCompact Antes de comprimir el contexto Guardar lo importante antes de la compresión
SessionEnd La sesión termina Limpieza final, guardar el estado
StopFailure La respuesta se cortó por un error de la API Alerta por rate limit o error de facturación
PermissionRequest Apareció una ventana de permiso Aprobar automáticamente ciertas operaciones
CwdChanged Cambió la carpeta de trabajo Cambiar de entorno
Setup Arranque con --init o --maintenance Instalar dependencias al inicializar

🎨 Imagínalo así: los eventos son las cámaras de una fábrica. Cámara en la entrada (PreToolUse), cámara en la salida (PostToolUse), cámara en la oficina del director (Stop). No instalas treinta cámaras el primer día: empiezas con 3 o 4 en los puntos críticos.


Más a fondo: los 4 eventos principales

⚠️ Importante sobre la vigencia: los primeros materiales sobre Claude Code mencionan "4 tipos de hooks" (Pre-tool / Post-tool / Stop / Need you): es el modelo básico de la documentación vieja. Para octubre de 2026, el ecosistema creció a unos 30 eventos del ciclo de vida (PreToolUse, PostToolUse, UserPromptSubmit, Stop, SessionStart, SubagentStop, Notification, PreCompact, PostCompact y otros) y 5 tipos de manejadores (command, http, mcp_tool, prompt, agent). Estos 4 escenarios básicos siguen cubriendo la mayoría de las tareas. Los demás eventos sirven para afinar encima. Más detalles en la lección Hook-Deny-By-Design: ahí se usan justo los eventos avanzados.

Equivalencias entre el viejo "cuarteto" y los eventos actuales:

Categoría vieja Eventos actuales de 2026
Pre-tool PreToolUse + PreCompact + UserPromptSubmit
Post-tool PostToolUse + PostCompact + SessionStart
Stop Stop + SubagentStop
Need you Notification + UserPromptSubmit

🎨 Imagínalo así: el viejo "cuarteto" son cuatro casetas de vigilancia en una bodega pequeña. Hoy la bodega creció hasta ser una fábrica: tres decenas de puestos, pero las 4 entradas principales siguen llevando casi todo el flujo. Los demás son para pasillos especiales.


🎨 Imagínalo así: PreToolUse es el control de calidad en la línea de ensamblaje. La pieza todavía no está atornillada, pero ya se revisa. Atrapas el defecto antes de instalarla. Si la instalas defectuosa, hay que desarmar todo el conjunto.

1. PreToolUse: revisión antes de la acción

Cuándo se dispara: antes de que Claude ejecute cualquier herramienta (escribir un archivo, leerlo, un comando de bash, etc.)

Para qué: bloquear acciones peligrosas, revisar condiciones, proteger archivos sensibles.

Escenarios prácticos:

  • No dejar que Claude edite el archivo .env con las claves de API
  • Revisar que el código no tenga secretos escritos directamente
  • Bloquear la escritura en la base de datos de producción
  • Revisar el presupuesto antes de operaciones caras
json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/check-secrets.sh"
          }
        ]
      }
    ]
  }
}

Si el script regresa exit code 2 → Claude Code se detiene y no ejecuta la acción. El mensaje de stderr se le pasa a Claude.


🎨 Imagínalo así: PostToolUse es el encargado del archivo. El documento ya se firmó y se entregó, y el encargado lo anota en el registro: quién, qué, cuándo. Sin él, en un mes no recordarás qué archivos tocó Claude el lunes.

2. PostToolUse: acción después de ejecutar

Cuándo se dispara: después de que Claude ejecutó una herramienta con éxito.

Para qué: registrar qué cambió, crear un registro de auditoría, avisar de cambios concretos.

Escenarios prácticos:

  • Anotar en un archivo de registro qué archivos cambió Claude y cuándo
  • Mandar un aviso a tu chat de trabajo (Slack, Telegram u otro) cuando cambió un archivo crítico
  • Actualizar un contador de operaciones para controlar el presupuesto
  • Crear un commit de git después de los cambios
json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/audit-log.sh"
          }
        ]
      }
    ]
  }
}

3. Stop: al terminar la respuesta

Cuándo se dispara: cuando Claude Code termina de responder y cierra la tarea.

Para qué: avisar que el trabajo está listo, limpiar, lanzar el siguiente paso.

Escenarios prácticos:

  • Notificación de macOS "Claude terminó la tarea": puedes trabajar en otra cosa mientras tanto
  • Mandar el reporte final a tu chat de trabajo
  • Correr las pruebas después de que Claude escribió código
  • Commit de git automático al terminar
json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude terminó la tarea\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

🎨 Imagínalo así: el hook Stop = el repartidor que te llama: "ya entregué tu pedido". No te quedas en la puerta todo el día: esperas la llamada.


4. Notification: avisos

Cuándo se dispara: cuando Claude Code le manda una notificación al usuario (pero no es Stop).

Para qué: reaccionar a los mensajes intermedios de Claude, no solo al final.

Diferencia con Stop: Stop es el final completo de la tarea. Notification es Claude avisando algo a mitad del proceso.

Valores de matcher: permission_prompt, idle_prompt, auth_success

Escenarios prácticos:

  • Registrar todos los mensajes intermedios de Claude
  • Avisar cuando Claude encuentra un error y sigue trabajando
  • Seguir el avance de tareas largas

5 tipos de manejadores (handlers): CÓMO ejecuta el hook la acción

El evento es el CUÁNDO. El manejador es el CÓMO. Claude Code admite 5 tipos de manejadores:

Tipo Qué hace Cuándo usarlo
command Ejecuta un script de bash El 90% de los casos: revisiones, registros, avisos
http Manda una solicitud HTTP POST Webhook a Slack, a un mensajero, a un servicio externo
mcp_tool Llama una herramienta de un servidor MCP Cuando ya tienes conectado un servidor MCP
prompt Manda texto a un modelo rápido Revisión con IA de la solicitud antes de ejecutarla
agent Lanza un subagente (experimental) Revisiones complejas que requieren razonar

🎨 Imagínalo así: 5 manejadores = 5 formas en que reacciona el guardia. Puede revisar él mismo (command), llamarle a su jefe (http), usar el radio (mcp_tool), preguntarle al compañero (prompt) o llamar al equipo de respuesta (agent).

Manejador command (script de bash): el principal

El más simple y común. Ejecuta un script de shell.

json
{
  "type": "command",
  "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-secrets.sh",
  "timeout": 30
}

Manejador http (webhook): para servicios externos

Manda los datos del hook como una solicitud POST. El cuerpo de la solicitud es el mismo JSON que un hook command recibe por stdin.

json
{
  "type": "http",
  "url": "http://localhost:8080/hooks/validate",
  "headers": {
    "Authorization": "Bearer $MY_TOKEN"
  },
  "allowedEnvVars": ["MY_TOKEN"],
  "timeout": 30
}

La respuesta del servidor en formato JSON se procesa igual que el stdout de un hook command.

Manejador prompt: revisión rápida con IA

Manda el texto a un modelo rápido. Sirve para evaluar si una solicitud es segura.

json
{
  "type": "prompt",
  "prompt": "¿Este comando de bash es seguro? Comando: $ARGUMENTS\nResponde en JSON: {\"decision\": \"allow\"} o {\"decision\": \"deny\"}",
  "timeout": 30
}

Manejadores mcp_tool y agent: avanzados

mcp_tool llama una herramienta de un servidor MCP conectado. agent lanza un subagente para revisar (la documentación lo marca como experimental). Los dos son para escenarios complejos, no para empezar.


Matcher: el filtro de "a qué reaccionar"

🎨 Imagínalo así: el matcher es el filtro en la caseta. El guardia no detiene a todo el mundo, solo a quien carga cajas (Write|Edit). A los mensajeros los deja pasar sin revisar. Si no, la fila de entrada mediría cien metros.

El matcher define a qué herramientas CONCRETAS reaccionar. Sin matcher, el hook se dispara con TODO.

Valor de matcher Qué hace Ejemplo
"Bash" Solo comandos de bash El hook se dispara con npm test, git push
"Write|Edit" Escritura o edición de archivos Hook para revisar secretos
"mcp__memory__.*" Todas las herramientas del servidor MCP memory Auditoría de operaciones MCP
"*" o vacío Todas las herramientas Registro universal

El matcher es una expresión regular si tiene caracteres especiales, o una coincidencia exacta si solo tiene letras.

El filtro adicional "if" permite filtrar por argumentos (por ejemplo, Bash(git *) o Edit(*.ts)):

json
{
  "matcher": "Bash",
  "hooks": [{
    "type": "command",
    "if": "Bash(rm *)",
    "command": "echo 'rm bloqueado' >&2 && exit 2"
  }]
}

Aquí el hook se dispara solo para Bash, y solo si el comando empieza con rm. La sintaxis completa de if está en la referencia oficial de hooks.


Estructura de settings.json (formato oficial)

Todos los hooks viven en settings.json. Hay tres niveles de archivos:

Archivo Alcance ¿Se comparte?
~/.claude/settings.json Todos los proyectos (global) No
.claude/settings.json Este proyecto Sí (se sube a git)
.claude/settings.local.json Este proyecto (local) No (va en .gitignore)

Estructura: 3 niveles de anidación

Código
hooks → Evento → [{ matcher, hooks: [{ type, command, ... }] }]

Ejemplo completo con 3 hooks:

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-secrets.sh",
            "timeout": 30
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/audit-log.sh"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude terminó\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Reglas clave:

  • Los nombres de los eventos van en CamelCase: PreToolUse, no pre_tool_use
  • Cada evento contiene un arreglo de grupos con matcher y hooks
  • Cada grupo contiene un arreglo de manejadores hooks
  • matcher filtra por herramienta (para Stop/SessionStart no hace falta)
  • Puedes apagar todos los hooks: "disableAllHooks": true

Cómo recibe datos el hook (protocolo JSON)

Claude Code le pasa los datos al hook por stdin (en los hooks command) o en el cuerpo del POST (en los hooks http), en formato JSON.

Qué recibe un hook PreToolUse

json
{
  "session_id": "abc123",
  "cwd": "/Users/me/project",
  "hook_event_name": "PreToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/project/config.py",
    "content": "API_KEY = 'sk-proj-abc123...'"
  }
}

Qué recibe un hook PostToolUse

json
{
  "session_id": "abc123",
  "cwd": "/Users/me/project",
  "hook_event_name": "PostToolUse",
  "tool_name": "Bash",
  "tool_input": { "command": "npm test" },
  "tool_response": "All tests passed"
}

Qué recibe un hook SessionStart

json
{
  "session_id": "abc123",
  "cwd": "/Users/me/project",
  "hook_event_name": "SessionStart",
  "source": "startup",
  "model": "<identificador del modelo>"
}

Cómo le responde el hook a Claude Code (respuesta JSON)

El hook puede regresar un JSON por stdout para controlar el comportamiento:

json
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "permissionDecisionReason": "Comando seguro",
    "additionalContext": "Una pista para Claude"
  }
}

Decisiones para PreToolUse: "allow" (permitir sin preguntar), "deny" (bloquear), "ask" (preguntarle al usuario); en las versiones nuevas también existe "defer".

Si varios hooks dan decisiones distintas, la prioridad es: deny > ask > allow.

Exit codes: cómo comunica el hook su decisión

Exit code Resultado
0 Éxito. Claude Code interpreta stdout como JSON
2 Bloqueo. El stderr se le pasa a Claude como motivo
1 u otro Error no crítico: se anota en el registro y el trabajo sigue

Importante: el exit code 2 (¡no el 1!) bloquea la acción. El exit code 1 es solo un error: el hook "se rompió", pero Claude sigue trabajando.


Cómo agregar un hook: dos formas

Forma 1: pedírselo a Claude Code (recomendado para empezar)

Escribe esto en el chat
Quiero hacer un hook: cuando Claude termine una respuesta,
que me mande una notificación de macOS

Claude Code te hará preguntas para aclarar, creará el script de bash y agregará la entrada en settings.json.

Forma 2: con /hooks en la terminal

bash
claude
# Dentro de Claude Code:
/hooks
# Abre la lista de hooks configurados (solo para ver)
# Para editarlos, cambia settings.json directamente

Muestra los hooks actuales: el tipo de manejador ([command], [http], [prompt]), el origen ([User], [Project], [Local]) y el matcher.


Hooks globales vs de proyecto

🎨 Imagínalo así: los hooks globales son como las reglas de protección civil contra incendios. Valen en cualquier edificio al que entres. Los hooks de proyecto son como las instrucciones de un lugar concreto: "en esta bodega, además, revisa la temperatura".

Los hooks de seguridad (secretos, presupuesto) ponlos de forma global (~/.claude/settings.json). Te protegen en todos tus proyectos.

Los hooks propios de un proyecto (linter, pruebas, despliegue) ponlos en el proyecto (.claude/settings.json). Puedes subirlos a git y compartirlos con tu equipo.

Código
~/.claude/settings.json          ← Seguridad (todos los proyectos)
  └── PreToolUse: no-secrets
  └── PreToolUse: budget-check

.claude/settings.json            ← De proyecto (este proyecto)
  └── PostToolUse: run-linter
  └── Stop: run-tests

Todos los niveles se combinan. Los hooks globales + de proyecto + locales trabajan juntos.


Variables de entorno en los hooks

Dentro de un hook command tienes disponibles:

Variable Qué contiene
$CLAUDE_PROJECT_DIR La raíz del proyecto (¡ponla entre comillas!)
$CLAUDE_ENV_FILE La ruta para guardar variables de entorno durante toda la sesión

Ejemplo de uso:

bash
#!/bin/bash
# Ejecutar un script desde la carpeta del proyecto
"$CLAUDE_PROJECT_DIR"/.claude/hooks/my-check.sh

Práctica

Tarea: conocer la estructura de settings.json

  1. Abre o crea el archivo .claude/settings.json
  2. Pídele a Claude Code: Muéstrame la configuración actual de hooks
  3. Pídele que cree el hook más simple: Crea un hook: cuando Claude termine una respuesta, muestra la notificación "Listo", y presiona yes
  4. Comprueba que settings.json se actualizó: mira la entrada nueva en la sección Stop (¡CamelCase!)
  5. Pruébalo: hazle a Claude cualquier pregunta sencilla; debe aparecer la notificación
  6. Escribe /hooks en Claude Code y comprueba que el hook aparece en la lista

Objetivo: entender que settings.json es el punto único de configuración de todos los hooks, y que los hooks funcionan solos, sin que intervengas


Herramientas y recursos

  • .claude/settings.json: archivo de hooks del proyecto (se sube a git)
  • ~/.claude/settings.json: archivo global de hooks (todos los proyectos)
  • /hooks: comando para ver los hooks configurados en Claude Code
  • jq: herramienta para procesar JSON en scripts de bash (la necesitas para los hooks command)
  • osascript: comando de macOS para mandar notificaciones nativas
  • Documentación oficial (referencia vigente): https://code.claude.com/docs/en/hooks — todos los eventos del ciclo de vida, formatos JSON, exit codes
  • Eventos avanzados: la lección Hook-Deny-By-Design, con práctica de SubagentStop, PreCompact y PermissionRequest

Fuentes


Conclusiones clave

Hooks ≠ Skills. Los skills los llamas tú. Los hooks funcionan solos con un evento: los configuras una vez.

Hay unos 30 tipos de eventos, pero empieza con 4-6 principales: PreToolUse, PostToolUse, Stop, Notification, SessionStart, UserPromptSubmit.

5 tipos de manejadores: command (bash), http (webhook), mcp_tool, prompt (revisión con IA), agent (subagente). Para empezar, con command basta.

El matcher filtra por herramienta: "Write|Edit" solo operaciones con archivos, "Bash" solo comandos.

Exit code 2 = bloqueo, exit code 0 = permitir. ¡No el 1: el que bloquea es el 2!

Los hooks viven en settings.json en tres niveles: global, de proyecto y local. Todos se combinan.


Qué sigue

→ Hooks EN VIVO: construimos hooks desde cero

La marca se guarda solo en este navegador y no se envía a ningún sitio. Mi progreso