# Hooks en Claude Code para principiantes: automatizando acciones repetitivas

> Guía práctica completa para configurar Hooks en Claude Code: linting y formateo automáticos, controles de calidad previos al commit, notificaciones y ejecución Headless.

## 1. Qué son los Hooks en Claude Code y por qué los necesitas

Al trabajar con asistentes de IA en la terminal, los desarrolladores a menudo se encuentran repitiendo las mismas instrucciones: *"ahora ejecuta ESLint"*, *"formatea el código con Prettier"*, *"comprueba los tipos de TypeScript antes de hacer commit"*. Aunque definas estas directrices en el archivo `CLAUDE.md`, los modelos de lenguaje pueden olvidarlas periódicamente o pasarlas por alto para ahorrar tokens.

Los **Hooks (ganchos)** en Claude Code resuelven este problema desde la raíz: son disparadores deterministas que ejecutan comandos del sistema operativo o scripts en momentos exactos del ciclo de vida del agente.

El principio es simple:
> **Siempre que Claude ejecuta el evento X → el sistema operativo lanza de forma garantizada la acción Y.**

```mermaid
flowchart LR
    subgraph Instrucciones_en_Texto["CLAUDE.md (Probabilístico)"]
        A["Prompt: 'Ejecuta siempre el linter'"] --> B{"¿Lo recuerda el modelo?"}
        B -->|A veces| C["Lanza la comprobación"]
        B -->|Omitido| D["Los errores se acumulan"]
    end
    subgraph Hooks_Nativos["Hooks en settings.json (Determinista)"]
        E["Evento: Archivo editado"] --> F["Disparador nativo del SO"]
        F --> G["Ejecución garantizada de npx eslint"]
    end
```

### Comparativa de enfoques de automatización

| Característica | Prompts manuales | Reglas en CLAUDE.md | Hooks nativos de Claude Code |
| :--- | :--- | :--- | :--- |
| **Fiabilidad de ejecución** | Baja (depende de la memoria humana) | Media (comportamiento probabilístico) | 100% (intercepción determinista de eventos) |
| **Consumo de tokens** | Alto (consume tokens en cada petición) | Medio (se carga en cada contexto del sistema) | Cero (se ejecuta localmente en la shell) |
| **Velocidad de respuesta** | Lenta (requiere entrada manual) | Requiere un turno adicional del modelo | Instantánea (invocación directa de proceso) |
| **Capacidad de bloqueo** | Inexistente | Inexistente | Disponible (código de salida != 0 aborta la acción) |

> [!NOTE]
> Los hooks de Claude Code se configuran en formato JSON dentro de `.claude/settings.json` a nivel de repositorio o globalmente en `~/.claude/settings.json`.

---

## 2. Ciclo de vida de eventos: PreToolUse, PostToolUse, Notification y Stop

Claude Code expone cuatro puntos de intercepción fundamentales (eventos) a los que vincular comandos automatizados.

```mermaid
sequenceDiagram
    autonumber
    actor Dev as Desarrollador
    participant Agent as Claude Code
    participant Hook as Motor de Hooks
    participant Tool as Herramienta (Bash/Edit/Write)

    Dev->>Agent: Solicitud de cambio de código
    Agent->>Hook: Intento de invocación de herramienta
    Note over Hook: PreToolUse Hook
    Hook-->>Agent: Validación superada (Exit Code 0)
    Agent->>Tool: Ejecución de la operación
    Tool-->>Agent: Resultado exitoso
    Agent->>Hook: Evento de fin de herramienta
    Note over Hook: PostToolUse Hook
    Hook-->>Agent: Resultado de linting / formateo
    Agent->>Hook: Fin de respuesta del modelo
    Note over Hook: Stop Hook (Notificación)
    Agent-->>Dev: Respuesta final enviada
```

### Principales eventos interceptables

1. **`PreToolUse` (Antes del uso de la herramienta):** se activa *antes* de que el agente ejecute una acción. Si el comando del hook devuelve un error (código de salida distinto de 0), la acción se bloquea. Es el lugar idóneo para controles de calidad previos a commits o pushes.
2. **`PostToolUse` (Después del uso de la herramienta):** se activa *inmediatamente después* de que una herramienta finalice con éxito. Es el disparador más habitual para formatear código (Prettier) o pasar linters (ESLint) sobre el archivo modificado.
3. **`Notification` (Notificación del sistema):** se ejecuta cuando el asistente necesita avisar al usuario o solicitar autorizaciones de permisos.
4. **`Stop` (Finalización de respuesta):** se dispara cuando Claude Code concluye por completo la generación de su respuesta y espera la siguiente intervención del usuario. Se utiliza para reproducir sonidos o enviar notificaciones de escritorio.

![Puntos de activación de Hooks en el ciclo de vida](/api/guides-media/automation/hooks-automation-guide-for-beginners/images/hooks-automation-guide-for-beginners-extra-02.webp)

---

## 3. Estructura de configuración en settings.json y sintaxis de Matcher

La configuración de hooks se almacena en `.claude/settings.json`. Si este archivo no existe aún en la raíz de tu proyecto, créalo.

### Sintaxis básica de configuración

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Iniciando edición del archivo...'"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Comando Bash ejecutado con éxito'"
          }
        ]
      }
    ]
  }
}
```

### Cómo funciona el campo Matcher

El campo `matcher` determina a qué herramienta del agente debe responder el hook correspondiente:

- `"Edit"` — intercepta la modificación de archivos existentes.
- `"Write"` — se activa al crear un nuevo archivo o sobrescribirlo por completo.
- `"Bash"` — responde a la ejecución de cualquier comando de consola.
- `"Bash(git commit*)"` — patrón selectivo que filtra comandos Bash que comiencen por `git commit`.
- `"*"` — comodín universal que responde a cualquier herramienta del asistente.

> [!TIP]
> Los nombres de `matcher` distinguen entre mayúsculas y minúsculas. Emplea los nombres oficiales de herramientas de Claude Code: `Edit`, `Write`, `Bash`, `Glob`, `Grep`.

---

## 4. Linting y formateo automatizados (ESLint + Prettier)

El caso de uso más práctico en el día a día es delegar el formateo y la corrección de estilo en herramientas como `Prettier` y `ESLint`. De este modo, todo el código nuevo o modificado se guarda con una estructura impecable.

### Configuración de PostToolUse para ESLint y Prettier

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx eslint --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ]
      },
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}
```

### Explicación de los modificadores de seguridad

- `"$CLAUDE_FILE_PATH"` — variable de entorno dinámica donde Claude inserta la ruta absoluta del archivo que acaba de modificar o crear.
- `2>/dev/null` — silencia la salida de errores auxiliares de stderr para mantener limpia la consola.
- `|| true` — construcción de shell indispensable. Garantiza que si el linter encuentra un error insalvable (con salida `1`), el hook devuelva código `0` y no interrumpa el flujo de trabajo de Claude.

```mermaid
flowchart TD
    A["Claude ejecuta Edit"] --> B["Archivo guardado en disco"]
    B --> C["Disparo de PostToolUse"]
    C --> D["npx eslint --fix $CLAUDE_FILE_PATH"]
    D --> E{"¿Éxito o || true?"}
    E --> F["El agente continúa con la tarea"]
```

---

## 5. Barreras de calidad previas al commit (TypeCheck + Tests)

Mientras que para el formateo usamos hooks permisivos (`|| true`), para registrar cambios en el control de versiones se requiere una barrera de calidad estricta (Quality Gate).

Mediante `PreToolUse`, puedes bloquear la ejecución de `git commit` si existen errores de tipos en TypeScript o fallos en las pruebas unitarias.

### Configuración del hook bloqueante de Pre-commit

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(git commit*)",
        "hooks": [
          {
            "type": "command",
            "command": "npm run typecheck && npm run lint"
          }
        ]
      }
    ]
  }
}
```

### Secuencia de intercepción de errores

1. Claude prepara el comando `git commit -m "..."`.
2. Antes de ejecutarlo, el sistema activa `PreToolUse`.
3. Se lanzan las comprobaciones: `npm run typecheck` y `npm run lint`.
4. **Si se detecta un error:** el proceso finaliza con código de salida 1.
5. Claude Code captura el log de compilación directamente en su contexto.
6. En lugar de generar un commit defectuoso, el asistente analiza la traza del error, corrige los tipos en el código y repite el commit limpiamente.

> [!IMPORTANT]
> En comprobaciones bloqueantes con `PreToolUse`, **jamás** añadas `|| true`. Si lo haces, la verificación siempre se considerará exitosa y anularás la protección.

---

## 6. Notificaciones sonoras y de escritorio al finalizar tareas (Stop Hook)

Las refactorizaciones complejas o la ejecución de suites de pruebas pueden demorarse entre 2 y 10 minutos. En lugar de vigilar constantemente la terminal, configura una alerta sobre el evento `Stop`.

:::tabs
@tab macOS
```json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "afplay /System/Library/Sounds/Glass.aiff && osascript -e 'display notification \"¡Tarea completada!\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
```
@tab Linux (Ubuntu / Debian)
```json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null || notify-send 'Claude Code' '¡Tarea finalizada con éxito!'"
          }
        ]
      }
    ]
  }
}
```
@tab Windows (WSL / PowerShell)
```json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "powershell.exe -c \"[System.Media.SystemSounds]::Asterisk.Play(); [System.Console]::Beep(800, 250)\""
          }
        ]
      }
    ]
  }
}
```
:::

> [!TIP]
> El evento `Stop` solo se dispara cuando el agente termina por completo la generación de su respuesta final, no entre llamadas intermedias a herramientas.

---

## 7. Inyección de contexto mediante variables de entorno

Para que los scripts de automatización sean modulares y conscientes de su contexto, Claude Code exporta automáticamente metadatos en variables de entorno del sistema operativo.

![Variables de entorno de Claude Code para hooks](/api/guides-media/automation/hooks-automation-guide-for-beginners/images/hooks-automation-guide-for-beginners-extra-01.webp)

### Referencia de variables del sistema en Claude Code

| Variable de entorno | Tipo de dato | Descripción y valor de ejemplo |
| :--- | :--- | :--- |
| **`$CLAUDE_FILE_PATH`** | Ruta absoluta | Ruta al archivo concreto que se está creando o modificando (`/Users/dev/project/src/index.ts`) |
| **`$CLAUDE_TOOL_NAME`** | Identificador de texto | Nombre de la herramienta que originó el evento (`Edit`, `Write`, `Bash`) |
| **`$CLAUDE_PROJECT_DIR`** | Ruta absoluta | Directorio raíz del proyecto donde se inició la sesión de Claude Code |

### Creación de un script validador sensible al contexto

Crea un script en `.claude/hooks/smart-validator.sh`:

```bash
#!/usr/bin/env bash
set -e

# Comprobar la existencia del archivo y ramificar según la extensión
if [[ -f "$CLAUDE_FILE_PATH" ]]; then
  case "$CLAUDE_FILE_PATH" in
    *.ts|*.tsx)
      echo "⚡ Validando archivo TypeScript: $CLAUDE_FILE_PATH"
      npx eslint --fix "$CLAUDE_FILE_PATH" || true
      ;;
    *.json)
      echo "🔍 Verificando sintaxis JSON..."
      jq empty "$CLAUDE_FILE_PATH" 2>/dev/null || echo "¡Sintaxis JSON no válida!"
      ;;
    *.md)
      echo "📝 Documentación actualizada: $(basename "$CLAUDE_FILE_PATH")"
      ;;
  esac
fi
```

Vincula el script dentro de `.claude/settings.json`:

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/smart-validator.sh"
          }
        ]
      }
    ]
  }
}
```

---

## 8. El patrón «CI-in-a-Loop»: retroalimentación inmediata

En el flujo habitual sin hooks se produce una brecha: el asistente modifica diez archivos y al compilar se encuentra con una avalancha de 40 errores de tipos. Descubrir qué cambio exacto rompió la compilación resulta costoso en tiempo y tokens.

**CI-in-a-Loop (Bucle estrecho de retroalimentación)** transforma este proceso:

```mermaid
flowchart TD
    A["Claude aplica una modificación"] --> B["Lanzamiento instantáneo de tsc"]
    B --> C{"¿Hay algún error?"}
    C -->|Sí| D["Claude ve 1 error puntual"]
    D --> E["Corrección inmediata en 5 segundos"]
    E --> B
    C -->|No| F["Continúa con el siguiente archivo"]
```

### Configuración del ciclo continuo de TypeScript

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx tsc --noEmit 2>&1 | head -n 20 || true"
          }
        ]
      }
    ]
  }
}
```

### Por qué es indispensable usar `head -n 20`

Si el compilador devuelve cientos de líneas de log, saturará la ventana de contexto de la IA. Limitar la salida mediante `head -n 20` muestra los errores iniciales más críticos, facilitando que el modelo los resuelva al instante sin agotar sus límites.

---

## 9. Automatización Headless: modo -p, Cron y Git Hooks

Los hooks pueden combinarse con el modo desatendido (headless) de Claude Code mediante la bandera `-p` (print/prompt). Esto permite que tareas complejas de desarrollo se ejecuten sin intervención humana.

```mermaid
flowchart LR
    A["Programación Cron (02:00)"] --> B["Script nightly-audit.sh"]
    B --> C["claude -p 'Run test suite, fix bugs, commit'"]
    C --> D["Hooks PostToolUse auditan el código"]
    D --> E["Push automático de cambios validados"]
```

### Script de auditoría nocturna desatendida (`nightly-audit.sh`)

```bash
#!/usr/bin/env bash
cd /var/www/my-project

# Ejecutar Claude Code de forma autónoma con una instrucción explícita
claude -p "Run full test suite. If any tests fail, inspect the stack trace and fix them. Ensure typecheck passes. Finally, commit all fixes with a conventional commit." >> /var/log/claude-audit.log 2>&1
```

### Programación mediante Cron

Edita la tabla de tareas (`crontab -e`) para fijar la ejecución cada madrugada a las 03:00:

```text
0 3 * * * /usr/local/bin/nightly-audit.sh
```

### Verificación automática en Git Hook nativo (`.git/hooks/post-merge`)

Para analizar incompatibilidades cada vez que se descarguen cambios con `git pull`:

```bash
#!/usr/bin/env bash
# .git/hooks/post-merge
echo "🚀 Ejecutando auditoría automática de dependencias con Claude..."
claude -p "Check if package.json was updated. If so, run npm install, verify build, and report summary."
```

No olvides conceder permisos de ejecución: `chmod +x .git/hooks/post-merge`.

---

## 10. Buenas prácticas de ingeniería y reglas de seguridad para Hooks

Un hook mal planificado puede provocar bucles infinitos o bloquear la consola. Aplica estas cuatro reglas de higiene técnica.

### Cuatro principios para diseñar hooks seguros

1. **Rendimiento subsegundo:** Los hooks vinculados a `PostToolUse` se ejecutan tras cada cambio de archivo. Si tardan más de 1 o 2 segundos, la sesión con Claude resultará lenta e incómoda. Reserva suites pesadas de pruebas E2E para `PreToolUse` antes del commit.
2. **Redirección sistemática a logs:** Canaliza siempre la salida de diagnóstico a un archivo temporal:
   ```bash
   "command": "bash .claude/hooks/check.sh >> /tmp/claude-hooks.log 2>&1 || true"
   ```
   Si una automatización falla silenciosamente, `/tmp/claude-hooks.log` mostrará el origen exacto.
3. **Verificación aislada en la consola:** Antes de añadir una instrucción a `settings.json`, pruébala directamente en tu shell. Si falla en la terminal, romperá con certeza la sesión de Claude Code.
4. **Prevención de recursión infinita:** Nunca configures en `PostToolUse` un script que modifique archivos del proyecto sin exclusiones. Si el script desencadena un nuevo `Edit`, el agente entrará en un ciclo interminable.

> [!WARNING]
> No ejecutes mediante hooks órdenes que requieran interacción por teclado (como preguntas interactivas `read -p` o `sudo` solicitando contraseñas), ya que bloquearán el proceso en segundo plano.

---

## 11. Taller práctico, chuleta de referencia y lista de verificación final

Para implementar esta automatización en tus proyectos, consulta esta guía rápida de decisiones y la configuración de producción recomendada.

![Chuleta de referencia para seleccionar tipos de Hooks](/api/guides-media/automation/hooks-automation-guide-for-beginners/images/hooks-automation-guide-for-beginners-extra-03.webp)

### Plantilla lista para producción de `.claude/settings.json`

Copia esta plantilla directamente en la carpeta `.claude` de tu proyecto:

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(git commit*)",
        "hooks": [
          {
            "type": "command",
            "command": "npm run typecheck && npm test"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ]
      },
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"¡Trabajo completado!\" with title \"Claude Code\"' 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}
```

### Autoevaluación rápida

> **1. ¿Cuál es la diferencia técnica clave entre `PreToolUse` y `PostToolUse`?**
>
> > [!TIP]
> > **Respuesta:** `PreToolUse` se ejecuta *antes* de la herramienta y puede abortar la acción si sale con código no nulo. `PostToolUse` se ejecuta *después* del éxito de la operación y se emplea para limpieza o formateo no bloqueante.

> **2. ¿Por qué se añade `|| true` en los comandos de formateo?**
>
> > [!TIP]
> > **Respuesta:** Para evitar que cualquier advertencia o fallo menor del formateador detenga la respuesta del modelo con un código de error.

> **3. ¿Qué variable de entorno contiene la ruta del archivo recién modificado?**
>
> > [!TIP]
> > **Respuesta:** La variable `$CLAUDE_FILE_PATH`.

### Lista de verificación para desplegar Hooks

- [ ] Creada la carpeta `.claude/` y el archivo `settings.json` en la raíz del proyecto.
- [ ] Configurado el formateo automático de archivos mediante `PostToolUse` + `Prettier`.
- [ ] Añadido el control de calidad `PreToolUse` sobre `Bash(git commit*)` con `typecheck`.
- [ ] Conectada la notificación auditiva o de escritorio al evento `Stop`.
- [ ] Comprobados todos los comandos en una terminal limpia antes de guardarlos.
- [ ] Verificado que ningún comando solicita contraseñas o confirmaciones `[y/N]` por consola.