¿Qué son los hooks de Claude Code? Ejemplos y cuándo usarlos (2026)
Los hooks de Claude Code son comandos de shell (o llamadas HTTP/MCP) que configuras en settings.json y que se ejecutan automáticamente en momentos concretos de una sesión de Claude Code: por ejemplo, antes de que se ejecute una herramienta, después de editar un archivo o cuando Claude termina un turno. Los tres eventos centrales que necesita quien empieza son PreToolUse (puede bloquear comandos peligrosos), PostToolUse (formatea el código automáticamente) y Stop (envía una notificación de "hecho"). Como los hooks se ejecutan con todos tus permisos de usuario y sin sandbox, revísalos con cuidado antes de activarlos.
Claude Code avanza rápido, así que la lista de eventos no para de crecer.
¿Qué son los hooks en Claude Code?
Los hooks en Claude Code son comandos que defines de antemano y que Claude Code ejecuta automáticamente en puntos fijos del ciclo de vida de una sesión. En lugar de "recordarle" a Claude que haga algo y esperar que no se olvide, un hook convierte ese comportamiento en algo determinista: cuando llega el momento adecuado, se ejecuta, sin importar si al modelo "le apetece" o no.
Si alguna vez has usado Git hooks (como un pre-commit que ejecuta un linter antes de cada commit), esta idea te resultará familiar. La única diferencia es que estos hooks se enganchan al ciclo de vida de un agente de código con IA en lugar de a Git. Cuando Claude está a punto de ejecutar una herramienta, acaba de editar un archivo o termina un turno de respuesta, Claude Code comprueba si hay algún hook registrado para ese evento y lo ejecuta.
La mayor fortaleza de un hook es que es determinista y puede bloquear. Una línea en tu CLAUDE.md que diga "acuérdate de ejecutar Prettier tras editar archivos" es solo una sugerencia: el modelo puede olvidarla. En cambio, un hook PostToolUse ejecuta Prettier todas y cada una de las veces, sin excepción. Con PreToolUse, un hook puede incluso rechazar una acción antes de que ocurra; por ejemplo, bloqueando un rm -rf peligroso.
Esto convierte a los hooks en la herramienta central para automatizar Claude Code: formatear código, ejecutar pruebas, registrar actividad, enviar notificaciones o construir barreras de seguridad. En este artículo te muestro cómo funcionan los hooks a través de settings.json, tres ejemplos listos para copiar y pegar, cuándo deberías (y cuándo no) usarlos, y una sección de seguridad que la mayoría de las guías omite.
¿Cómo funcionan los hooks? (settings.json)
Los hooks se declaran en tu archivo settings.json, bajo la clave hooks. La estructura se anida en tres niveles: nombre del evento -> lista de matchers -> lista de hooks a ejecutar. Concretamente, eso es hooks > EventName > [{ matcher, hooks: [{ type, command }] }]. Aquí tienes un settings.json mínimo que de verdad funciona:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$CLAUDE_FILE_PATHS\""
}
]
}
]
}
}
Léelo de dentro hacia fuera: cuando se dispara el evento PostToolUse, Claude Code compara el matcher (Edit|Write) con el nombre de la herramienta que acaba de ejecutarse; si coincide, ejecuta cada command del array hooks.
Tres ámbitos de configuración: esto importa porque decide dónde se aplica un hook y si se termina subiendo a Git:
| Archivo | Ámbito | Git | Úsalo para |
|---|---|---|---|
~/.claude/settings.json | Toda la máquina (global) | No se sube | Hooks personales que quieres en todos los proyectos |
.claude/settings.json | Por proyecto | Se puede subir, compartido con el equipo | Hooks de proyecto compartidos (formatear, probar) |
.claude/settings.local.json | Por proyecto, solo tú | En .gitignore (por defecto) | Hooks sensibles con tokens/rutas privadas |
Los plugins también pueden traer sus propios hooks a través de su archivo hooks/hooks.json.
El campo type admite cinco clases: command (ejecuta un comando de shell, con diferencia el más común), http (llama a una URL), mcp_tool (llama a una herramienta en un servidor MCP; consulta también qué es MCP y cómo usarlo), prompt y agent. A lo largo de este artículo me centro en command porque está listo para copiar y pegar y cubre el 90% de lo que vas a necesitar. (Escribir bien la sintaxis de los hooks en settings.json es un requisito previo: un JSON inválido significa que el hook nunca se ejecuta, sin avisar.)
Los principales tipos de evento (ciclo de vida)
No necesitas memorizarlos todos. Para empezar, con el puñado de abajo cubres la mayoría de las situaciones:
| Evento | Se dispara cuando | ¿Puede bloquear? | Uso típico |
|---|---|---|---|
PreToolUse | Antes de que Claude ejecute una herramienta | Sí | Bloquear comandos peligrosos, forzar confirmación |
PostToolUse | Después de que una herramienta tiene éxito | No | Formatear código, ejecutar pruebas, registrar |
UserPromptSubmit | Cuando envías un prompt | Sí | Inyectar contexto, validar la entrada |
Stop | Cuando Claude termina un turno | No | Enviar una notificación de "hecho" |
SessionStart | Cuando se abre una nueva sesión | No | Cargar variables de entorno, registrar |
Notification | Cuando Claude emite una notificación | No | Redirigir notificaciones a otro canal |
Actualización de 2026 (información nueva): muchas guías antiguas todavía enumeran solo los cuatro eventos clásicos. En realidad, Claude Code tiene ahora más de 30 eventos de ciclo de vida, añadiendo otros como PostToolUseFailure, SubagentStart/SubagentStop, PreCompact/PostCompact, SessionEnd y más, según la documentación oficial de Anthropic (code.claude.com/docs/en/hooks, consultada el 2026-08-09). Pero tranquila: como principiante solo necesitas los 3 o 4 eventos centrales de arriba; el resto es para escenarios avanzados.
El matcher decide a qué herramienta se aplica un hook. Cuatro formas habituales: coincidir con una sola herramienta de forma exacta ("Bash"), coincidir con varias herramientas con una barra vertical ("Edit|Write"), una regex ("mcp__.*" para atrapar todas las herramientas MCP) y vacío o "*", que coincide con todo. Comparemos PreToolUse y PostToolUse en los ejemplos de abajo.
Ejemplo 1 — PreToolUse: bloquear comandos peligrosos
Este es el caso de uso más impresionante y también la barrera de seguridad más práctica. La idea: antes de que Claude ejecute cualquier comando Bash, un hook inspecciona el comando; si detecta un patrón peligroso como rm -rf, el hook lo rechaza y nunca deja que el comando se ejecute.
PreToolUse tiene dos formas de bloquear. La forma "limpia" es imprimir un JSON con un permissionDecision puesto a uno de tres valores: "allow" (ejecutarlo, saltándose el paso de confirmación), "deny" (bloquear del todo) o "ask" (forzar una confirmación). La forma rápida y sencilla es usar un código de salida: el script termina con exit 2 para bloquear, y en ese caso lo que hayas escrito en stderr se envía de vuelta a Claude para que sepa por qué se le bloqueó. La configuración:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/block-danger.sh"
}
]
}
]
}
}
Y el script .claude/hooks/block-danger.sh:
#!/usr/bin/env bash
# Read the JSON payload from stdin, pull out the command Claude wants to run
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command // empty')
if echo "$command" | grep -Eq 'rm[[:space:]]+-rf|git[[:space:]]+push[[:space:]]+--force'; then
echo "Blocked: command matches a dangerous pattern ($command)" >&2
exit 2 # exit 2 = block, stderr is sent back to Claude
fi
exit 0 # exit 0 = allow it to continue
El resultado: cuando Claude intenta ejecutar rm -rf build/, el hook lo atrapa, devuelve exit 2, el comando nunca se ejecuta y Claude recibe un mensaje que explica el porqué. Esto es exactamente lo que una regla de CLAUDE.md no puede garantizar: una regla es solo una sugerencia blanda, mientras que un hook es una barrera dura. Si quieres ajustar los permisos a un nivel más alto, lee más sobre permisos y configuración segura en Claude Code.
Ejemplo 2 — PostToolUse: formatear el código automáticamente
Uno de los primeros hooks que yo activo en cada proyecto: ejecutar el formateador automáticamente cada vez que Claude edita un archivo. Se acabaron los diffs desordenados por un espacio que falta o un salto de línea equivocado. Como este es PostToolUse (se ejecuta después de que la herramienta tiene éxito), no bloquea nada: solo hace la limpieza.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "cd \"${CLAUDE_PROJECT_DIR}\" && npx prettier --write \"$CLAUDE_FILE_PATHS\""
}
]
}
]
}
}
El matcher Edit|Write atrapa las dos herramientas de edición de archivos. Para un proyecto de Python, cambia el comando por black "$CLAUDE_FILE_PATHS" o ruff format. Algunas variables de entorno prácticas que Claude Code pasa a un hook:
${CLAUDE_PROJECT_DIR}: la ruta absoluta a la raíz del proyecto, para que el comando se ejecute en el directorio correcto.$CLAUDE_FILE_PATHS: la ruta (o rutas) del archivo o archivos que se acaban de tocar, para que formatees el archivo correcto en lugar de todo el repositorio.- También puedes leer siempre el payload JSON completo desde
stdin(como en el Ejemplo 1) para obtener los detalles detool_input.
Consejo: mantén el comando ligero y rápido. Un hook PostToolUse se ejecuta después de cada edición de archivo, así que un formateador lento ralentizará toda la sesión.
Ejemplo 3 — Stop: avisar cuando Claude termine
Cuando le encargas a Claude una tarea larga y te pones con otra cosa, es fácil olvidarte de volver a comprobar. Un hook Stop se ejecuta cuando Claude termina un turno de respuesta: perfecto para lanzar una notificación. Aquí tienes un ejemplo usando ntfy para enviar un aviso a tu móvil:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "curl -s -d \"Claude Code finished the task\" ntfy.sh/your-topic-name"
}
]
}
]
}
}
No hace falta ningún matcher porque Stop no está ligado a ninguna herramienta. En macOS puedes cambiarlo por osascript -e 'display notification "Done!" with title "Claude Code"'; en Linux usa notify-send. Pequeño, pero increíblemente práctico cuando haces malabares con varias cosas a la vez.
Cuándo deberías —y cuándo NO— usar un hook
Los hooks son potentes, pero no son la herramienta para todo. La línea es sencilla: los hooks son para cosas que deben ejecutarse siempre y son deterministas: formatear, probar, bloquear comandos, registrar. Si lo que necesitas es orientación de comportamiento o una capacidad, hay una herramienta más adecuada.
| Lo que quieres resolver | La herramienta correcta |
|---|---|
| Algo que debe ejecutarse cada vez, de forma determinista (formatear, probar, bloquear comandos) | Hook |
| Guiar el estilo o las convenciones de código de Claude | Una regla en CLAUDE.md |
| Una acción que tú misma lanzas cuando la necesitas | Slash commands en Claude Code |
| Empaquetar una capacidad reutilizable (instrucciones + scripts) | Skills en Claude Code |
Un ejemplo fácil de equivocar: "recordarle a Claude que siempre escriba pruebas" debería ser una regla en CLAUDE.md, no un hook, porque es orientación blanda. Pero "ejecutar toda la suite de pruebas tras editar archivos en src/" sí es un hook de verdad, porque es determinista. Si estos cuatro conceptos todavía te resultan borrosos, tengo un texto dedicado sobre en qué se diferencian skills, subagents, hooks y MCP: ahí es donde encaja el panorama completo.
⚠️ Notas de seguridad al usar hooks
Esta es la sección que la mayoría de las guías omite y, sin embargo, es la más importante. Según la documentación oficial (code.claude.com/docs/en/hooks, consultada el 2026-08-09): los hooks se ejecutan con todos los permisos de tu cuenta de usuario y SIN sandbox. Eso significa que un hook con errores —o uno malicioso que copiaste por accidente— puede borrar archivos, filtrar secretos o ejecutar código arbitrario en tu máquina, de forma totalmente automática y sin preguntar.
Algunos principios que sigo siempre:
- Lee cada hook con cuidado antes de habilitarlo, sobre todo los que vienen de un plugin, de un kit o del repositorio de otra persona. Trátalo como código que se ejecuta como root.
- Nunca dejes secretos escritos a fuego (tokens, claves de API) en un comando. Léelos desde variables de entorno en lugar de escribirlos en línea.
- Guarda los hooks sensibles en
.claude/settings.local.json(en .gitignore) para no subirlos por accidente a un repositorio compartido. - Conoce el interruptor de emergencia: usa
disableAllHookspara apagar todos los hooks mientras depuras o cuando algo parece sospechoso. Las empresas pueden restringir aún más conallowManagedHooksOnlyyallowedHttpHookUrls. - Ten cuidado con un
PreToolUseque hagaallowautomático: se salta el paso de confirmación, lo cual es cómodo, pero elimina una capa de protección.
En resumen: un hook es un cuchillo afilado. Muy útil, pero tienes que sujetarlo de la forma correcta. Consulta más problemas habituales y sus soluciones en la resolución de errores comunes de Claude Code.
Ir más rápido: hooks y skills ya hechos de un kit
Escribir tus propios hooks, scripts y skills para cada proyecto cuesta un esfuerzo real, sobre todo cuando quieres un conjunto coherente de barreras de seguridad y flujos de trabajo. Algunos kits para Claude Code, como el kit AgentKit para Claude Code, agrupan skills, subagents y flujos de trabajo para que no tengas que construirlo todo desde cero. Si quieres verlo directamente, puedes consultar los precios de AgentKit (20% de descuento por el enlace). Para que quede claro: los hooks básicos de este artículo los puedes construir tú misma y no necesitas comprar nada; un kit solo vale la pena considerarlo cuando quieres un conjunto entero ya hecho.
Depuración: ¿por qué no se ejecuta mi hook?
Un hook "silencioso" es el problema más habitual. Recorrer esta lista casi siempre encuentra la causa:
- ¿El JSON es válido? Una sola coma de más en
settings.jsony el archivo entero deja de cargarse. Pásalo por un validador de JSON. - ¿El matcher usa el nombre de herramienta correcto? Los nombres distinguen mayúsculas y minúsculas: es
Bash,Edit,Write, nobashniedit. - ¿El script devuelve el código de salida correcto?
exit 0para pasar,exit 2para bloquear (conPreToolUse). Otros códigos de salida pueden ignorarse. - ¿El stdout está "limpio"? Si el hook devuelve JSON de control, el stdout debe contener solo ese JSON; el texto suelto rompe el análisis.
- ¿El script es ejecutable? En macOS/Linux, acuérdate de
chmod +x. - ¿Está activado
disableAllHooks? Si desactivaste los hooks antes para depurar, no te olvides de volver a activarlos.
Preguntas frecuentes (FAQ)
¿En qué se diferencia un hook de un slash command y de una skill?
Un hook se ejecuta automáticamente en puntos del ciclo de vida (no lo llamas a mano). Un slash command es una acción que lanzas tú misma cuando la necesitas. Una skill es una capacidad empaquetada (instrucciones + scripts) que Claude carga por su cuenta cuando el contexto encaja. En resumen: hook = automático y determinista, slash command = manual, skill = una capacidad reutilizable.
¿Los hooks funcionan en Windows?
Sí. Como type: command ejecuta un comando de shell, puedes apuntarlo a un script de PowerShell (powershell -File .claude\hooks\block-danger.ps1) o usar Git Bash/WSL para ejecutar un script de bash. El comando solo tiene que ser válido en el shell de tu máquina.
¿Los hooks ralentizan Claude Code?
Pueden, si el comando es pesado. Los hooks se ejecutan de forma síncrona en el momento del evento, así que un formateador o una suite de pruebas lentos estirarán cada turno. Mantén los hooks ligeros, formatea solo el archivo que acaba de cambiar ($CLAUDE_FILE_PATHS) en lugar de todo el repositorio, y plantéate sacar las pruebas pesadas de PostToolUse.
¿Cuál es la diferencia entre hooks globales y de proyecto?
Un hook global (~/.claude/settings.json) se aplica a todos los proyectos de tu máquina y no se sube a Git. Un hook de proyecto (.claude/settings.json) se aplica solo a ese proyecto y se puede subir para que todo el equipo lo comparta. La variante .local.json es por proyecto pero está en .gitignore, para tu propia configuración privada.
¿Se pueden bloquear comandos peligrosos con un hook?
Sí, y ahí está justamente la fortaleza de PreToolUse. El hook inspecciona el comando antes de que se ejecute y lo rechaza con permissionDecision: "deny" o código de salida 2; por ejemplo, bloqueando rm -rf o git push --force (mira el Ejemplo 1 de arriba).
¿Son seguros los hooks?
Los hooks se ejecutan con todos tus permisos de usuario y sin sandbox, así que un hook con errores o malicioso puede hacer daño de verdad (borrar archivos, filtrar secretos). El mecanismo en sí es seguro si escribes y revisas tus hooks con cuidado; el riesgo viene de habilitar un hook desconocido sin leerlo. Trata siempre un hook como código que se ejecuta con los privilegios más altos.
Conclusión + próximos pasos
Domina los tres eventos centrales y podrás usar los hooks para casi todo lo que necesites: PreToolUse para bloquear comandos peligrosos, PostToolUse para formatear/probar automáticamente y Stop para que te avisen. Recuerda la regla de oro: los hooks se ejecutan con permisos totales y sin sandbox; revísalos con cuidado antes de habilitarlos. Para ir más allá, lee qué son las skills en Claude Code y los slash commands en Claude Code, o da un paso atrás para ver el panorama general sobre en qué se diferencian skills, subagents, hooks y MCP y cuándo usar cada uno.