Skip to content

Hooks (ganchos): Acciones automáticas en momentos fijos

📚 Navegación de la serie: El artículo anterior 32 Estilos de salida (Output Styles) te enseñó cómo cambiar de "personalidad" para que Claude trabaje con el tono que deseas. En este artículo hablaremos de otra forma de "automatización": no se trata de cambiar cómo responde, sino de ejecutar una acción de forma obligatoria en el instante preciso en que ocurre un evento: formatear el código tras modificar un archivo, bloquear comandos peligrosos de forma directa o recibir una notificación al terminar una tarea. Esto es lo que hacen los Hooks (ganchos).

Imagina esta cifra: en una semana, la cantidad de veces que tuviste que ejecutar manualmente prettier --write después de que Claude modificara el código fue de 23 veces.

23 veces. Un mismo movimiento repetido de forma mecánica 23 veces. Lo peor fue que en dos ocasiones se te olvidó hacerlo, los cambios se subieron al repositorio y la validación de formato de la integración continua (CI) los rechazó, obligándote a repetir todo el proceso.

En ese momento es cuando debes hacerte una pregunta: ¿por qué una tarea repetitiva e idéntica debe depender de tu memoria o de la buena voluntad de Claude? Habíamos escrito en CLAUDE.md la instrucción "ejecuta prettier tras editar un archivo", pero una de cada tres veces a Claude se le olvidaba hacerlo; eso se debe a que esa regla es una petición, no una garantía.

Sin embargo, al configurar un Hook, con una sola línea de configuración resuelves el problema para siempre: a partir de ese momento, cada vez que Claude edite un archivo, el formateador se ejecutará automáticamente; no tendrás que volver a escribir prettier manualmente ni la CI volverá a rechazar tus cambios. En este artículo explicaremos qué son, cómo configurarlos y cómo depurarlos.

Al terminar de leer este artículo, obtendrás:

  • Una explicación en una frase de qué es un Hook y en qué punto fundamental se diferencia de las "peticiones escritas en CLAUDE.md".
  • En qué momentos específicos del ciclo de vida de Claude puedes colgar un Hook (PreToolUse / PostToolUse / Stop / SessionStart, etc.).
  • En qué archivo se configuran los Hooks y cómo usar matcher para limitar su ejecución a situaciones como "solo al modificar un archivo".
  • Tres ejemplos reales listos para copiar: formatear automáticamente tras modificar, bloquear comandos peligrosos y enviar notificaciones.
  • El canal de comunicación entre los Hooks y Claude (JSON por stdin, códigos de salida y stdout): la clave para entenderlo todo.
  • Los pasos a seguir cuando un Hook no responde o devuelve un error.

01 Primero entiende: Qué es un Hook y el valor de su "garantía"

Empecemos con la conclusión: un Hook es "un comando de shell o una petición que se ejecuta automáticamente en el instante preciso en que ocurre un evento determinado". Su activación no depende de que Claude decida ejecutarlo; su disparo está garantizado. (Soporta comandos de shell, peticiones HTTP, herramientas de MCP e instrucciones para el LLM).

La definición oficial es muy clara:

Los hooks son comandos de shell definidos por el usuario que se ejecutan en momentos específicos del ciclo de vida de Claude Code. Ofrecen un control determinista sobre el comportamiento de Claude Code, garantizando que ciertas acciones ocurran siempre en lugar de depender de que el LLM decida ejecutarlas.

Presta atención a los términos: "control determinista" y "garantizando que ocurran siempre". Esa es la clave de los Hooks.

Analogía: Reglas de automatización en tu casa inteligente ("Cuando... entonces..."). Configuras reglas como "cuando se abra la puerta, entonces enciende la luz" o "cuando salga de casa, entonces apaga los enchufes". Si se cumple la condición, el evento ocurre sin excepción y sin que nadie tenga que acordarse de hacerlo. Los Hooks son esas mismas reglas para Claude Code: defines "cuando ocurra X evento, entonces ejecuta este comando" y el sistema lo ejecutará de forma obligatoria.

Es vital asimilar la diferencia fundamental: lo escrito en CLAUDE.md es una "petición" (Claude intentará seguirla pero puede olvidarla); un Hook configurado es una "garantía" (si ocurre el evento, la acción se ejecutará obligatoriamente, sin importar si Claude lo recuerda o no). Palabras oficiales de la documentación:

Las instrucciones en CLAUDE.md o en un skill del tipo "nunca edites .env" son peticiones, no garantías. Un hook PreToolUse que bloquee la edición es una medida de obligado cumplimiento.

Esta es la explicación de las 23 ejecuciones manuales de prettier: escribirlo en CLAUDE.md es una petición (falla una de cada tres veces); configurarlo como Hook es una garantía (no falla nunca).

Casos de uso habituales que justifican aplicar una "garantía":

  • "Formatear o pasar el linter tras modificar un archivo" → Automatízalo para no tener que escribirlo tú ni confiar en que lo haga Claude.
  • "Bloquear de forma segura comandos peligrosos como rm -rf o la edición de claves" → Requiere un bloqueo seguro que no dependa de la IA.
  • "Enviar una notificación de escritorio cuando requiera aprobación o termine una tarea" → Te permite centrarte en otras tareas sin tener que vigilar la terminal.

💡 Resumen en una frase: Un Hook es una "acción automática desencadenada por un evento". Su valor reside en transformar una "petición" en una "garantía": las reglas de CLAUDE.md pueden olvidarse, pero el Hook se ejecutará siempre que ocurra el evento.


02 En qué momentos se pueden colgar los Hooks: El ciclo de vida de Claude

Un Hook no puede ejecutarse en cualquier momento; debe asociarse a un momento específico del flujo de trabajo de Claude. Estos momentos se conocen oficialmente como eventos (events). Para usar bien los Hooks, lo primero es saber en qué instante quieres que ocurra la acción.

Si recuerdas el "ciclo de agente" del artículo 03, el trabajo de Claude es un bucle continuo de "pensar → hacer → observar". Estos eventos se distribuyen a lo largo de este ciclo. La documentación oficial los clasifica según su frecuencia de disparo en tres grupos, una división muy fácil de recordar:

  • Una vez por conversación: SessionStart (al iniciar o reanudar la sesión) y SessionEnd (al finalizar la sesión).
  • Una vez por turno de chat: UserPromptSubmit (cuando envías un prompt y antes de que Claude lo procese) y Stop (cuando Claude termina de responder en ese turno).
  • En cada llamada a herramientas: PreToolUse (justo antes de ejecutar una herramienta) y PostToolUse (justo después de ejecutar una herramienta con éxito).

Para visualizar dónde se sitúan estos eventos en el flujo, revisa la siguiente imagen:

Los 7 momentos para los Hooks en Claude Code: SessionStart → UserPromptSubmit → Bucle Pre/Post herramienta → Stop → SessionEnd

El diagrama muestra el flujo: al entrar a la sesión se dispara SessionStart, cuando hablas se dispara UserPromptSubmit, y luego se entra en el bucle de "ejecución de herramientas". Cada vez que usa una herramienta, se dispara PreToolUse antes y PostToolUse después; al terminar de responder se dispara Stop, y al cerrar la sesión SessionEnd. Asocia tu acción al evento del flujo que corresponda.

Aunque la herramienta soporta decenas de eventos avanzados (como PreCompact/PostCompact al consolidar contexto, FileChanged al cambiar archivos en disco, ConfigChange al alterar la configuración, o SubagentStart/SubagentStop al iniciar o parar subagentes), estudiar y dominar estos cuatro cubrirá el 90% de tus necesidades:

EventoCuándo se disparaCaso de uso típico
PreToolUseAntes de ejecutar una herramientaBloquear comandos peligrosos, proteger archivos sensibles (puede cancelar la acción)
PostToolUseDespués de ejecutar una herramienta con éxitoFormatear el código o pasar el linter tras modificar archivos
StopAl terminar de responder en el turno actualVerificar que la tarea se ha completado, inspeccionar el área de trabajo
SessionStartAl iniciar o reanudar la sesiónInyectar información sobre el estado del proyecto (como los últimos commits) en el contexto

Un truco para recordar su comportamiento: fíjate en los prefijos Pre y Post. Pre significa "antes", por lo que es el único que puede bloquear la acción antes de que ocurra; Post significa "después", es decir, la herramienta ya se ha ejecutado y solo puedes actuar "a toro pasado" (formatear, registrar logs), pero no puedes evitar la ejecución. Analizaremos esto en la siguiente sección.

💡 Resumen en una frase: Los Hooks se asocian a eventos específicos del ciclo de vida de Claude, clasificados por frecuencia (por sesión, por turno o por herramienta); céntrate en dominar PreToolUse (antes, puede bloquear), PostToolUse (después, acción posterior), Stop (fin de turno) y SessionStart (inicio de sesión).


03 Dónde se configuran los Hooks y cómo acotarlos con matcher

Una vez que sabemos qué eventos escuchar, veamos cómo escribirlos. Los Hooks se configuran dentro de los archivos de configuración (settings.json) que estudiamos en el artículo 31. El archivo elegido determinará su ámbito de aplicación:

Archivo de configuraciónÁmbito¿Se comparte en git?
~/.claude/settings.jsonTodos tus proyectosNo, es de uso exclusivo en tu máquina
.claude/settings.json (raíz del proyecto)Solo en este proyecto, se incluye en el repositorio de git
.claude/settings.local.json (raíz del proyecto)Solo en este proyectoNo, lo ignora git automáticamente

Sigue la misma lógica que vimos en la configuración ("archivador de proyecto frente a cajón de usuario"): los Hooks comunes del equipo (como formatear tras guardar) se configuran a nivel de proyecto en .claude/settings.json en git; las preferencias personales (como notificaciones de escritorio) se guardan a nivel global en ~/.claude/settings.json.

Estructura de la configuración de un Hook

Veamos un ejemplo básico y representativo: "formatear con prettier automáticamente tras editar con Edit o Write", la solución al problema de formato inicial. Lo añadimos al archivo .claude/settings.json en la raíz del proyecto:

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}

Analicemos las tres secciones de esta configuración:

  1. "PostToolUse": el evento al que asociamos la acción (aquí: tras ejecutar una herramienta).
  2. "matcher": "Edit|Write": acota qué herramientas disparan el Hook (aquí: solo tras usar Edit o Write, no con Bash ni Read).
  3. El array hooks interno: define la acción a ejecutar: "type": "command" indica que ejecuta un comando de shell, y "command" detalla la orden.

El comando usa jq, una utilidad para procesar JSON (se instala con brew install jq en Mac o apt-get install jq en Ubuntu). Lo explicaremos en la siguiente sección: sirve para extraer la ruta del archivo modificado (tool_input.file_path) de los datos JSON que le entrega Claude, pasándola como argumento a prettier.

matcher: Acotar el disparo a situaciones específicas

La opción matcher es uno de los campos más importantes de la configuración. Su función es: sin matcher, el Hook se ejecutará en cada evento del tipo configurado; con matcher, limitas el disparo a las herramientas que definas.

Analogía: Las normas de acceso de un vigilante de seguridad. Si no defines un criterio, el vigilante detendrá a cualquiera que cruce la puerta, ralentizando el flujo; con un matcher, el vigilante solo detendrá a los repartidores, dejando pasar a los demás sin detenerlos. matcher define ese filtro de acceso.

Para eventos de herramientas (PreToolUse/PostToolUse), matcher filtra por el nombre de la herramienta. Puedes configurarlo de tres formas:

matcher configuradoComportamientoEjemplo
"Edit|Write"Coincidencia exacta con las herramientas indicadas (separadas por |)Se activa solo al usar Edit o Write
"Bash"Coincidencia con una sola herramientaSe activa solo al usar Bash
"" o si se omiteCoincide con todoSe activa siempre que ocurra el evento

Importante: matcher distingue entre mayúsculas y minúsculas; escribir edit no coincidirá con la herramienta Edit. Esta es una causa común por la que los Hooks no se activan.

Ten en cuenta también que algunos eventos no soportan matcher (como UserPromptSubmit o Stop), ya que no están vinculados a herramientas concretas y se ejecutan siempre ante su evento. Si añades un matcher a estos eventos, se ignorará.

💡 Resumen en una frase: Los Hooks se configuran en settings.json (Usuario para global, Proyecto para compartido). Su estructura consta de: evento, matcher e instrucciones; matcher limita la ejecución a herramientas específicas y distingue mayúsculas y minúsculas.


04 Comunicación entre el Hook y Claude: stdin, códigos de salida y stdout

Esta es la clave para entender la integración. ¿Cómo extrae el comando la ruta del archivo? ¿Cómo consigue un Hook bloquear una acción? La respuesta está en sus canales de comunicación.

La comunicación se apoya en tres canales estándar: Claude envía los datos del evento en formato JSON a través del canal de entrada stdin al script → el script procesa la información → el script indica a Claude cómo proceder a través de su "código de salida" y la salida estándar stdout. Analicemos cada canal.

Entrada: Claude te entrega un JSON por stdin

Al dispararse el evento, Claude Code escribe los datos de ese evento en formato JSON en el canal de entrada estándar (stdin) de tu comando. Por ejemplo, al intentar ejecutar un comando en Bash, el Hook PreToolUse recibirá esta información:

json
{
  "session_id": "abc123",
  "cwd": "/Users/sarah/myproject",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "npm test"
  }
}

Toda la información (qué acción quiere realizar, con qué herramienta y qué parámetros) está disponible en el JSON. La orden jq -r '.tool_input.file_path' del artículo anterior extrae el valor del campo tool_input.file_path (la ruta del archivo editado). La opción -r de jq indica que devuelva el texto plano sin comillas.

Salida: El código de salida indica a Claude qué hacer

El script indica su resultado a Claude a través de su código de salida (exit code). Esta es la convención del sistema; recuerda estos tres códigos:

Código de salidaSignificadoComportamiento
0CorrectoContinúa la ejecución (en PreToolUse, no significa aprobación directa, se aplican las reglas de autorización habituales)
2BloquearCancela la ejecución; el texto que escribas en el canal de errores stderr se enviará a Claude como feedback para que corrija la acción
Otros (como 1)Error de ejecuciónContinúa la ejecución y muestra el aviso de fallo del Hook en la terminal

Presta atención a exit 2: es la única vía para que el Hook cancele una acción. Ten en cuenta este comportamiento que puede ir en contra de tu intuición:

En la mayoría de eventos de hooks, solo el código de salida 2 cancela el proceso. Claude Code interpreta el código de salida 1 como un fallo que no bloquea la ejecución y continúa con la tarea, a pesar de ser el código estándar de error en Unix. Si quieres forzar la cancelación por seguridad, usa exit 2.

Es decir: para bloquear una acción, tu script debe devolver exit 2, no exit 1. Si usas el código exit 1 habitual en Unix, verás un error en la terminal pero el comando se ejecutará igualmente. Es un error común al diseñar Hooks de seguridad; el script detecta el peligro y muestra un aviso, pero al terminar con exit 1, Claude continúa con la ejecución.

Recuerda también que solo los eventos Pre pueden bloquear la acción. Si un Hook PostToolUse devuelve exit 2, no podrá evitar la acción porque esta ya se ha completado; se limitará a mostrar el error de stderr en el chat de Claude. Pre sirve para bloquear; Post actúa como acción posterior.

Avanzado: Salidas JSON por stdout para un control detallado

Los códigos de salida ofrecen una respuesta binaria (bloquear o continuar). Si necesitas mayor control (como indicar a Claude el motivo del bloqueo o inyectar información en el contexto), termina con exit 0 y escribe un JSON en la salida estándar stdout.

Usa el código de salida 2 con stderr para "bloquear", o escribe un JSON con código de salida 0 para un "control detallado". No los mezcles: si devuelves un código de salida 2, Claude Code ignorará la salida de stdout.

Analicemos los dos casos de uso de JSON en stdout:

1. Cancelar en PreToolUse detallando el motivo → usando permissionDecision:

json
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Este comando modifica la base de datos de producción y está prohibido"
  }
}

Los valores admitidos por permissionDecision son: "deny" (bloquea la acción y envía la explicación a Claude), "ask" (pregunta al usuario de forma habitual), "allow" (ejecuta directamente sin preguntar) o "defer" (aplaza la ejecución, útil para flujos de aprobación asíncronos en entornos no interactivos).

Aquí debemos destacar una regla de seguridad muy importante relacionada con los artículos 20 y 21: un Hook que devuelva "allow" no puede eludir tus reglas de autorización de settings.json. Palabras oficiales de la documentación:

Devolver "allow" evita la pregunta interactiva en consola pero no anula las reglas de permisos. Si una regla deniega el uso de una herramienta, la acción se bloqueará aunque el hook devuelva "allow".

Es decir: un Hook solo puede restringir permisos, nunca otorgar más accesos de los permitidos por las reglas de autorización. Este diseño de seguridad evita que un Hook malicioso pueda abrir accesos comprometiendo el sistema. Por contra, la prioridad de bloqueo de un Hook PreToolUse es máxima: incluso si inicias Claude con --dangerously-skip-permissions (saltarse todas las autorizaciones), si un Hook devuelve deny, la acción se bloqueará. Los Hooks son una excelente forma de establecer límites de seguridad infranqueables en el equipo.

2. Inyectar información en el contexto en SessionStart → escribe el texto en stdout directamente (estos eventos procesan la salida de stdout inyectándola en el contexto de Claude). Por ejemplo, para informarle de los últimos 5 commits al iniciar la sesión:

json
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "git log --oneline -5"
          }
        ]
      }
    ]
  }
}

💡 Resumen en una frase: La comunicación se realiza por tres vías: el JSON de entrada en stdin, el código de salida para definir la acción y stdout para enviar JSON de control; recuerda: usa exit 2 para bloquear, no mezcles códigos de error con JSON en stdout, y ten en cuenta que los Hooks no pueden eludir las reglas de autorización básicas.


05 Tres ejemplos prácticos listos para usar

Veamos tres ejemplos habituales de Hooks listos para incorporar a tus proyectos, detallando el evento, el matcher y el nivel recomendado.

Ejemplo 1: Formatear el código automáticamente tras modificar (PostToolUse)

La solución para el formateador de código. Es seguro y no tiene efectos secundarios; te recomendamos configurarlo en todos tus proyectos. Lo añadimos a nivel de proyecto en .claude/settings.json:

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}

Mecánica: cada vez que Claude edita un archivo con Edit o Write → el Hook procesa el JSON de stdin y extrae la ruta del archivo → ejecuta prettier --write sobre ese archivo. El formato se mantiene siempre unificado y sin intervención manual. Puedes adaptar la orden para usar eslint --fix, gofmt, black u otros formateadores según el lenguaje.

Ejemplo 2: Bloquear comandos peligrosos (PreToolUse con script)

Este ejemplo implementa la cancelación con exit 2. Al ser una lógica compleja, es más ordenado estructurarla en un script independiente en lugar de escribirla dentro del JSON.

Paso 1: Crea el script en .claude/hooks/block-dangerous.sh:

bash
#!/bin/bash
# block-dangerous.sh: Bloquea comandos Bash peligrosos
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')

if echo "$COMMAND" | grep -q "rm -rf"; then
  echo "Acción bloqueada: detectado comando rm -rf en la instrucción" >&2   # Se envía a stderr para Claude
  exit 2                                                                     # exit 2 cancela la ejecución
fi

exit 0   # Permite la ejecución, aplicando las reglas de autorización normales

Paso 2: Concede permisos de ejecución al script (obligatorio en entornos Mac e Linux para que Claude pueda ejecutarlo):

bash
chmod +x .claude/hooks/block-dangerous.sh

Paso 3: Registra el script en .claude/settings.json, asociándolo al evento PreToolUse de la herramienta Bash:

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-dangerous.sh"
          }
        ]
      }
    ]
  }
}

Usamos la variable de entorno $CLAUDE_PROJECT_DIR proporcionada por Claude Code, que apunta a la raíz del proyecto. De este modo, la ruta al script se resolverá correctamente sin importar en qué subcarpeta inicies la sesión.

⚠️ Advertencia de seguridad (en línea con el artículo 21): los Hooks se ejecutan con tus privilegios de usuario en la máquina, por lo que tienen acceso a tus archivos y comandos. Revisa el código de cualquier script antes de añadirlo como Hook, y evita copiar código de internet sin comprobar su funcionamiento.

Ejemplo 3: Enviar una notificación de escritorio (Notification)

Si Claude requiere que apruebes un paso o ha terminado una tarea pesada y has cambiado de ventana, este Hook te enviará un aviso de escritorio. Se asocia al evento Notification (se dispara cuando Claude genera una notificación).

En macOS lo guardamos en la configuración de usuario ~/.claude/settings.json (al ser una preferencia personal, se define a nivel global):

json
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code requiere tu atención\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Comandos según el sistema operativo (órdenes nativas listas para usar):

Sistema operativoComando a usar en command
macOSosascript -e 'display notification "..." with title "Claude Code"'
Linuxnotify-send 'Claude Code' '...'
WindowsLlamada a PowerShell MessageBox (ver ejemplos en la documentación oficial)

Nota para macOS: si las notificaciones no se muestran, comprueba en "Ajustes del Sistema → Notificaciones" que el Editor de Scripts (Script Editor) tiene concedidos los permisos para mostrar avisos.

💡 Resumen en una frase: Dispones de tres ejemplos listos para adaptar: formato de archivos (en PostToolUse, seguro y recomendado), bloqueo de comandos (en PreToolUse, requiere chmod +x y exit 2) y avisos de escritorio (en Notification, según tu sistema operativo); utiliza $CLAUDE_PROJECT_DIR para definir rutas en el repositorio.


06 Práctica: Configurar un Hook en 5 minutos y verificar su ejecución

Pasemos a la práctica. Diseñaremos un Hook seguro e inocuo para ver su funcionamiento: hacer que cada vez que Claude ejecute un comando Bash, este se registre en un archivo de log. No modificaremos código del proyecto y comprobaremos el resultado de forma directa.

Nota: este ejercicio requiere la utilidad jq. Si no la tienes instalada, ejecuta brew install jq en Mac o sudo apt-get install jq en Ubuntu.

Paso 1: Crear la configuración a nivel de proyecto

Crea el archivo .claude/settings.json en una carpeta vacía de prueba e introduce la siguiente configuración (si ya tienes un archivo de configuración, añade la clave hooks sin sobrescribir lo demás):

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.command' >> ~/claude-bash-log.txt"
          }
        ]
      }
    ]
  }
}

Esta regla indica: tras ejecutar la herramienta Bash (PostToolUse con matcher: "Bash") → extrae el comando de los datos JSON en stdin → añádelo con >> al final del archivo claude-bash-log.txt en tu directorio de usuario.

Paso 2: Iniciar Claude y verificar el registro del Hook

bash
claude

Escribe en el chat:

text
/hooks

Resultado esperado: se abrirá una pantalla interactiva de solo lectura que muestra los Hooks registrados. Navega hasta el evento PostToolUse y verás que contiene un Hook configurado. Al seleccionarlo, mostrará los detalles: el matcher (Bash), el origen (Project, es decir, .claude/settings.json) y el comando configurado. Verlo en esta lista confirma que el Hook se ha registrado con éxito.

Nota: La pantalla de /hooks es solo para inspeccionar recursos; no permite añadir ni modificar Hooks. Para realizar cambios, edita el archivo settings.json o pídele a Claude que lo haga.

Paso 3: Pedir a Claude que ejecute un comando Bash

Regresa a la conversación pulsando Esc y pídele que ejecute un comando sencillo:

text
Muestra la lista de archivos de la carpeta actual con ls

Claude utilizará la herramienta Bash para ejecutar ls. Esta acción disparará el Hook PostToolUse en segundo plano (los Hooks se ejecutan de forma silenciosa, por lo que no verás avisos en la terminal).

Paso 4: Validar el resultado en el archivo de log

Abre otra terminal y consulta el archivo de registro:

bash
cat ~/claude-bash-log.txt

Resultado esperado: el archivo contendrá la línea ls (y cualquier otra orden de Bash ejecutada durante la sesión). Ver la orden en el archivo confirma que el Hook se ha ejecutado de forma automática tras usar la herramienta, validando el funcionamiento del automatismo.

Paso 5: Limpieza (opcional)

Para deshacer los cambios, elimina la sección hooks del archivo .claude/settings.json (para borrar un Hook basta con retirarlo del archivo de configuración) y borra el archivo de logs con rm ~/claude-bash-log.txt.

Al completar estos pasos habrás comprobado el flujo de trabajo: escribir la configuración → comprobar el registro con /hooks → disparar el evento → verificar el resultado. Cualquier Hook que configures en el futuro seguirá esta estructura.

💡 Resumen en una frase: Diseña un Hook de registro para probar: escribe la configuración en .claude/settings.json → comprueba su registro con /hooks → pide a Claude que ejecute un comando Bash → valida el archivo de logs en tu máquina; verificar la salida te ayudará a entender el funcionamiento en segundo plano.


07 Resolución de problemas: Si el Hook no se activa o da error

Si un Hook no responde o da fallos al configurarlo, sigue estos pasos de diagnóstico ordenados por frecuencia de error:

SíntomaCausa probable a comprobar
El Hook no se activa1. Ejecuta /hooks para verificar si aparece en la lista.
2. El matcher distingue mayúsculas y minúsculas: edit no coincidirá con Edit.
3. El evento es incorrecto: si quieres bloquear una acción antes de ejecutarse, usa PreToolUse, no PostToolUse.
El Hook no aparece en /hooks1. La sintaxis del JSON es incorrecta (los archivos JSON no admiten comentarios ni comas sueltas al final).
2. La ruta del archivo de configuración es incorrecta (a nivel de proyecto debe estar en .claude/settings.json, y a nivel global en ~/.claude/settings.json).
3. Si acabas de guardar el archivo, reinicia la sesión para forzar la lectura.
Aviso de error hook error en la terminalEl script ha finalizado con un código de salida distinto de cero de forma inesperada. Pruébalo en tu terminal (ver comando abajo). Si indica command not found, comprueba la ruta al script usando $CLAUDE_PROJECT_DIR o rutas absolutas; si indica jq: command not found, instala la utilidad jq.
El script no se ejecutaEn sistemas Mac e Linux, comprueba que has concedido permisos de ejecución al archivo con chmod +x.
La acción no se bloquea al fallarHas usado el código de salida exit 1; cámbialo a exit 2 (ver detalles en la sección 04).

Dos métodos de depuración muy útiles:

1. Probar el script de forma aislada pasando datos simulados. No necesitas iniciar la sesión de Claude; puedes pasarle una estructura JSON equivalente por la terminal y comprobar su comportamiento y código de salida:

bash
echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /tmp/x"}}' | ./block-dangerous.sh
echo $?   # Muestra el código de salida: un script de bloqueo debe devolver 2

Este es el procedimiento recomendado: depura tu script en la consola y, cuando funcione correctamente, asócialo como Hook en Claude.

2. Activar los logs de depuración para analizar el comportamiento. Si quieres ver qué Hooks coinciden, qué códigos de salida devuelven y qué escriben en stdout o stderr, inicia Claude con --debug. Los logs se guardarán en ~/.claude/debug/<conversation_id>.txt:

bash
claude --debug

También puedes activar la depuración en caliente escribiendo /debug en el chat. Los logs mostrarán información detallada de la ejecución de los Hooks:

text
[DEBUG] Executing hooks for PostToolUse:Bash
[DEBUG] Hook command completed with status 0

Si sospechas que un Hook está provocando fallos en la conversación y quieres desactivar todos los Hooks de forma temporal, añade "disableAllHooks": true en tu archivo de configuración, evitando tener que borrarlos uno a uno.

💡 Resumen en una frase: Si un Hook falla, sigue este orden: inspecciona /hooks → comprueba mayúsculas y minúsculas en el matcher → depura el script pasando un JSON de prueba en la consola → inicia con --debug para ver los registros del sistema; recuerda que solo exit 2 bloqueará la ejecución.


08 Resumen

En este artículo hemos estudiado los Hooks en Claude Code, analizando su funcionamiento, momentos de ejecución y métodos de depuración.

Repasemos los puntos clave:

ConceptoDefinición / ComportamientoDetalle clave
Qué es un HookAcción automática ante un eventoConvierte una "petición" en una "garantía", asegurando la ejecución.
Cuándo se ejecutaEventos del ciclo de vidaPre para bloquear antes de la acción, Post para ejecutar después, Stop al terminar el turno, SessionStart al iniciar.
Estructura en JSONConfigurado en settings.jsonSe define el evento, el matcher (filtro por herramienta sensible a mayúsculas) y la acción.
Flujo de comunicaciónstdin / códigos de salida / stdoutClaude envía un JSON por stdin, el script decide con su código de salida (exit 2 para bloquear) y se ayuda de stdout para enviar JSON de control.
Medidas de seguridadLímite de permisosLos Hooks solo pueden restringir permisos (deny), nunca otorgar más accesos de los definidos en settings.json.
Método de depuraciónConsola y logsDepura el script de forma independiente en la terminal y usa --debug para leer los registros del motor de Claude Code.

Ahora deberías ser capaz de: explicar la diferencia de diseño entre una petición en CLAUDE.md y la garantía de un Hook, identificar en qué momento del ciclo de vida de Claude asociar una tarea, configurar un Hook en settings.json usando matchers para filtrar herramientas, programar scripts que interactúen con Claude a través de stdin/código de salida/stdout, y depurar fallos en caliente usando logs de depuración. Implementar Hooks te otorga el control absoluto y determinista sobre las acciones y seguridad de Claude en tus desarrollos.

Con esto cerramos el estudio de la automatización en la configuración. Tienes las herramientas para formatear código, registrar logs y bloquear accesos de forma segura y desasistida.


En el próximo artículo, 34 "Referencia de la CLI: Comandos y flags", entraremos en el bloque de referencia de comandos. A lo largo de la serie hemos usado la terminal para iniciar Claude Code, activar depuración o pasar parámetros de seguridad. En la siguiente sección recopilaremos la guía de referencia completa de comandos y opciones de la consola (CLI), estructurada como un diccionario de consulta rápida. Piensa en esto: ¿cuántos flags de inicio de Claude Code conoces? Al revisar el próximo artículo verás que existen opciones muy útiles para simplificar tus comandos diarios que aún no has utilizado.


Lecturas recomendadas