IA /

IA:Hook

Descripción

Un hook de Claude es una función que se ejecuta automáticamente antes o después de ciertas acciones dentro de Claude Code, permitiéndote interceptar, modificar o extender el comportamiento normal del entorno. Actúa como un punto de inserción donde puedes añadir lógica personalizada sin tener que alterar el flujo principal del sistema.

En la práctica, los hooks sirven para automatizar tareas, validar datos, transformar entradas o salidas, o integrar comportamientos adicionales cuando Claude ejecuta comandos, lee archivos o interactúa con herramientas. Funcionan como pequeñas piezas de middleware que te permiten adaptar Claude Code a tus necesidades sin tocar su núcleo.

Normalmente los hooks se guardan en .claude/settings.json o si son personales dentro de .claude/settings.local.json. Esto es un ejemplo de hook.

  1. {
  2.   "hooks": {
  3.     "PreToolUse": [
  4.       {
  5.         "matcher": "Bash",
  6.         "hooks": [
  7.           {
  8.             "type": "command",
  9.             "if" : "(Bash git *)",
  10.             "StatusMessage" : "Ejecutando HOOK 001",
  11.             "command": "$input = $Input | ConvertFrom-Json; $entry = @{ts=(Get-Date -Format o); session=$input.session_id; cmd=$input.tool_input.command} | ConvertTo-Json -Compress; $logDir = Join-Path $env:CLAUDE_PROJECT_DIR '.claude/logs'; New-Item -ItemType Directory -Force -Path $logDir | Out-Null; Add-Content -Path (Join-Path $logDir 'audit.jsonl') -Value $entry",
  12.             "shell": "powershell",
  13.             "async": true
  14.           }
  15.         ]
  16.       }
  17.     ]
  18.   }
  19. }

Un hook es un script, endpoint HTTP, prompt LLM o subagente que se ejecuta automáticamente cuando ocurre un evento específico en Claude Code. A diferencia de las instrucciones en CLAUDE.md (que son sugerencias que el modelo puede o no seguir), los hooks son deterministas: garantizan que la acción se ejecuta siempre, sin excepción.

Analogía: Si CLAUDE.md es un cartel de "por favor, cierra la puerta al salir", un hook es un mecanismo automático que cierra la puerta cada vez que alguien pasa.

Los cuatro tipos de handler

Claude Code soporta cuatro tipos de hooks, cada uno con un caso de uso diferente:

command

Descripción: Ejecuta un comando shell. Recibe JSON por stdin, devuelve resultado por exit code + stdout.

Cuándo usarlo: Scripts locales, validaciones rápidas, formateo, notificaciones.

http

Descripción: Envía un POST HTTP con el JSON del evento a una URL.

Cuándo usarlo: Integración con servicios externos, webhooks, APIs de equipo.

prompt

Descripción: Envía un prompt a un modelo Claude para evaluación sí/no en un solo turno.

Cuándo usarlo: Decisiones que requieren juicio semántico, no reglas fijas.

agent

Descripción: Genera un subagente con acceso a herramientas (Read, Grep, Glob) para verificar condiciones.

Cuándo usarlo: Validaciones complejas que necesitan inspeccionar archivos o código.

Eventos disponibles

Claude Code expone más de 20 eventos en su ciclo de vida. Estos son los más utilizados en flujos de trabajo profesionales:

SessionStart

Cuándo se dispara: Al iniciar o reanudar una sesión.

Uso típico: Cargar contexto, variables de entorno, verificar dependencias.

UserPromptSubmit

Cuándo se dispara: Al enviar un prompt, antes de que Claude lo procese.

Uso típico: Enriquecer contexto, validar, filtrar prompts.

PreToolUse

Cuándo se dispara: Antes de ejecutar una herramienta.

Uso típico: Validar, bloquear, modificar inputs. Único evento que puede bloquear herramientas.

PermissionRequest

Cuándo se dispara: Cuando se muestra el diálogo de permisos.

Uso típico: Auto-aprobar o auto-denegar permisos programáticamente.

PermissionDenied

Cuándo se dispara: Cuando el clasificador auto-mode deniega una llamada.

Uso típico: Logging, o permitir reintento con retry: true.

PostToolUse

Cuándo se dispara: Después de que la herramienta se ejecute con éxito.

Uso típico: Formatear, lintear, logging, inyectar contexto.

PostToolUseFailure

Cuándo se dispara: Después de que una herramienta falle.

Uso típico: Logging de errores, alertas, contexto correctivo.

Notification

Cuándo se dispara: Cuando Claude envía una alerta.

Uso típico: Notificaciones de escritorio/Slack.

Stop

Cuándo se dispara: Cuando Claude termina de responder.

Uso típico: Tests finales, reportes, forzar que continúe.

StopFailure

Cuándo se dispara: Cuando el turno termina por error de API.

Uso típico: Logging de errores, alertas de rate limit.

SubagentStart

Cuándo se dispara: Cuando se crea un subagente.

Uso típico: Setup de entorno, inyección de contexto al subagente.

SubagentStop

Cuándo se dispara: Cuando un subagente termina.

Uso típico: Validar output del subagente.

TaskCreated

Cuándo se dispara: Cuando se crea una tarea (agent teams).

Uso típico: Validar convenciones de nombres, requerir descripciones.

TaskCompleted

Cuándo se dispara: Cuando se marca una tarea como completada.

Uso típico: Ejecutar tests antes de cerrar una tarea.

TeammateIdle

Cuándo se dispara: Cuando un teammate va a entrar en idle.

Uso típico: Quality gates antes de que un teammate deje de trabajar.

ConfigChange

Cuándo se dispara: Cuando cambia un archivo de configuración.

Uso típico: Auditoría, bloquear cambios no autorizados.

CwdChanged

Cuándo se dispara: Cuando cambia el directorio de trabajo.

Uso típico: Recargar variables de entorno (como direnv).

FileChanged

Cuándo se dispara: Cuando un archivo vigilado cambia en disco.

Uso típico: Recargar .envrc, .env, etc.

InstructionsLoaded

Cuándo se dispara: Cuando se carga un CLAUDE.md o .claude/rules/*.md.

Uso típico: Auditoría, observabilidad.

PreCompact / PostCompact

Cuándo se dispara: Antes/después de compactación de contexto.

Uso típico: Re-inyectar contexto crítico tras compactación.

WorktreeCreate / WorktreeRemove

Cuándo se dispara: Al crear/eliminar un worktree.

Uso típico: Soporte para VCS no-git (SVN, Perforce, Mercurial).

Elicitation / ElicitationResult

Cuándo se dispara: Cuando un servidor MCP pide input al usuario.

Uso típico: Responder programáticamente a elicitaciones MCP.

SessionEnd

Cuándo se dispara: Al terminar una sesión.

Uso típico: Cleanup, logging final.

Exit codes y comunicación

Los hooks de tipo command se comunican con Claude Code mediante exit codes, stdout y stderr:

Exit code 0

Significado: Éxito.

Comportamiento: stdout se parsea como JSON para campos de control. En UserPromptSubmit y SessionStart, stdout se añade como contexto visible para Claude.

Exit code 2

Significado: Error bloqueante.

Comportamiento: stderr se envía a Claude como error. Bloquea la operación (en eventos que lo soporten).

Otro

Significado: Error no bloqueante.

Comportamiento: stderr se muestra solo en modo verbose. La ejecución continúa.

Importante: Exit code 1 no bloquea. Es un error no bloqueante. Si tu hook debe impedir una acción, usa exit 2. Esta es una fuente común de bugs.

Qué eventos puede bloquear exit code 2

No todos los eventos soportan bloqueo. Esta es la forma más clara de verlo:

Eventos que sí puede bloquear (exit 2)

  • PreToolUse
  • PermissionRequest
  • UserPromptSubmit
  • Stop
  • SubagentStop
  • TeammateIdle
  • TaskCreated
  • TaskCompleted
  • ConfigChange
  • Elicitation
  • ElicitationResult

Eventos que no puede bloquear

  • PostToolUse
  • PostToolUseFailure
  • PermissionDenied
  • Notification
  • SubagentStart
  • SessionStart
  • SessionEnd
  • CwdChanged
  • FileChanged
  • PreCompact
  • PostCompact
  • StopFailure
  • InstructionsLoaded

Matchers y Variables de entorno en Hooks de Claude Code

Parte 1 - Qué filtra el matcher en cada evento

El campo matcher es un regex que decide si un hook se activa o no. Lo importante es que lo que filtra cambia según el evento. No todos los matchers filtran lo mismo: en unos filtra el nombre de la herramienta, en otros filtra cómo se inició la sesión, en otros filtra el nombre de un archivo.

Si omites el matcher, lo dejas vacío ("") o pones "*", el hook se activa siempre que ocurra ese evento.

A continuación tienes cada evento con sus valores de matcher, agrupados por categoría.

Eventos de herramientas: el matcher filtra el nombre de la herramienta

Estos son los eventos más usados. El matcher se compara contra el campo tool_name del JSON que recibe el hook.

Los eventos que filtran por nombre de herramienta son: PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest y PermissionDenied.

Los valores posibles del matcher para herramientas built-in son:

  • Bash — comandos de shell
  • Edit — reemplazar texto en un archivo existente
  • Write — crear o sobrescribir un archivo
  • MultiEdit — múltiples ediciones en un archivo
  • Read — leer contenido de un archivo
  • Glob — buscar archivos por patrón
  • Grep — buscar contenido en archivos con regex
  • WebFetch — obtener contenido de una URL
  • WebSearch — buscar en la web
  • Agent — crear un subagente
  • AskUserQuestion — preguntar al usuario
  • ExitPlanMode — salir del modo plan
  • Notebook* — herramientas de notebook (usando regex con *)

Para herramientas MCP, el patrón es mcp__<servidor>__<herramienta>. Por ejemplo:

  • mcp__memory__create_entities — herramienta específica del servidor Memory
  • mcp__github__search_repositories — herramienta específica del servidor GitHub
  • mcp__memory__.* — todas las herramientas del servidor Memory (usando regex)
  • mcp__.*__write.* — cualquier herramienta que contenga "write" de cualquier servidor

Como el matcher es regex, puedes combinar con pipe: Edit|Write|MultiEdit el ejemplo anterior activa el hook cuando Claude edita o escribe cualquier archivo.

Ejemplo — Formatear el código solo después de ediciones de archivo:

  1. {
  2.   "hooks": {
  3.     "PostToolUse": [
  4.       {
  5.         "matcher": "Edit|Write|MultiEdit",
  6.         "hooks": [
  7.           {
  8.             "type": "command",
  9.             "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write 2>/dev/null; exit 0"
  10.           }
  11.         ]
  12.       }
  13.     ]
  14.   }
  15. }

Ejemplo — Auditar todas las operaciones del servidor MCP de memoria:

  1. {
  2.   "hooks": {
  3.     "PreToolUse": [
  4.       {
  5.         "matcher": "mcp__memory__.*",
  6.         "hooks": [
  7.           {
  8.             "type": "command",
  9.             "command": "echo \"$(date -Is) | Memory MCP operation\" >> ~/mcp-audit.log"
  10.           }
  11.         ]
  12.       }
  13.     ]
  14.   }
  15. }

SessionStart: el matcher filtra cómo se inició la sesión

Cuando usas SessionStart, el matcher se compara contra el campo source del JSON, que indica cómo arrancó la sesión.

Valores posibles:

  • startup — sesión nueva (el usuario ejecutó claude)
  • resume — sesión reanudada con --resume, --continue o /resume
  • clear — después de ejecutar /clear
  • compact — después de una compactación automática o manual

Esto es muy útil para distinguir comportamientos. Por ejemplo, puedes re-inyectar contexto crítico solo después de compactación (cuando Claude "olvida" información), sin ejecutar el hook en cada inicio normal.

Ejemplo — Re-inyectar contexto solo después de compactación:

  1. {
  2.   "hooks": {
  3.     "SessionStart": [
  4.       {
  5.         "matcher": "compact",
  6.         "hooks": [
  7.           {
  8.             "type": "command",
  9.             "command": "echo 'RECORDATORIO: Este proyecto usa Python 3.12 con FastAPI. BD: PostgreSQL. Todos los endpoints requieren validación Pydantic.'"
  10.           }
  11.         ]
  12.       }
  13.     ]
  14.   }
  15. }

El stdout de SessionStart se añade como contexto visible para Claude, así que lo que imprimas con echo llegará directamente al modelo.

Ejemplo — Cargar variables de entorno solo en sesiones nuevas:

  1. {
  2.   "hooks": {
  3.     "SessionStart": [
  4.       {
  5.         "matcher": "startup",
  6.         "hooks": [
  7.           {
  8.             "type": "command",
  9.             "command": ".claude/hooks/setup-env.sh"
  10.           }
  11.         ]
  12.       }
  13.     ]
  14.   }
  15. }

SessionEnd: el matcher filtra por qué terminó la sesión

Valores posibles:

  • clear — el usuario ejecutó /clear
  • resume — el usuario cambió de sesión con /resume interactivo
  • logout — el usuario cerró sesión
  • prompt_input_exit — el usuario salió mientras la entrada de prompt estaba visible
  • bypass_permissions_disabled — se deshabilitó el modo bypass de permisos
  • other — cualquier otra razón de cierre

Ejemplo — Guardar un log solo cuando la sesión termina normalmente:

  1. {
  2.   "hooks": {
  3.     "SessionEnd": [
  4.       {
  5.         "matcher": "other|prompt_input_exit",
  6.         "hooks": [
  7.           {
  8.             "type": "command",
  9.             "command": "echo \"$(date -Is) | Sesión finalizada\" >> .claude/logs/sessions.log"
  10.           }
  11.         ]
  12.       }
  13.     ]
  14.   }
  15. }

Ten en cuenta que los hooks SessionEnd tienen un timeout por defecto de solo 1.5 segundos. Si necesitas más tiempo, establece la variable de entorno CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS antes de lanzar Claude Code.

Notification: el matcher filtra el tipo de notificación

Valores posibles:

  • permission_prompt — Claude necesita que apruebes un permiso
  • idle_prompt — Claude ha estado inactivo y necesita tu atención
  • auth_success — autenticación completada con éxito
  • elicitation_dialog — un servidor MCP pide input del usuario

Esto permite configurar alertas diferentes según la situación. Por ejemplo, una notificación urgente cuando Claude espera permisos, y una notificación más suave cuando simplemente está idle.

Ejemplo — Notificación de escritorio solo cuando se requieren permisos:

  1.     {
  2.       "hooks": {
  3.         "Notification": [
  4.           {
  5.             "matcher": "permission_prompt",
  6.             "hooks": [
  7.               {
  8.                 "type": "command",
  9.                 "command": "osascript -e 'display notification \"Claude necesita permisos\" with title \"⚠️ Claude Code\"'"
  10.               }
  11.             ]
  12.           }
  13.         ]
  14.       }
  15.     }

SubagentStart y SubagentStop: el matcher filtra el tipo de agente

Valores posibles:

  • Bash — subagente de tipo Bash
  • Explore — subagente de exploración
  • Plan — subagente de planificación
    Cualquier nombre de agente custom definido en .claude/agents/

Ejemplo — Inyectar contexto de seguridad a subagentes de exploración:

  1.     {
  2.       "hooks": {
  3.         "SubagentStart": [
  4.           {
  5.             "matcher": "Explore",
  6.             "hooks": [
  7.               {
  8.                 "type": "command",
  9.                 "command": "echo '{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"No leas archivos .env ni .key\"}}'"
  10.               }
  11.             ]
  12.           }
  13.         ]
  14.       }
  15.     }

ConfigChange: el matcher filtra la fuente de configuración

Valores posibles:

  • user_settings — cambios en ~/.claude/settings.json
  • project_settings — cambios en .claude/settings.json
  • local_settings — cambios en .claude/settings.local.json
  • policy_settings — cambios en managed policy settings (admin)
  • skills — cambios en archivos de .claude/skills/

Nota importante: los cambios en policy_settings no pueden ser bloqueados por hooks, aunque el hook sí se ejecuta (útil para auditoría).

Ejemplo — Auditar cualquier cambio en la configuración del proyecto:

  1.     {
  2.       "hooks": {
  3.         "ConfigChange": [
  4.           {
  5.             "matcher": "project_settings|local_settings",
  6.             "hooks": [
  7.               {
  8.                 "type": "command",
  9.                 "command": "echo \"$(date -Is) | Config changed\" >> .claude/logs/config-audit.log"
  10.               }
  11.             ]
  12.           }
  13.         ]
  14.       }
  15.     }

FileChanged: el matcher filtra por nombre de archivo (basename)

A diferencia del resto de matchers, aquí el matcher especifica qué archivos vigilar. Es una lista separada por pipes de nombres de archivo (sin ruta, solo el basename).

Ejemplos de matchers:

  • .envrc — solo el archivo .envrc
  • .env — solo el archivo .env
  • .envrc|.env — ambos archivos
  • package.json — el archivo package.json
  • Dockerfile — el Dockerfile

Este hook es especialmente útil combinado con CLAUDE_ENV_FILE para recargar variables de entorno automáticamente cuando cambian archivos de configuración.

Ejemplo — Recargar variables cuando cambia .envrc (integración con direnv):

  1.     {
  2.       "hooks": {
  3.         "FileChanged": [
  4.           {
  5.             "matcher": ".envrc|.env",
  6.             "hooks": [
  7.               {
  8.                 "type": "command",
  9.                 "command": ".claude/hooks/reload-env.sh"
  10.               }
  11.             ]
  12.           }
  13.         ]
  14.       }
  15.     }

Y el script reload-env.sh:

  1.     #!/bin/bash
  2.     # Recargar variables cuando cambia .envrc o .env
  3.     if [ -n "$CLAUDE_ENV_FILE" ]; then
  4.         if [ -f .envrc ]; then
  5.             direnv export bash >> "$CLAUDE_ENV_FILE" 2>/dev/null
  6.         fi
  7.     fi
  8.     exit 0

StopFailure: el matcher filtra el tipo de error

Valores posibles:

  • rate_limit — límite de tasa alcanzado
  • authentication_failed — fallo de autenticación
  • billing_error — error de facturación
  • invalid_request — petición inválida
  • server_error — error del servidor
  • max_output_tokens — se alcanzó el límite máximo de tokens de salida
  • unknown — error no identificado

Ejemplo — Alerta específica para rate limits:

  1.     {
  2.       "hooks": {
  3.         "StopFailure": [
  4.           {
  5.             "matcher": "rate_limit",
  6.             "hooks": [
  7.               {
  8.                 "type": "command",
  9.                 "command": "notify-send 'Claude Code' 'Rate limit alcanzado. Espera antes de continuar.'"
  10.               }
  11.             ]
  12.           }
  13.         ]
  14.       }
  15.     }

InstructionsLoaded: el matcher filtra la razón de carga

Valores posibles:

  • session_start — archivos cargados al iniciar sesión
  • nested_traversal — carga lazy al acceder a un subdirectorio con su propio CLAUDE.md
  • path_glob_match — carga lazy cuando una regla condicional con paths: coincide
  • include — archivo cargado por inclusión desde otro archivo de instrucciones
  • compact — archivos recargados después de una compactación

Este evento es solo de observación: no puedes bloquear ni modificar la carga de instrucciones.

PreCompact y PostCompact: el matcher filtra qué disparó la compactación

Valores posibles:

  • manual — el usuario ejecutó /compact
  • auto — compactación automática cuando la ventana de contexto se llenó

Elicitation y ElicitationResult: el matcher filtra el nombre del servidor MCP

El matcher se compara contra el nombre del servidor MCP que está solicitando input del usuario. Los valores dependen de los servidores MCP que tengas configurados.

Eventos sin soporte de matcher

Los siguientes eventos no soportan matchers y se disparan siempre:

  • UserPromptSubmit — siempre se ejecuta al enviar un prompt
  • Stop — siempre se ejecuta cuando Claude termina de responder
  • TeammateIdle — siempre se ejecuta cuando un teammate va a entrar en idle
  • TaskCreated — siempre se ejecuta al crear una tarea
  • TaskCompleted — siempre se ejecuta al completar una tarea
  • WorktreeCreate — siempre se ejecuta al crear un worktree
  • WorktreeRemove — siempre se ejecuta al eliminar un worktree
  • CwdChanged — siempre se ejecuta al cambiar de directorio

Si añades un campo matcher a estos eventos, será ignorado silenciosamente.

Parte 2 — Variables de entorno disponibles en hooks

Los hooks tienen acceso a ciertas variables de entorno que Claude Code establece automáticamente. Además, reciben datos del evento como JSON por stdin (en hooks de tipo command) o como body del POST (en hooks HTTP). No confundas las variables de entorno (accesibles con $VARIABLE) con los campos JSON (accesibles con jq).

Variables de entorno para todos los hooks

$CLAUDE_PROJECT_DIR

Ruta absoluta a la raíz del proyecto. Es la variable más usada para referenciar scripts relativos al proyecto. Siempre envuélvela en comillas para manejar rutas con espacios.

    {
      "type": "command",
      "command": "python3 \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/mi-hook.py"
    }

$CLAUDE_CODE_REMOTE

Se establece como "true" cuando Claude Code se ejecuta en un entorno web remoto (por ejemplo, Claude Code en la web). No se establece en la CLI local. Útil si quieres que un hook se comporte diferente en entornos remotos.

  1.     #!/bin/bash
  2.     if [ "$CLAUDE_CODE_REMOTE" = "true" ]; then
  3.         echo "Ejecutando en entorno remoto, saltando notificación de escritorio"
  4.         exit 0
  5.     fi
  6.     osascript -e 'display notification "Tarea completada" with title "Claude Code"'

Variable de entorno para persistir variables de sesión

$CLAUDE_ENV_FILE

Esta es una variable especial que solo está disponible en tres eventos: SessionStart, CwdChanged y FileChanged. Contiene la ruta a un archivo temporal donde puedes escribir sentencias export que se aplicarán a todos los comandos Bash subsiguientes de la sesión.

Usa append (>>) para no sobreescribir variables establecidas por otros hooks.

  1.     #!/bin/bash
  2.     # .claude/hooks/setup-env.sh (hook de SessionStart)
  3.     if [ -n "$CLAUDE_ENV_FILE" ]; then
  4.         echo 'export NODE_ENV=development' >> "$CLAUDE_ENV_FILE"
  5.         echo 'export PYTHONDONTWRITEBYTECODE=1' >> "$CLAUDE_ENV_FILE"
  6.         echo 'export PATH="$PATH:./node_modules/.bin"' >> "$CLAUDE_ENV_FILE"
  7.     fi
  8.     exit 0

Un patrón avanzado es capturar todas las variables de entorno que establece un script de setup (como nvm use) comparando el estado antes y después:

  1.     #!/bin/bash
  2.     ENV_BEFORE=$(export -p | sort)
  3.  
  4.     # Ejecutar setup que modifica el entorno
  5.     source ~/.nvm/nvm.sh
  6.     nvm use 20
  7.  
  8.     if [ -n "$CLAUDE_ENV_FILE" ]; then
  9.         ENV_AFTER=$(export -p | sort)
  10.         comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$CLAUDE_ENV_FILE"
  11.     fi
  12.     exit 0

Lo que NO son variables de entorno (son campos JSON)

Un error común es confundir los datos que llegan por JSON stdin con variables de entorno. Los siguientes datos llegan como parte del JSON del evento y se acceden con jq, no con $VARIABLE:

  • session_id — identificador de la sesión actual
  • transcript_path — ruta al archivo JSON de la conversación
  • cwd — directorio de trabajo actual
  • permission_mode — modo de permisos activo ("default", "auto", "plan", etc.)
  • hook_event_name — nombre del evento que se disparó
  • tool_name — nombre de la herramienta (en eventos de tool)
  • tool_input — parámetros de la herramienta (en eventos de tool)

Para acceder a ellos desde un script bash:

  1.     #!/bin/bash
  2.     input=$(cat)  # Leer todo el JSON de stdin
  3.     session_id=$(echo "$input" | jq -r '.session_id')
  4.     tool_name=$(echo "$input" | jq -r '.tool_name // empty')
  5.     command=$(echo "$input" | jq -r '.tool_input.command // empty')

O en Python:

  1.     import sys, json
  2.     data = json.load(sys.stdin)
  3.     session_id = data.get("session_id", "unknown")
  4.     tool_name = data.get("tool_name", "")

Variable de entorno para el timeout de SessionEnd

CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS

No es una variable que usen los hooks internamente, sino que la estableces tú antes de lanzar Claude Code para controlar cuánto tiempo pueden tardar los hooks de SessionEnd. El valor por defecto es 1500 milisegundos (1.5 segundos), que es bastante corto. Si tus hooks de limpieza necesitan más tiempo:

CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude

Nota sobre $CLAUDECODE : La variable CLAUDECODE (sin guion bajo) se establece como 1 en los shells que Claude Code genera con la herramienta Bash y en sesiones tmux. Pero no se establece dentro de hooks. No la uses en tus scripts de hooks porque siempre estará vacía. Existe para que tus scripts normales (no hooks) puedan detectar si están ejecutándose dentro de un shell de Claude Code.

Resumen rápido

Los matchers filtran cosas diferentes según el evento. En eventos de herramientas filtran el nombre de la herramienta (Bash, Edit, Write, etc. o nombres MCP). En SessionStart filtran cómo arrancó la sesión (startup, resume, clear, compact). En Notification filtran el tipo de alerta. En FileChanged filtran qué archivos vigilar. Y varios eventos como Stop, UserPromptSubmit o CwdChanged no soportan matchers y se disparan siempre.

Las variables de entorno disponibles en hooks son pocas pero importantes. $CLAUDE_PROJECT_DIR es la más usada para referenciar scripts. $CLAUDE_ENV_FILE solo existe en SessionStart, CwdChanged y FileChanged, y sirve para persistir variables que afectarán a todos los comandos Bash de la sesión. El resto de datos del evento (session_id, tool_name, tool_input, etc.) llega como JSON por stdin, no como variables de entorno.

Ejemplos

Script en Python para bloquear mediante Hooks la ejecución de comandos peligrosos mediante Bash

Prompt ejemplo de Hook para capturar prompts después de su ejecución.


IA : Prompts : Claude : Copilot

Última modificación de la página el 20 May 2026 a las 12h13
Powered by PmWiki