Ruta del currículo
- CLAUDE.md Mastery — memoria del repo y reglas
- Effective Prompting — framing de tareas y restricciones
- MCP Power Tools — herramientas y contexto vivo
- Multi-Agent Workflows — delegación y ejecución en paralelo
- Hooks Automation — enforcement local del flujo de trabajo ← Estás aquí
- GitHub Actions Workflows — mover trabajo repetible a automatización de equipo
Documentación oficial usada en esta guía
- Lifecycle de hooks y configuración — Hooks
- Consideraciones de seguridad para scripts — Hooks
- Settings y configuración local — Settings
Por Qué Importan los Hooks
Claude Code se vuelve mucho más útil cuando deja de ser solo un editor inteligente y empieza a hacer cumplir automáticamente el flujo de trabajo del equipo.
Los hooks permiten ejecutar comandos alrededor del uso de herramientas y de eventos del ciclo de vida. Eso sirve para:
- formatear después de editar
- correr lint o tests antes de operaciones delicadas
- avisarte cuando termina una tarea larga
- bloquear cambios en rutas sensibles
- preservar contexto antes de compactar
El Ciclo de Vida de un Hook
Cada vez que Claude Code ejecuta una herramienta, ocurre este flujo:
Solicitud del usuario
↓
Se dispara PreToolUse ← bloquear o verificar aquí
↓
Se ejecuta la herramienta (Edit, Write, Bash, etc.)
↓
Se dispara PostToolUse ← post-procesar, formatear, notificar aquí
↓
Claude responde
Si un hook PreToolUse termina con un código de salida distinto de cero, la herramienta queda bloqueada por completo. Así es como funcionan los guardrails de protección de archivos.
Cómo Configurar los Hooks
Los hooks se registran en .claude/settings.json en la raíz del proyecto. Si el archivo no existe, créalo.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"command": ".claude/hooks/protect-files.sh"
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"command": ".claude/hooks/auto-format.sh"
}
],
"PreCompact": [
{
"matcher": ".*",
"command": ".claude/hooks/save-context.sh"
}
],
"Notification": [
{
"matcher": ".*",
"command": ".claude/hooks/notify-done.sh"
}
]
}
}- matcher: expresión regular que filtra qué herramientas activan el hook.
"Edit|Write"aplica tanto a Edit como a Write. - command: el comando de shell o ruta del script a ejecutar.
- Los scripts necesitan permiso de ejecución:
chmod +x .claude/hooks/tu-script.sh.
Ejemplos Prácticos de Hooks
1. Formatear automáticamente tras editar (PostToolUse)
Ejecuta Prettier de forma automática cada vez que se modifica un archivo. Este ejemplo aplica solo a archivos TypeScript y TSX.
#!/bin/bash
# .claude/hooks/auto-format.sh
FILE=$(echo "$CLAUDE_TOOL_INPUT" | jq -r '.file_path // empty')
# Salir silenciosamente si no hay ruta de archivo
[[ -z "$FILE" ]] && exit 0
# Aplicar Prettier solo a archivos TypeScript
if [[ "$FILE" == *.ts || "$FILE" == *.tsx ]]; then
npx prettier --write "$FILE" 2>/dev/null
echo "Formateado: $FILE"
fiLa variable de entorno CLAUDE_TOOL_INPUT contiene la entrada de la herramienta en formato JSON. Usa jq para extraer lo que necesitas.
2. Proteger archivos sensibles (PreToolUse)
Impide que Claude edite accidentalmente archivos .env, historial de migraciones o código generado.
#!/bin/bash
# .claude/hooks/protect-files.sh
FILE=$(echo "$CLAUDE_TOOL_INPUT" | jq -r '.file_path // empty')
# Lista de patrones de ruta a proteger
PROTECTED=(
".env"
".env.local"
".env.production"
"prisma/migrations"
"generated/"
"__generated__"
)
for pattern in "${PROTECTED[@]}"; do
if [[ "$FILE" == *"$pattern"* ]]; then
echo "BLOQUEADO: '$FILE' es un archivo protegido. Edítalo manualmente si es intencional." >&2
exit 1
fi
done
exit 0Salir con 1 detiene la herramienta. Salir con 0 permite que continúe.
3. Preservar contexto antes de compactar (PreCompact)
Cuando una conversación crece, Claude Code compacta el contenido antiguo. Guarda un snapshot antes de que eso pase para poder retomar donde lo dejaste.
#!/bin/bash
# .claude/hooks/save-context.sh
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
SAVE_DIR=".claude/snapshots"
mkdir -p "$SAVE_DIR"
# Escribir un snapshot del contexto
cat > "$SAVE_DIR/context-$TIMESTAMP.md" << EOF
# Snapshot de Contexto — $TIMESTAMP
## Estado de Git
$(git status --short 2>/dev/null || echo "sin git")
## Archivos modificados recientemente
$(git diff --name-only HEAD 2>/dev/null | head -20 || echo "ninguno")
## Notas
Guardado automáticamente antes de compactar.
EOF
echo "Contexto guardado en $SAVE_DIR/context-$TIMESTAMP.md"4. Notificación al completar una tarea (Notification)
No tienes que quedarte mirando la terminal todo el tiempo. Envía una notificación de escritorio cuando Claude termine.
#!/bin/bash
# .claude/hooks/notify-done.sh
# macOS
if command -v osascript &>/dev/null; then
osascript -e 'display notification "Claude Code terminó la tarea" with title "Claude Code" sound name "Glass"'
fi
# Linux (notify-send)
if command -v notify-send &>/dev/null; then
notify-send "Claude Code" "Tarea completada"
fiModelo Mental
Piensa en los hooks como guardrails dirigidos por eventos.
Usos de Alto Valor
- proteger
.env, migraciones o código generado - ejecutar lint o
tsctras ediciones - guardar estado antes de compactar
- mandar notificaciones al terminar tareas largas
Consejos de Depuración
Cuando un hook no se comporta como esperas, prueba lo siguiente.
1. Ejecutar el script por separado
# Simular la variable de entorno y ejecutar directamente
export CLAUDE_TOOL_INPUT='{"file_path": "src/app.ts"}'
bash .claude/hooks/auto-format.sh
echo "Código de salida: $?"2. Escribir logs en stderr
Usar >&2 dentro del script muestra la salida en el flujo de error de Claude Code.
echo "DEBUG: FILE=$FILE" >&23. Verificar los códigos de salida
Un código de salida distinto de cero en un hook PreToolUse bloquea la herramienta. Si Claude está siendo bloqueado sin razón aparente, revisa qué devuelve tu script.
4. Confirmar que jq está instalado
which jq || echo "jq no encontrado — brew install jq o apt install jq"Seguridad
Anthropic deja claro que los hooks ejecutan comandos arbitrarios en tu sistema.
Buenas prácticas:
- validar inputs
- usar rutas absolutas
- citar variables de shell
- bloquear path traversal
- evitar secretos y archivos sensibles
- probar primero en un entorno seguro
Referencia Completa de Eventos Hook
Aquí tienes una tabla con todos los tipos de eventos hook que soporta Claude Code.
| Evento | Momento | Caso de uso |
|---|---|---|
PreToolUse |
Antes de ejecutar la herramienta | Bloquear operaciones peligrosas, validar entradas |
PostToolUse |
Después de ejecutar la herramienta | Auto-formatear, lint, enviar notificaciones |
PreCompact |
Antes de comprimir el contexto | Guardar estado importante, crear snapshots |
PostCompact |
Después de comprimir el contexto | Restaurar contexto, re-inyectar reglas críticas |
Notification |
Cuando Claude envía una notificación | Alertas de escritorio, mensajes de Slack, efectos de sonido |
Stop |
Cuando Claude termina de responder | Limpieza de sesión, validación final, auto-guardado |
Puntos clave:
- Cada evento recibe diferentes variables de entorno
- Solo
PreToolUsepuede BLOQUEAR la ejecución (exit 1). El resto son solo advisory - Los patrones de matcher soportan regex:
"Edit|Write","Bash",".*"para todas las herramientas
Referencia de Variables de Entorno
Estas son las variables de entorno disponibles dentro de los scripts hook.
| Variable | Disponible en | Contenido |
|---|---|---|
CLAUDE_TOOL_NAME |
Todos los hooks | Nombre de la herramienta en uso (Edit, Write, Bash, etc.) |
CLAUDE_TOOL_INPUT |
Todos los hooks | JSON con los parámetros de la herramienta (file_path, command, etc.) |
CLAUDE_TOOL_OUTPUT |
Solo PostToolUse | JSON con el resultado de la ejecución |
CLAUDE_SESSION_ID |
Todos los hooks | Identificador de la sesión actual |
CLAUDE_PROJECT_DIR |
Todos los hooks | Ruta del directorio raíz del proyecto |
CLAUDE_MODEL |
Todos los hooks | Modelo actual (claude-sonnet-4-6, etc.) |
- Parsea las entradas JSON con
jq:echo "$CLAUDE_TOOL_INPUT" | jq -r '.file_path' - Siempre maneja variables faltantes con valores por defecto
Patrón PostCompact Hook
La compresión de contexto elimina el historial de conversación antiguo para liberar tokens. El problema es que las reglas o el contexto importante también pueden desaparecer.
El hook PostCompact se ejecuta después de la compresión y puede re-inyectar contexto crítico de vuelta a la conversación.
#!/bin/bash
# .claude/hooks/post-compact.sh
# Re-inyectar contexto crítico después de la compresión
cat << 'CONTEXT'
[Post-Compact Context Restoration]
- Current task: Review authentication module
- Important constraint: Do NOT modify database schema
- Active branch: feature/auth-refactor
- Files modified so far: src/auth/login.ts, src/auth/session.ts
CONTEXTRegístralo en settings:
{
"hooks": {
"PostCompact": [
{
"matcher": ".*",
"command": ".claude/hooks/post-compact.sh"
}
]
}
}- La salida de los hooks PostCompact se alimenta de vuelta a la conversación como contexto
- Mantenlo corto — una salida larga anula el propósito de la compactación
Flujo Multi-Hook: Pipeline CI Local
Combina múltiples hooks para construir un pipeline CI local completo. Cada vez que se edita un archivo, se ejecutan automáticamente la verificación de tipos, el linting y los tests.
#!/bin/bash
# .claude/hooks/local-ci.sh — Hook PostToolUse para Edit|Write
FILE=$(echo "$CLAUDE_TOOL_INPUT" | jq -r '.file_path // empty')
[[ -z "$FILE" ]] && exit 0
ERRORS=""
# Paso 1: Verificación de tipos TypeScript (solo para archivos .ts/.tsx)
if [[ "$FILE" == *.ts || "$FILE" == *.tsx ]]; then
if ! npx tsc --noEmit --pretty 2>/tmp/tsc-output.txt; then
ERRORS+="TypeScript errors found:\n$(cat /tmp/tsc-output.txt)\n\n"
fi
fi
# Paso 2: Verificación ESLint
if [[ "$FILE" == *.ts || "$FILE" == *.tsx || "$FILE" == *.js ]]; then
if ! npx eslint "$FILE" --quiet 2>/tmp/eslint-output.txt; then
ERRORS+="ESLint issues:\n$(cat /tmp/eslint-output.txt)\n\n"
fi
fi
# Paso 3: Ejecutar tests relacionados
TEST_FILE="${FILE%.ts}.test.ts"
if [[ -f "$TEST_FILE" ]]; then
if ! npx jest "$TEST_FILE" --silent 2>/tmp/test-output.txt; then
ERRORS+="Test failures:\n$(cat /tmp/test-output.txt)\n\n"
fi
fi
# Reportar resultados
if [[ -n "$ERRORS" ]]; then
echo "⚠ Local CI found issues:" >&2
echo -e "$ERRORS" >&2
else
echo "✓ Local CI passed: types, lint, tests" >&2
fi
exit 0 # No bloquear — solo reportarPuntos clave:
- Se ejecuta automáticamente después de cada edición de archivo
- Reporta via stderr para que Claude vea el feedback
- exit 0 significa advisory — Claude ve las advertencias pero no se bloquea
- Cambia a exit 1 en PreToolUse si quieres hacerlo obligatorio
Configuración completa de settings.json para el pipeline:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"command": ".claude/hooks/protect-files.sh"
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"command": ".claude/hooks/auto-format.sh"
},
{
"matcher": "Edit|Write",
"command": ".claude/hooks/local-ci.sh"
}
],
"PreCompact": [
{
"matcher": ".*",
"command": ".claude/hooks/save-context.sh"
}
],
"PostCompact": [
{
"matcher": ".*",
"command": ".claude/hooks/post-compact.sh"
}
],
"Notification": [
{
"matcher": ".*",
"command": ".claude/hooks/notify-done.sh"
}
]
}
}Hooks vs CLAUDE.md
| Herramienta | Mejor para |
|---|---|
CLAUDE.md |
reglas, arquitectura y convenciones |
| hooks | enforcement automático |
| prompt | la tarea de hoy |
Claude Code vs Codex
Codex suele apoyarse más en sandbox y approvals. Claude Code hooks se apoya más en automatización local basada en eventos.