Los hooks de Claude Code son comandos (o llamadas HTTP, prompts y algunos otros tipos de handler) que Claude Code ejecuta automáticamente en momentos concretos de una sesión, como antes de que se ejecute una herramienta, cuando hace falta un permiso o cuando Claude termina de responder. Se definen bajo la clave hooks en un archivo de configuración como ~/.claude/settings.json. Cada hook recibe por stdin un JSON con información del evento y puede responder con su código de salida o con un objeto JSON por stdout, lo que le permite registrar, notificar, bloquear una acción o responder por ti.
01Cómo se estructura un hook
La configuración de un hook tiene tres niveles:
- El evento del hook, como
PreToolUseoStop. - Un grupo de matcher, que filtra cuándo se dispara, por ejemplo "solo para la herramienta Bash".
- Uno o más handlers del hook, que es lo que realmente se ejecuta.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "/path/to/lint-check.sh"
}
]
}
]
}
}
Esto ejecuta un script de lint después de que Claude escriba o edite un archivo. Para añadir otro evento, agrega una clave hermana dentro del mismo objeto hooks.
02Dónde se definen los hooks
~/.claude/settings.jsonTodos tus proyectosNo, solo en tu máquina.claude/settings.jsonUn proyectoSí, se puede hacer commit.claude/settings.local.jsonUn proyectoNohooks/hooks.json de un pluginMientras el plugin esté activadoSíLos hooks de distintos archivos se suman en lugar de reemplazarse. Escribe /hooks en Claude Code para ver todos los hooks activos y de dónde viene cada uno.
En una sesión interactiva, Claude Code no ejecuta ningún hook, ni siquiera los tuyos, hasta que aceptes el diálogo de confianza del workspace para esa carpeta.
03Tipos de handler
La mayoría de los hooks son "type": "command", que ejecuta un comando de shell. Hay otros cuatro:
http: envía por POST el JSON del evento a una URL y lee el cuerpo de la respuesta.mcp_tool: llama a una herramienta de un servidor MCP que tengas configurado.prompt: le hace una pregunta de un solo turno a un modelo de Claude y lee una decisión en JSON.agent: lanza un subagente que puede leer archivos antes de decidir (experimental).
Los hooks de comando se ejecutan con todos tus permisos de usuario, mediante sh -c en macOS y Linux, y con Git Bash (o PowerShell) en Windows. Añade "async": true para ejecutar uno en segundo plano; eso sí, ya no podrá tomar decisiones.
04Matchers
El matcher decide qué ocurrencias de un evento ejecutan el hook. Con qué se compara depende del evento: el nombre de la herramienta en los eventos de herramientas, el tipo de notificación en Notification, cómo se inició la sesión en SessionStart, etc.
"*",""o no poner matcher coincide con todo.- Las letras, dígitos,
_,-, espacios,|y,se tratan como nombres exactos.Edit|Writecoincide con cualquiera de las dos herramientas. - Cualquier otra cosa se interpreta como una expresión regular de JavaScript, así que
mcp__memory__.*coincide con todas las herramientas de un servidor MCP.
Los matchers distinguen mayúsculas y minúsculas. Algunos eventos, como Stop y UserPromptSubmit, ignoran los matchers. En los eventos de herramientas, un campo if con una regla de permisos como "Bash(git *)" restringe aún más un handler concreto.
05Entrada: lo que recibe tu hook
Cada hook recibe por stdin un JSON con algunos campos comunes, como session_id, transcript_path, cwd y hook_event_name, además de campos específicos del evento. Por ejemplo, un hook PreToolUse para una llamada a Bash también recibe tool_name y tool_input.command. Léelo con jq o con cualquier parser de JSON:
#!/bin/bash
input=$(cat)
cmd=$(jq -r '.tool_input.command // empty' <<<"$input")
echo "Claude wants to run: $cmd" >> ~/claude-commands.log
exit 0
06Salida: códigos de salida y JSON
Un hook puede responder de dos formas.
Códigos de salida. 0 significa éxito. 2 es un error bloqueante: en los eventos que pueden bloquear, la acción se detiene y tu stderr pasa a ser el motivo. Cualquier otro código, incluido el típico 1, es un error no bloqueante, así que la acción sigue adelante y ves un aviso de error del hook. Si un hook tiene que imponer una regla, sal con 2, no con 1.
JSON en stdout. Sal con 0 e imprime un único objeto JSON para tener un control más fino. Algunos campos funcionan en todos los eventos, como continue: false para detener Claude por completo. Otros dependen del evento: Stop usa decision: "block" con un reason, mientras que PreToolUse y PermissionRequest ponen su decisión dentro de hookSpecificOutput. No imprimas nada más en stdout: una línea suelta de tu perfil de shell hace que Claude Code no pueda leer el JSON.
07Todos los eventos de hook
SessionStartSe inicia o se reanuda una sesiónNo (añade contexto)SetupSe inicia con --init-only, o con --init / --maintenance junto a -pNoInstructionsLoadedSe carga un archivo CLAUDE.md o .claude/rules/*.mdNoUserPromptSubmitEnvías un prompt, antes de que Claude lo veaSíUserPromptExpansionUn comando escrito se expande en un promptSíPreToolUseAntes de cualquier llamada a una herramientaSíPermissionRequestUna llamada a una herramienta necesita una decisión de permisosPermite o deniega mediante JSONPermissionDeniedEl modo automático deniega una llamada a una herramientaNoPostToolUseDespués de que una llamada a una herramienta termina bienNo (la herramienta ya se ejecutó)PostToolUseFailureDespués de que falla una llamada a una herramientaNoPostToolBatchTras un lote de llamadas a herramientas en paralelo, antes de la siguiente llamada al modeloSíNotificationClaude Code envía una notificaciónNoMessageDisplayMientras se muestra el texto de la respuesta de ClaudeNo (puede cambiar lo que se muestra)SubagentStart / SubagentStopUn subagente empieza o terminaSolo SubagentStopTaskCreated / TaskCompletedSe crea una tarea o se marca como completadaSíStopClaude termina de responderSí (hace que Claude siga)StopFailureEl turno termina con un error de la APINoTeammateIdleUn compañero de un equipo de agentes está a punto de quedarse inactivoSíConfigChangeCambia un archivo de configuración durante una sesiónSíCwdChangedCambia el directorio de trabajoNoDirectoryAddedSe añade un directorio con /add-dirNoFileChangedCambia en disco un archivo vigiladoNoWorktreeCreate / WorktreeRemoveSe crea o se elimina un worktreeSíPreCompact / PostCompactAntes y después de compactar el contextoSolo PreCompactPreModelSwitch / PostModelSwitchAntes y después de cambiar el modeloSolo PreModelSwitchElicitation / ElicitationResultUn servidor MCP te pide datos, y después de que respondesSíSessionEndTermina una sesiónNoAnthropic añade eventos de vez en cuando, así que consulta la referencia de hooks para ver la lista actual y los campos de entrada de cada evento.
08Qué eventos importan para las notificaciones
Cuatro eventos cubren casi todo lo que la gente quiere que se le avise:
Stoppara "Claude ha terminado". Consulta la guía del Stop hook.Notificationpara "Claude te está esperando", con tipos comopermission_prompteidle_prompt. Consulta la guía del Notification hook.PermissionRequestpara enterarte, o responder, en el momento en que se necesita un permiso. Consulta la guía de PermissionRequest.PreToolUseen la herramientaAskUserQuestion, para ver o responder las preguntas de opción múltiple de Claude. Consulta cómo responder preguntas desde el móvil.
Para una configuración de escritorio lista para pegar, empieza por cómo recibir una notificación cuando Claude Code termina.
09Dónde encaja Claude Code Notifier
Claude Code Notifier está construido por completo sobre estos hooks. Su herramienta de línea de comandos gratuita, ccn, funciona en Mac, Windows y Linux. Al instalarla se añaden siete entradas de hook a ~/.claude/settings.json, cada una ejecutando ccn hook, y se guarda una copia de seguridad única del archivo. ccn se ejecuta unos milisegundos por evento y luego termina, así que nada queda corriendo.
Por sí sola muestra notificaciones de escritorio. Con la app de iPhone o Android vinculada, los mismos hooks llevan tus respuestas de vuelta: permitir o denegar un permiso, responder una pregunta o enviar la siguiente instrucción cuando Claude se detiene. Es independiente y no la hace Anthropic. Si solo necesitas un log o un paso de lint, unas pocas líneas propias son más sencillas. Tienes los detalles en la página de ccn.
10Preguntas frecuentes
¿Cómo pruebo un hook sin esperar a Claude?
Pásale JSON de ejemplo al script por una tubería y revisa el código de salida: echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh; echo $?. Luego ejecuta /hooks en Claude Code para confirmar que está registrado en el evento correcto.
¿Por qué no se ejecuta mi hook?
Las causas habituales son JSON no válido en settings.json (comas finales, comentarios), un matcher que no coincide exactamente (distinguen mayúsculas y minúsculas), un script sin permisos de ejecución o una carpeta en la que aún no has confiado. Inicia Claude Code con claude --debug y lee el log de depuración para ver qué se ejecutó. La lista completa está en la lista de comprobación para solucionar problemas.
¿Cómo desactivo todos los hooks durante un tiempo?
Pon "disableAllHooks": true en un archivo de configuración. Para omitirlos en una sola ejecución, inicia Claude Code con --settings '{"disableAllHooks": true}'. No hay un interruptor para un solo hook; en su lugar, elimina su entrada. Ninguna de las dos opciones desactiva los hooks que tu organización haya definido en la configuración gestionada.
¿Cuál es el timeout predeterminado de un hook?
Diez minutos (600 segundos) para hooks de comando, HTTP y herramientas MCP, 30 segundos para hooks de prompt y 60 para hooks de agente. Algunos eventos usan valores más cortos, y puedes definir timeout en segundos en cualquier handler.