
Claude Code Hooks: La Guía Completa para Desarrolladores con Ejemplos Listos para Producción
Claude Code es excelente escribiendo código, pero sigue siendo un sistema probabilístico. Puedes pedirle que ejecute Prettier después de cada edición de archivo. Puedes poner esa instrucción en tu CLAUDE.md. Y a veces... simplemente lo olvida. Los hooks de Claude Code resuelven esto dándote un control determinístico y garantizado sobre lo que ocurre antes, durante y después de cada acción que Claude realiza.
Llevo meses configurando hooks en decenas de proyectos y se han convertido silenciosamente en la parte más importante de mi configuración de Claude Code. Esta guía cubre todo, desde los conceptos básicos hasta un kit de inicio listo para producción que puedes añadir a cualquier proyecto hoy mismo. Si ya has usado Claude Code junto a herramientas como Cursor o Copilot, sabes el valor de la personalización -- los hooks van un paso más allá.
¿Qué Son los Hooks de Claude Code (y Por Qué Deberían Importarte)?
Los hooks de Claude Code son comandos de shell, endpoints HTTP o prompts de LLM definidos por el usuario que se ejecutan automáticamente en puntos específicos del ciclo de vida de Claude Code. Según la documentación oficial de Anthropic, a diferencia de las instrucciones en prompts que Claude podría ignorar, los hooks se disparan de forma determinística cada vez -- dándote control garantizado sobre el formateo, la seguridad, las notificaciones y la automatización del flujo de trabajo.
El Problema Probabilístico
La cuestión con las instrucciones en CLAUDE.md es esta: son sugerencias, no contratos. Puedes escribir "ejecuta siempre npx prettier --write después de editar archivos TypeScript" en el contexto de tu proyecto, y Claude lo seguirá la mayor parte del tiempo. Pero "la mayor parte del tiempo" no es suficiente cuando estás aplicando un formato de código en todo un equipo, o bloqueando pushes a producción, o registrando cada comando de shell para una auditoría de seguridad.
Aquí está la tensión central de cualquier herramienta de programación con IA. Claude es un modelo de lenguaje -- opera con probabilidades. Tu context engineering puede influir en el comportamiento, pero no puede garantizarlo.
Cómo los Hooks Resuelven Esto
Los hooks se saltan el LLM por completo. Son scripts de shell, llamadas HTTP o evaluaciones de IA que se disparan en eventos específicos del ciclo de vida -- antes de que se ejecute una herramienta (PreToolUse), después de que se complete (PostToolUse), cuando aparece una notificación, cuando comienza una sesión, o cuando Claude se detiene. Piensa en ellos como los hooks de Git, pero para tu asistente de programación con IA.
Existen cuatro tipos de hook: command (scripts de shell), HTTP (peticiones POST via webhook), prompt (evaluaciones de sí/no de Claude en un solo turno) y agent (lanza un subagente con acceso a herramientas). Más adelante desglosaremos cada uno -- los hooks de tipo command cubren aproximadamente el 90% de lo que necesitarás.
Cómo Funcionan los Hooks de Claude Code: El Flujo del Ciclo de Vida
Los hooks de Claude Code se ejecutan en un ciclo de vida definido: se dispara un evento (p. ej., PreToolUse), el matcher comprueba si el hook aplica, el script del hook se ejecuta y recibe JSON por stdin, y el código de salida determina qué ocurre a continuación. El código de salida 0 significa continuar, el código de salida 2 significa bloquear la acción. Este flujo es el mismo independientemente del tipo de hook que estés usando.
Evento -> Matcher -> Hook -> Código de Salida (El Flujo de 4 Pasos)
Así funciona cada ejecución de hook:
1. SE DISPARA EL EVENTO p. ej., PreToolUse(Write)
|
2. EL MATCHER COMPRUEBA ¿"Write" coincide con el patrón del hook?
|
3. SE EJECUTA EL HOOK El script de shell se ejecuta, recibe JSON por stdin
|
4. EL CÓDIGO DE SALIDA DECIDE 0 = continuar | 2 = bloquear | otro = errorEl JSON que llega por stdin contiene todo sobre el evento: el tool_name, el tool_input (ruta del archivo, contenido, comando) y los metadatos de la sesión. Tu script lee este JSON, aplica la lógica que necesite y sale con el código apropiado.
Para los hooks PreToolUse, el código de salida 2 es el poderoso -- bloquea la acción por completo y envía tu mensaje de stdout de vuelta a Claude como feedback. Claude ve tu mensaje y puede ajustar su enfoque.
Ámbitos de Configuración: Usuario, Proyecto y Local
Los hooks viven en settings.json en tres niveles:
| Ámbito | Archivo | ¿Se sube a Git? | Caso de uso |
|---|---|---|---|
| Usuario | ~/.claude/settings.json | No | Configuración personal (notificaciones, preferencias de formateo) |
| Proyecto | .claude/settings.json | Sí | Hooks compartidos del equipo (protección de archivos, tests, linting) |
| Local | .claude/settings.local.json | No (en .gitignore) | Ajustes personales para este proyecto |
La configuración de proyecto es la más útil para equipos. Pon tus hooks en .claude/settings.json, súbelos al repositorio, y cada desarrollador del equipo obtiene las mismas restricciones automáticamente.
El Campo if: Filtrado de Grano Fino
Desde Claude Code v2.1.85, los hooks soportan un campo if que permite filtrar por argumentos de herramienta -- no solo por nombres de herramienta. Como se documenta en la referencia de hooks de Anthropic, esto significa que puedes escribir un hook que solo se dispare en comandos Bash que coincidan con git push, en lugar de dispararse en cada invocación de Bash.
{
"matcher": "Bash",
"if": "tool_input.command matches 'git push'",
"hooks": [{ "type": "command", "command": "./scripts/check-branch.sh" }]
}Esto fue un cambio de juego. Antes del campo if, o hacías coincidir demasiado (todos los comandos Bash) o hacías el filtrado dentro de tu script (engorroso).
Todos los Eventos de Hooks de Claude Code: Tabla de Referencia Rápida
Claude Code proporciona más de 20 eventos de hook a lo largo de su ciclo de vida, como se documenta en la referencia oficial de hooks y el changelog de Claude Code. Los más utilizados son PreToolUse, PostToolUse, Notification y Stop -- pero los eventos más recientes como ConfigChange y FileChanged abren patrones de automatización avanzados.
Aquí está la referencia completa:
| Evento | Cuándo se dispara | ¿Puede bloquear? | Caso de uso común |
|---|---|---|---|
| PreToolUse | Antes de que se ejecute una herramienta | Sí (exit 2) | Bloquear comandos peligrosos, proteger archivos |
| PostToolUse | Después de que una herramienta se complete | No | Auto-formateo, ejecutar tests, registrar acciones |
| Notification | Cuando Claude envía una notificación | No | Alertas de escritorio, mensajes de Slack |
| Stop | Cuando Claude termina una respuesta | No | Limpieza, generación de resúmenes |
| SessionStart | En la inicialización de la sesión | No | Inyectar contexto, configurar el entorno |
| UserPromptSubmit | Cuando el usuario envía un prompt | Sí (exit 2) | Validación de entrada, filtrado de contenido |
| PreCompact | Antes de la compactación del contexto | No | Guardar estado antes de que se recorte la memoria |
| PostCompact | Después de la compactación del contexto | No | Reinyectar contexto crítico |
| ConfigChange | Cuando cambia la configuración | No | Recarga en caliente de variables de entorno |
| FileChanged | Cuando cambia un archivo vigilado | No | Disparar rebuilds, invalidar cachés |
| TaskCreated | Cuando se lanza una nueva tarea | No | Seguimiento de tareas, asignación de recursos |
| PermissionDenied | Cuando falla una comprobación de permisos | No | Registro de auditoría, alertas por acciones bloqueadas |
| WorktreeCreate | Cuando se crea un nuevo worktree de Git | No | Inicializar configuración específica del worktree |
| SubagentStart | Cuando se lanza un subagente | No | Monitorizar actividad del subagente |
| SubagentStop | Cuando un subagente termina | No | Validar la salida del subagente |
Consejo pro: Usarás PreToolUse y PostToolUse para el 80% de tus hooks. SessionStart es el siguiente más útil -- es perfecto para inyectar el contexto del proyecto que Claude necesita al inicio de cada sesión.
Los 4 Tipos de Hook de Claude Code Explicados
Claude Code soporta cuatro tipos de handler de hook: los hooks command ejecutan scripts de shell, los hooks HTTP hacen POST a URLs, los hooks prompt le hacen una pregunta de sí/no a Claude, y los hooks agent lanzan un subagente con acceso a herramientas. En nuestra experiencia, los hooks command cubren el 90% de los casos de uso. Usa HTTP para integraciones externas, y los hooks prompt y agent para decisiones matizadas que necesitan el juicio de la IA.
| Tipo | Velocidad | Complejidad | Mejor para | Ejemplo |
|---|---|---|---|---|
| Command | Rápido | Baja | Formateo, bloqueo, registro | Ejecutar Prettier después de editar un archivo |
| HTTP | Media | Media | Servicios externos, webhooks | POST a Slack al completarse |
| Prompt | Lento | Media | Decisiones subjetivas | "¿Es seguro ejecutar este código?" |
| Agent | El más lento | Alta | Verificación compleja con conciencia del archivo | Comprobar si el código nuevo sigue los patrones del proyecto |
Hooks Command (El Caballo de Batalla)
Los hooks command ejecutan un comando de shell y usan el código de salida para determinar el resultado. Reciben los datos JSON del evento por stdin.
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "jq -r '.tool_input.command' | grep -q 'rm -rf /' && exit 2 || exit 0"
}]
}]
}
}Esto es lo que usarás para formateo, protección de archivos, notificaciones y la mayor parte de la automatización. Rápido, simple y predecible.
Hooks HTTP (Integraciones Externas)
Los hooks HTTP envían una petición POST a una URL con el JSON del evento como cuerpo. El código de estado de la respuesta determina el resultado (200 = continuar, 403 = bloquear).
{
"hooks": {
"Stop": [{
"matcher": "",
"hooks": [{
"type": "http",
"url": "https://your-api.com/claude-webhook"
}]
}]
}
}Excelentes para enviar eventos a Slack, Discord, PagerDuty o un dashboard personalizado. También puedes usarlos para consultar un motor de políticas externo antes de permitir la ejecución de una herramienta.
Hooks Prompt (Decisiones Impulsadas por IA)
Los hooks prompt pasan los datos del evento al propio Claude para una evaluación de sí/no en un solo turno. Claude devuelve una respuesta JSON con "decision": "allow" o "decision": "block" más el razonamiento.
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "prompt",
"prompt": "¿Es seguro ejecutar este comando bash en un entorno de producción? Considera: ¿modifica archivos del sistema, elimina datos o accede a credenciales sensibles?"
}]
}]
}
}Úsalos con moderación. Añaden latencia (una llamada completa al LLM por ejecución de hook) y coste. Pero para comprobaciones de seguridad genuinamente subjetivas -- como "¿parece destructiva esta migración de base de datos?" -- son difíciles de superar. Si tienes curiosidad sobre cambiar los modelos de Claude Code, el modelo usado para los hooks prompt sigue el modelo de tu sesión actual.
Hooks Agent (Verificación Asistida por Herramientas)
Los hooks agent lanzan un subagente con acceso a las herramientas Read, Grep y Glob. El subagente puede inspeccionar archivos antes de tomar su decisión.
{
"hooks": {
"PreToolUse": [{
"matcher": "Write",
"hooks": [{
"type": "agent",
"prompt": "Comprueba si el archivo que se está escribiendo sigue las convenciones de nomenclatura y los patrones de importación del proyecto. Lee .claude/CONVENTIONS.md para ver las reglas."
}]
}]
}
}Este es el tipo de hook más poderoso, pero también el más lento. Resérvalo para comprobaciones de alto riesgo donde necesitas contexto del archivo para tomar una buena decisión.
7 Ejemplos de Hooks de Claude Code Listos para Producción (Listos para Copiar y Pegar)
Los hooks de Claude Code más útiles incluyen el auto-formateo con Prettier o Black después de editar archivos, bloquear escrituras en archivos protegidos, enviar notificaciones de escritorio al completarse una tarea, inyectar contexto del proyecto al inicio de la sesión, ejecutar tests después de cambios en el código, aplicar protección de ramas y auditar todo el uso de herramientas. Llevo meses usando variaciones de estos en cada proyecto.
Cada ejemplo a continuación es un fragmento completo de settings.json que puedes añadir directamente a tu .claude/settings.json. Colecciones de la comunidad como awesome-claude-code tienen incluso más patrones.
1. Auto-Formatear al Guardar
{
"hooks": {
"PostToolUse": [{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // .tool_input.file' /dev/stdin); case \"$FILE\" in *.ts|*.tsx|*.js|*.jsx) npx prettier --write \"$FILE\" 2>/dev/null;; *.py) black \"$FILE\" 2>/dev/null;; esac; exit 0"
}]
}]
}
}Esto se dispara después de cada Write o Edit, extrae la ruta del archivo del JSON de stdin y ejecuta el formateador apropiado. El exit 0 al final garantiza que el hook nunca bloquee -- los fallos de formateo no deberían detener a Claude.
Consejo pro: Añade *.go con gofmt y *.rs con rustfmt si trabajas con varios lenguajes.
2. Bloquear Escrituras en Archivos Protegidos
{
"hooks": {
"PreToolUse": [{
"matcher": "Write|Edit",
"if": "tool_input.file_path matches '(\\.env|\\.env\\.local|package-lock\\.json|yarn\\.lock|pnpm-lock\\.yaml)'",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"BLOQUEADO: Este archivo está protegido. Edítalo manualmente.\"}' && exit 2"
}]
}]
}
}El código de salida 2 bloquea la acción y envía el mensaje JSON de vuelta a Claude. Claude ve el feedback y se ajusta -- normalmente te dirá que quería modificar el archivo y te pedirá que lo hagas manualmente. El campo if evita que esto se dispare en cada Write.
3. Notificación de Escritorio al Completarse
{
"hooks": {
"Notification": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "MSG=$(jq -r '.message // \"Tarea de Claude Code finalizada\"' /dev/stdin); if [ \"$(uname)\" = 'Darwin' ]; then osascript -e \"display notification \\\"$MSG\\\" with title \\\"Claude Code\\\"\"; else notify-send 'Claude Code' \"$MSG\"; fi; exit 0"
}]
}]
}
}Funciona en macOS (osascript) y Linux (notify-send). El matcher vacío significa que se dispara en todas las notificaciones. Es genuinamente útil cuando lanzas una tarea larga y cambias a otra ventana.
4. Inyección de Contexto al Iniciar la Sesión
{
"hooks": {
"SessionStart": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"Proyecto: '\"$(basename $(pwd))\"' | Rama: '\"$(git branch --show-current 2>/dev/null || echo none)\"' | Último commit: '\"$(git log --oneline -1 2>/dev/null || echo none)\"'\"}'; exit 0"
}]
}]
}
}Esto inyecta el nombre del proyecto actual, la rama de Git y el último commit en cada sesión. Claude recibe este contexto automáticamente -- no necesitas decirle en qué rama estás.
5. Auto-Ejecutar Tests Después de Cambios en el Código
{
"hooks": {
"PostToolUse": [{
"matcher": "Write|Edit",
"if": "tool_input.file_path matches '\\.(ts|tsx|js|jsx|py)$'",
"hooks": [{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path' /dev/stdin); TEST_FILE=$(echo \"$FILE\" | sed 's/\\.[^.]*$/.test&/'); if [ -f \"$TEST_FILE\" ]; then npx jest \"$TEST_FILE\" --no-coverage 2>&1 | tail -5; fi; exit 0",
"timeout": 30000
}]
}]
}
}Si existe un archivo de test correspondiente, se ejecuta automáticamente después de que Claude edite el código fuente. El tail -5 mantiene la salida concisa, y el timeout evita suites de tests interminables. Esto encaja bien con un flujo de trabajo de revisión de código asistida por IA.
6. Aplicación de Protección de Ramas (Avanzado)
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"if": "tool_input.command matches 'git push.*(main|master|production)'",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"BLOQUEADO: Push directo a rama protegida. Usa una rama de funcionalidad y abre un PR.\"}' && exit 2"
}]
}]
}
}Esto bloquea cualquier git push que tenga como objetivo las ramas main, master o production. Claude recibe el feedback y sugerirá crear una rama de funcionalidad.
7. Registro de Auditoría de Seguridad (Avanzado)
{
"hooks": {
"PostToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "INPUT=$(cat /dev/stdin); CMD=$(echo \"$INPUT\" | jq -r '.tool_input.command'); echo \"[$(date -u +%Y-%m-%dT%H:%M:%SZ)] BASH: $CMD\" >> .claude/audit.log; exit 0"
}]
}]
}
}Registra cada comando Bash que ejecuta Claude en un archivo de auditoría con marca de tiempo UTC. Invaluable para revisiones de seguridad y para entender qué hizo realmente Claude durante una sesión. Mantén .claude/audit.log en tu .gitignore.
Hooks vs MCP vs Skills vs CLAUDE.md: Cuándo Usar Cada Uno
Usa hooks para la automatización determinística que siempre debe ejecutarse (formateo, bloqueos, notificaciones). Usa MCP para darle a Claude acceso a herramientas y datos externos. Usa Skills para paquetes de prompts reutilizables. Usa CLAUDE.md para orientación de comportamiento y contexto del proyecto. Los hooks son garantizados; todo lo demás es probabilístico. Esta es la distinción más importante, y sigo volviendo a ella cuando asesoro a equipos.
La Matriz de Decisión
| Mecanismo | ¿Determinístico? | Cuándo se ejecuta | Mejor para | Ejemplo |
|---|---|---|---|---|
| Hooks | Sí | Automáticamente en eventos del ciclo de vida | Aplicación de reglas, automatización, notificaciones | Auto-formatear, bloquear escrituras |
| MCP | No (Claude decide) | Cuando Claude llama a la herramienta MCP | Nuevas capacidades, acceso a datos externos | Consultar una base de datos, buscar en Notion |
| Skills | No (el usuario dispara) | Cuando el usuario invoca un slash command | Conjuntos de instrucciones reutilizables | /review para flujo de revisión de código |
| CLAUDE.md | No (orientación) | Se lee al inicio de la sesión | Contexto del proyecto, estándares de código | "Usa Tailwind, escribe tests para todo el código nuevo" |
Para una guía detallada sobre MCP, consulta nuestra guía de MCP. Si vienes de Cursor, el sistema de reglas de Cursor es aproximadamente análogo a CLAUDE.md -- pero Cursor no tiene nada parecido a los hooks.
Cuándo se Solapan (y Cómo Elegir)
Este es el diagrama de flujo que uso:
- "¿Esto NECESITA ocurrir cada vez, sin excepciones?" -- Hook. Formatea código, bloquea archivos protegidos, envía notificaciones. Cero ambigüedad.
- "¿Claude necesita una CAPACIDAD nueva que no tiene?" -- Servidor MCP. Accede a una base de datos, llama a una API, busca en documentación externa.
- "¿Quiero INSTRUCCIONES reutilizables para un flujo de trabajo específico?" -- Skill (slash command). Plantillas de revisión de código, listas de verificación de despliegue.
- "¿Quiero moldear el COMPORTAMIENTO de Claude en este proyecto?" -- CLAUDE.md. Estándares de código, decisiones de arquitectura, librerías preferidas.
Ejemplos reales que aclaran el límite:
- "Siempre formatea con Prettier" = Hook (debe ocurrir cada vez)
- "Usa Prettier para el formateo" en CLAUDE.md = Orientación (Claude podría olvidarlo)
- "Busca en nuestra documentación interna" = MCP (nueva capacidad)
- "Sigue nuestra guía de estilo al revisar código" = Skill o CLAUDE.md
Como se describe en el anuncio de plugins de Anthropic, los hooks son una pieza de un ecosistema de plugins más amplio que también incluye MCP y Skills. Están diseñados para complementarse mutuamente, no para competir.
El Kit de Inicio: Configuración de Hooks de Claude Code Lista para Cualquier Proyecto
Una configuración de hooks de inicio para Claude Code debería incluir auto-formateo al editar archivos, notificación al completar una tarea, protección de archivos sensibles, inyección de contexto de sesión y un hook de stop para limpieza. Esta es exactamente la configuración que añado a cada proyecto nuevo -- adaptada al stack, pero la estructura siempre es la misma.
La Configuración
{
"hooks": {
"SessionStart": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"Proyecto: '\"$(basename $(pwd))\"' | Rama: '\"$(git branch --show-current 2>/dev/null)\"' | Node: '\"$(node -v 2>/dev/null)\"'\"}'; exit 0"
}]
}],
"PreToolUse": [{
"matcher": "Write|Edit",
"if": "tool_input.file_path matches '(\\.env|\\.env\\..+|.*lock\\.json|.*lock\\.yaml)'",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"Archivo protegido. Edítalo manualmente.\"}' && exit 2"
}]
}],
"PostToolUse": [{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // .tool_input.file' /dev/stdin); case \"$FILE\" in *.ts|*.tsx|*.js|*.jsx) npx prettier --write \"$FILE\" 2>/dev/null;; *.py) black \"$FILE\" 2>/dev/null;; *.go) gofmt -w \"$FILE\" 2>/dev/null;; esac; exit 0"
}]
}],
"Notification": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "MSG=$(jq -r '.message // \"Listo\"' /dev/stdin); osascript -e \"display notification \\\"$MSG\\\" with title \\\"Claude Code\\\"\" 2>/dev/null || notify-send 'Claude Code' \"$MSG\" 2>/dev/null; exit 0"
}]
}],
"Stop": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "echo '[STOP] '\"$(date +%H:%M:%S)\"'' >> .claude/session.log; exit 0"
}]
}]
}
}Cómo Personalizar para Tu Stack
| Stack | Comando de formateo | Comando de tests | Extensiones vigiladas |
|---|---|---|---|
| Node/TypeScript | npx prettier --write | npx jest --no-coverage | .ts, .tsx, .js, .jsx |
| Python | black | pytest -x | .py |
| Go | gofmt -w | go test ./... | .go |
| Rust | rustfmt | cargo test | .rs |
Intercambia los comandos de formateo y tests en la configuración anterior para que coincidan con tu stack. La estructura se mantiene idéntica.
Verificar que Tus Hooks Funcionan
Tres formas de confirmar que los hooks están activos:
- Comando
/hooks-- Escribe/hooksen Claude Code para ver todos los hooks registrados, sus matchers y su estado. - Inspección del transcript -- Después de que se dispare un hook, comprueba el transcript de la sesión. Las ejecuciones de hooks aparecen con su salida y código de salida.
- Toggle rápido -- Añade
"disableAllHooks": truea tu settings.json para desactivar temporalmente todos los hooks sin borrar la configuración. Elimínalo (o ponlo enfalse) para volver a activarlos.
Integración con CI/CD: Hooks de Claude Code en Modo Headless
Los hooks de Claude Code funcionan en modo headless (claude -p) con algunas diferencias: los hooks Notification siguen disparándose, pero deberías redirigirlos a registros en lugar de alertas de escritorio. Los hooks PreToolUse con código de salida 2 pueden pausar las sesiones headless para revisión humana. GitHub Actions usa anthropics/claude-code-action@v1 junto con hooks para flujos de trabajo automatizados.
Comportamiento en Modo Headless
| Evento de hook | Modo interactivo | Modo headless (-p) | Recomendación para CI |
|---|---|---|---|
| PreToolUse (exit 2) | Bloquea, muestra mensaje | Pausa para --resume | Úsalo para aprobaciones humanas obligatorias |
| PostToolUse | Se ejecuta normalmente | Se ejecuta normalmente | Mantén formateadores y registradores |
| Notification | Alerta de escritorio | Se dispara (sin UI) | Redirige a archivo de log o webhook de Slack |
| Stop | Ejecuta limpieza | Ejecuta limpieza | Útil para recolección de artefactos de CI |
| SessionStart | Inyecta contexto | Inyecta contexto | Inyecta variables de entorno de CI |
La gran sorpresa en modo headless: los hooks PreToolUse que salen con código 2 no fallan silenciosamente. Pausan la sesión y te permiten reanudarla con --resume, lo que te da un patrón de supervisión humana en los pipelines de CI/CD.
Integración con GitHub Actions
Aquí hay un flujo de trabajo mínimo de GitHub Actions que usa Claude Code con hooks. Como se documenta en la guía oficial de GitHub Actions:
- name: Run Claude Code
uses: anthropics/claude-code-action@v1
with:
prompt: "Review this PR and suggest improvements"
allowed_tools: "Read,Grep,Glob"
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}Tus hooks en .claude/settings.json viajan con el repositorio, así que se dispararán en CI exactamente igual que en local. Solo asegúrate de que los hooks que dependen de herramientas específicas del escritorio (como osascript) tengan fallbacks o condicionales.
Gestión de Hooks en Equipo
Un patrón que funciona bien para equipos:
.claude/settings.json(subido al repo) -- Hooks compartidos del equipo: protección de archivos, formateadores, protección de ramas. Todo el mundo los recibe..claude/settings.local.json(en .gitignore) -- Hooks personales: preferencias de notificación, registro personalizado, hooks experimentales.~/.claude/settings.json(global del usuario) -- Tus valores predeterminados en todos los proyectos: estilo de notificación, preferencias personales de formateo.
Esto refleja cómo funcionan .editorconfig (subido al repo) y la configuración local del IDE (personal). Como señala la guía de CI/CD de Angelo Lima, los equipos que estandarizan hooks compartidos ven menos problemas del tipo "funciona en mi máquina" con Claude Code.
Resolución de Problemas de Hooks de Claude Code y Errores Comunes
Los problemas más comunes de los hooks de Claude Code incluyen: hooks que no se disparan (comprueba la ortografía del matcher y la ubicación de settings.json), hooks que se ejecutan pero no bloquean (código de salida incorrecto -- usa 2, no 1), bucles infinitos (el hook Stop se dispara a sí mismo) y arranque lento (demasiados hooks síncronos). El error más común que veo es la confusión con los códigos de salida -- los desarrolladores usan exit 1 cuando quieren decir exit 2.
El Hook No se Dispara
Síntomas: Añadiste un hook pero no pasa nada cuando ocurre el evento.
Soluciones:
- Errata en el matcher -- Los matchers distinguen mayúsculas de minúsculas.
"write"no coincidirá con la herramientaWrite. Comprueba los nombres exactos de las herramientas con/hooks. - Archivo de configuración incorrecto -- Los hooks en
~/.claude/settings.jsonno aparecerán en la salida de/hookspara el ámbito del proyecto. Prueba con.claude/settings.jsonen la raíz del proyecto. - Error de sintaxis JSON -- Una coma de más o un corchete faltante deshabilita silenciosamente toda la configuración de hooks. Pasa tu settings.json por
jq .para validarlo. disableAllHooks: true-- Comprueba si alguien (o una sesión de depuración anterior) dejó este flag activado.
El Hook se Ejecuta pero No Bloquea
Síntomas: Tu hook PreToolUse se ejecuta, pero la acción continúa de todos modos.
Soluciones:
- Código de salida incorrecto -- El código de salida 1 significa "error" (el hook falló), no "bloquear". Usa
exit 2para bloquear una acción. Esto confunde a casi todo el mundo, como se señala en la documentación oficial. - JSON de stdout faltante -- Para hooks de bloqueo, emite un mensaje JSON para que Claude sepa por qué se bloqueó la acción:
echo '{"message": "Bloqueado: razón"}'
Bucles Infinitos
Síntomas: Claude sigue reintentando la misma acción, o tu máquina se calienta de forma sospechosa.
Soluciones:
- Hook Stop que dispara acciones -- Si tu hook Stop escribe un archivo o ejecuta un comando que hace que Claude responda, has creado un bucle. Los hooks Stop solo deben hacer cosas pasivas: registrar, notificar, limpiar.
- Hook PostToolUse que provoca ediciones -- Un hook PostToolUse que modifica un archivo dispara otro evento PostToolUse. Protégete contra esto con matchers específicos o el campo
if.
Problemas de Rendimiento
Síntomas: Claude tarda notablemente más en arrancar o ejecutar herramientas.
Soluciones:
- Demasiados hooks SessionStart -- Cada uno se ejecuta síncronamente al arrancar. Mantenlos ligeros (menos de 1 segundo cada uno).
- Scripts pesados en rutas calientes -- Los hooks en PreToolUse y PostToolUse se disparan con frecuencia. Si tu script hace peticiones de red o cálculos pesados, añade un campo
timeout(en milisegundos) y considera si debería ser un hook HTTP en su lugar. - Sin caché -- Si estás comprobando lo mismo repetidamente (como "¿es esta una rama protegida?"), guarda el resultado en un archivo temporal en lugar de ejecutar comandos Git en cada invocación del hook.
Preguntas Frecuentes
¿Qué son los hooks de Claude Code y cómo funcionan?
Los hooks de Claude Code son scripts de automatización definidos por el usuario que se ejecutan en eventos específicos del ciclo de vida durante una sesión de Claude Code. Los configuras en settings.json con un patrón de matcher y un handler (comando de shell, endpoint HTTP, prompt o agente). Cuando se dispara el evento coincidente, el hook se ejecuta automáticamente y usa códigos de salida para controlar el resultado.
¿Cómo configuro los hooks en settings.json de Claude Code?
Añade un objeto "hooks" a cualquiera de las tres ubicaciones de configuración: ~/.claude/settings.json (global del usuario), .claude/settings.json (compartido del proyecto) o .claude/settings.local.json (personal del proyecto). Cada tipo de evento se mapea a un array de definiciones de hook con matcher, campo if opcional y un array hooks que contiene objetos handler con type y command o url.
¿Cuál es la diferencia entre los hooks PreToolUse y PostToolUse?
PreToolUse se dispara antes de que se ejecute una herramienta, dándote el poder de bloquearla con código de salida 2. PostToolUse se dispara después de que la ejecución se complete, útil para formateo, tests o registro. PreToolUse es para prevención y control. PostToolUse es para validación y limpieza. Ambos reciben el nombre de la herramienta y su entrada como JSON por stdin.
¿Pueden los hooks de Claude Code bloquear comandos peligrosos?
Sí. Los hooks PreToolUse con código de salida 2 bloquean cualquier ejecución de herramienta. Puedes proteger archivos sensibles de ser escritos, bloquear comandos de shell que coincidan con patrones peligrosos como rm -rf o git push main, y evitar el acceso a bases de datos de producción. El mensaje de bloqueo se envía de vuelta a Claude como feedback, para que pueda ajustar su enfoque.
¿Qué eventos de hook están disponibles en Claude Code?
Claude Code proporciona más de 15 eventos: PreToolUse y PostToolUse para la ejecución de herramientas, Notification para alertas, Stop para el fin de sesión, SessionStart para la inicialización, UserPromptSubmit para el filtrado de entrada, PreCompact y PostCompact para la gestión del contexto, y eventos más nuevos como ConfigChange, FileChanged, TaskCreated y PermissionDenied. Consulta la tabla de referencia completa en la sección de eventos de hook más arriba.
¿En qué se diferencian los hooks de las herramientas MCP y los Skills?
Los hooks son determinísticos -- siempre se disparan en eventos coincidentes independientemente de lo que Claude decida. Las herramientas MCP amplían las capacidades de Claude (acceso a bases de datos, llamadas a APIs) pero Claude elige cuándo usarlas. Los Skills son paquetes de instrucciones reutilizables invocados mediante slash commands. CLAUDE.md proporciona orientación de comportamiento. Usa hooks cuando algo debe ocurrir siempre, MCP cuando Claude necesita nuevas habilidades.
¿Funcionan los hooks de Claude Code en modo headless?
Sí, con matices. Los hooks se disparan normalmente en modo headless (claude -p), pero los hooks específicos del escritorio como las notificaciones de macOS necesitan fallbacks. Más importante: los hooks PreToolUse que salen con código 2 pueden pausar las sesiones headless para aprobación humana mediante --resume. Esto permite pipelines de CI/CD con supervisión humana donde ciertas acciones requieren aprobación manual.
¿Cuántos hooks son demasiados? ¿Los hooks ralentizan Claude Code?
No hay un límite fijo, pero cada hook síncrono añade latencia. Los hooks SessionStart se ejecutan al arrancar, así que mantenlos rápidos (menos de 1 segundo cada uno). Los hooks PreToolUse y PostToolUse se disparan en cada llamada de herramienta coincidente -- los scripts pesados aquí se acumulan rápidamente. Recomendaría mantener el total de hooks por debajo de 10-15, usar el campo if para reducir el ámbito, y añadir valores de timeout para evitar scripts interminables.
¿Puedo usar hooks para auto-formatear código con Prettier o Black?
Sí -- es el caso de uso más popular de los hooks. Crea un hook PostToolUse que coincida con Write|Edit, extrae la ruta del archivo del JSON de stdin y ejecuta el formateador apropiado según la extensión del archivo. Consulta el ejemplo número uno en la sección de ejemplos de producción para ver una configuración completa y lista para copiar y pegar que maneja archivos TypeScript, JavaScript y Python.
¿Son seguros los hooks de Claude Code? ¿Cuáles son los riesgos de seguridad?
Los hooks se ejecutan con todos tus permisos de usuario -- no hay sandbox. Un hook malicioso podría leer tus claves SSH, borrar archivos o exfiltrar datos. Usa solo hooks de fuentes de confianza, revisa cualquier .claude/settings.json compartido antes de aceptarlo en tu proyecto, y usa .claude/settings.local.json para hooks personales que no deberían compartirse. Para patrones más amplios de seguridad en IA, consulta nuestra guía de guardarraíles para LLMs.