Hooks de Claude Code: automatiza tu flujo de trabajo
Llevar Claude Code de "chat de código" a "parte integrada del workflow" requiere una pieza que pocos descubren al principio: los hooks. Son scripts que se ejecutan en puntos concretos del ciclo del agente — antes de ejecutar una tool, después de cada edición, al recibir un prompt nuevo — y permiten intervenir sin tener que pedírselo al modelo.
Si has usado git hooks alguna vez, la idea es similar: el agente dispara eventos, tú cuelgas shell scripts en ellos. Bien usados, los hooks resuelven tres problemas clásicos de trabajar con un agente de código:
Seguridad: bloquear comandos peligrosos o modificar parámetros antes de ejecutarlos.
Convenciones: formatear código automáticamente, forzar patrones de commit, añadir headers.
Contexto: inyectar información del proyecto antes de cada prompt.
Este artículo es un despiece técnico. Forma parte del cluster sobre cómo funciona Claude Code por dentro, junto con los análisis del loop agéntico, permisos con ML y subagentes.
Qué son los hooks exactamente
Un hook en Claude Code es un comando shell que se ejecuta cuando el agente emite un evento concreto. Se configuran en JSON en ~/.claude/settings.json (globales) o .claude/settings.json (específicos del proyecto).
Cuando el evento se dispara, Claude Code:
Envía al hook un JSON por stdin con todo el contexto del evento (qué tool, qué input, qué output).
Espera la respuesta del hook por stdout.
Según el exit code y el JSON devuelto, decide si continúa, bloquea o modifica la acción.
La documentación oficial vive en code.claude.com/docs/en/hooks.
Los 12 eventos disponibles
Claude Code define 12 eventos. Los más usados en la práctica son seis:
|
Evento |
Cuándo dispara |
Uso típico |
|---|---|---|
|
|
Antes de ejecutar una tool |
Validar, bloquear, modificar input |
|
|
Después de una tool exitosa |
Formatear, testear, log |
|
|
Al enviar un prompt |
Inyectar contexto, filtrar |
|
|
Al arrancar una sesión |
Cargar variables de entorno |
|
|
Al cerrar sesión |
Guardar resumen, limpiar |
|
|
Cuando el agente detiene generación |
Métricas, notificaciones |
El resto (SubagentStop, PreCompact, Notification, Error, etc.) se usan menos pero cubren casos específicos.
Anatomía de un hook
Todos los hooks siguen el mismo contrato:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash /Users/yo/.claude/hooks/validate-bash.sh"
}
]
}
]
}
}Matcher: regex contra el nombre de la tool.
Bashsolo matchea BashTool;Bash|Editmatchea ambos;.*matchea todos.Type:
command(ejecuta shell) es el habitual.Command: la ruta al script o comando inline a ejecutar.
Patrón 1: PreToolUse para bloquear comandos peligrosos
El caso más frecuente: no quieres que el agente ejecute rm -rf, sudo o comandos que toquen producción, ni aunque tú le digas "procede".
#!/bin/bash
# ~/.claude/hooks/validate-bash.sh
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command // ""')
if echo "$command" | grep -qE '^(rm -rf /|sudo rm|:(){ :|:& };:|dd if=)'; then
echo '{"decision": "block", "reason": "Comando bloqueado por política de seguridad"}'
exit 0
fi
exit 0Recibe el JSON por stdin con
tool_input.commandsiendo el comando bash.Si matchea un patrón peligroso, devuelve un JSON con
decision: blocky razón.Claude Code muestra la razón al usuario y no ejecuta.
Desde Claude Code v2.0.10, los hooks PreToolUse pueden también modificar el input en vez de bloquearlo: devuelves un JSON con el tool input corregido y el agente procede con la versión segura. Útil para añadir flags (--dry-run), corregir rutas, o forzar ejecución en sandbox.
Relacionado: el sistema de permisos con ML de Claude Code ya clasifica comandos bash por riesgo, pero los hooks son la palanca para añadir tus propias reglas corporativas encima.
Patrón 2: PostToolUse para formatear código automáticamente
Cada vez que el agente edita un archivo, quieres que quede formateado según convenciones del equipo. En vez de explicarle la regla en el prompt, hook:
#!/bin/bash
# ~/.claude/hooks/format-on-edit.sh
input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path // ""')
if [[ "$file_path" == *.ts || "$file_path" == *.tsx ]]; then
bunx prettier --write "$file_path" 2>/dev/null
elif [[ "$file_path" == *.py ]]; then
ruff format "$file_path" 2>/dev/null
fi
exit 0Configuración:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "bash ~/.claude/hooks/format-on-edit.sh" }]
}
]
}
}Ventaja frente a pedírselo al modelo: ocurre siempre, consistente, sin gastar tokens. El modelo escribe el código y el hook lo deja bonito sin que el modelo tenga que saber Prettier o Ruff.
Patrón 3: UserPromptSubmit para inyectar contexto
Cada proyecto tiene piezas de contexto que quieres recordarle al agente en cada prompt: el stack, las convenciones, dónde está la doc. Puedes meterlo en CLAUDE.md (que Claude Code carga automáticamente) o, si es más dinámico, en un hook:
#!/bin/bash
# ~/.claude/hooks/inject-project-context.sh
input=$(cat)
prompt=$(echo "$input" | jq -r '.user_prompt')
git_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
uncommitted=$(git status --porcelain 2>/dev/null | wc -l)
context="[Contexto del proyecto]
- Branch actual: $git_branch
- Cambios sin commitear: $uncommitted archivos
- Último commit: $(git log -1 --oneline 2>/dev/null)"
echo "{\"additional_context\": $(echo "$context" | jq -Rsa .)}"Esto inyecta info al system prompt sin consumir tu bandwidth de escritura. El agente siempre sabe en qué branch estás, cuánto tienes pendiente y qué commits recientes hay.
Contención importante: no abuses. Cada byte de contexto extra es tokens que pagas. Inyecta solo lo que de verdad aporta.
Patrón 4: Stop con notificación
Si Claude Code está corriendo una tarea larga (un refactor multi-archivo, un test suite), queremos saber cuándo termina sin mirar la terminal:
#!/bin/bash
# ~/.claude/hooks/notify-stop.sh
# Mac
osascript -e 'display notification "Claude Code terminó" with title "Ready"'
# Linux
# notify-send "Claude Code" "Terminó"
# Slack
# curl -X POST -H 'Content-type: application/json' \
# --data "{\"text\":\"Claude Code terminó\"}" \
# "$SLACK_WEBHOOK_URL"
exit 0Configurado como Stop hook. Sin matcher — se dispara siempre que el agente pare de generar.
Patrón 5: SessionStart para cargar secretos
Si tu workflow usa variables de entorno sensibles (tokens de API, credenciales de staging) que no quieres en .env sin cifrar:
#!/bin/bash
# ~/.claude/hooks/load-secrets.sh
# 1Password CLI, pass, o keychain nativo
SECRETS=$(op read "op://Private/claude-code/dev-env")
echo "{\"environment\": $(echo "$SECRETS" | jq -Rsa .)}"Al arrancar sesión, Claude Code recibe las variables y las usa durante la sesión. Las claves nunca tocan disco sin cifrar.
Cómo configurar hooks en la práctica
Paso 1: crear el directorio de hooks
mkdir -p ~/.claude/hooksPaso 2: escribir el script
Crea un .sh y dale permisos:
chmod +x ~/.claude/hooks/mi-hook.shPaso 3: registrarlo en settings.json
Edita ~/.claude/settings.json (para todos los proyectos) o .claude/settings.json (para uno):
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "bash ~/.claude/hooks/mi-hook.sh" }
]
}
]
}
}Paso 4: probarlo
Abre Claude Code, pídele algo que dispare el evento (un comando bash para PreToolUse), y observa que el hook se ejecuta.
Si el hook falla, Claude Code muestra el error. Si devuelve exit code 2, el tool se bloquea. Si exit 0 con decision: block en JSON, también se bloquea con razón.
Debugging de hooks
El hook no se ejecuta
Verifica que el archivo tiene
chmod +x.Verifica el matcher:
BashmatcheaBashTool, nobash.Revisa la sintaxis JSON en settings.json con
jq .para asegurar que parsea.
El hook se ejecuta pero no hace lo esperado
Añade logging al script:
echo "[$(date)] Hook triggered with input:" >> /tmp/claude-hooks.log
tee -a /tmp/claude-hooks.logY tail el log en otra terminal mientras pruebas.
El hook rompe la experiencia
Si un hook es lento (>500ms) lo notarás en cada interacción. Mídelo con time y si pesa, cámbialo a asíncrono (dispara el hook pero no espera resultado).
Patrones avanzados
Logging a un sistema externo
Enviar cada tool use a tu stack de observabilidad (Grafana, Datadog):
#!/bin/bash
input=$(cat)
curl -s -X POST "$OTEL_ENDPOINT" \
-H "Content-Type: application/json" \
-d "$input" &
exit 0Fíjate en el & — dispara y olvida para no bloquear.
Hooks por proyecto con convenciones distintas
En .claude/settings.json de cada repo puedes sobrescribir. Por ejemplo, un proyecto Python aplica ruff al PostToolUse, uno TypeScript aplica prettier, y uno Go aplica gofmt. El agente solo sabe escribir código; el hook garantiza el estilo.
Hooks que dialogan con subagentes
Combinando subagentes con hooks, puedes hacer que un SubagentStop dispare un lint + test + reporte, y si falla, automáticamente invoque otro subagente para arreglarlo. Es la base de workflows agénticos "auto-reparables".
Cuándo NO usar hooks
Hooks no son la solución a todo. Evítalos cuando:
El comportamiento debe ser autoritativo para el modelo: si quieres que el modelo sepa que no debe usar
varen JS, ponlo en elCLAUDE.md. El hook solo corrige post-hoc, no enseña.La lógica es compleja y cambiante: un hook que requiere mantenimiento constante es deuda. Mejor resolverlo en el prompt o en un MCP server dedicado.
Necesitas conversación bidireccional: un hook no puede "preguntar" al usuario. Para eso, MCP tools o permisos.
El ecosistema de hooks
Existe una comunidad activa compartiendo hooks reutilizables. Patrones que ya no necesitas escribir desde cero:
Bloquear edición de archivos en rutas sensibles.
Auto-commit después de cada edición con mensaje generado.
Ejecutar tests del archivo tocado después de cada Edit.
Validar que el código nuevo no rompa linter antes de continuar.
Redactar secretos antes de enviarlos a logs.
Copiar y adaptar es lo normal aquí; la mayoría de hooks útiles caben en 20 líneas.
Conclusión
Los hooks son la diferencia entre "Claude Code es un chat listillo" y "Claude Code es parte integrada de mi workflow". Tres o cuatro hooks bien pensados — validador de bash, formatter post-edit, inyector de contexto de proyecto, notificación al terminar — cambian la experiencia completamente sin gastar un token más.
Si estás evaluando llevar Claude Code al nivel profesional, empieza por el bloqueador de comandos peligrosos. Es el que más seguridad añade con menos esfuerzo. Después escala hasta donde tu workflow lo justifique.
Para seguir:
Cómo funciona Claude Code por dentro — pillar con el panorama completo.
Configurar MCP en Claude Code CLI — el otro mecanismo de extensión.
Subagentes de Claude Code — complemento natural a los hooks.
Fuentes verificadas
Documentación oficial de hooks: code.claude.com/docs/en/hooks.
PreToolUse modifica tool inputs desde v2.0.10: confirmado en docs oficiales.
Lista de 12 eventos: pixelmojo.io/blogs/claude-code-hooks-production-quality-ci-cd-patterns.
Repo de comunidad: github.com/disler/claude-code-hooks-mastery.
Datos verificados el 23 de abril de 2026.



