30 eventos de hook se disparan en una sesión de Claude Code. Solo 3 pueden responder.
La lista completa de eventos de hook de Claude Code, cuándo se dispara cada uno, cuáles son los 15 que pueden bloquear y la regla de stdout que se traga en silencio la salida de la mayoría de los hooks. Una referencia de campo construida ejecutando hooks en producción a lo largo de miles de sesiones de agentes.
Dos fallos aparecen una y otra vez cuando se conectan hooks a Claude Code, y no se parecen en nada.
El primero: añades un hook y no pasa nada. Ni error, ni aviso, ni línea de log. El hook simplemente no se ejecuta nunca.
El segundo: el hook se ejecuta claramente, ves sus efectos en el disco, pero el mensaje que imprime para el agente no llega nunca. El agente se comporta como si el hook no hubiera dicho nada.
Los dos vienen del mismo sitio. El sistema de hooks es más grande y menos uniforme que el puñado de eventos que cubren la mayoría de los artículos, y las reglas sobre quién puede hablarle al agente no son las que uno supondría. Esta es la referencia que nos habría gustado tener. Construimos AgentsRoom sobre estos hooks, y todo lo que sigue está citado de la referencia oficial o medido en producción.
Hay 30 eventos, no seis
La mayoría de las guías cubren PreToolUse, PostToolUse, UserPromptSubmit, Stop, Notification y SubagentStop. Esos seis son reales, y cargan con casi todo el trabajo útil. También son la quinta parte de lo que existe.
La lista completa, agrupada por lo que observa cada uno:
| Grupo | Eventos |
|---|---|
| Sesión | SessionStart, SessionEnd, Setup |
| Prompt | UserPromptSubmit, UserPromptExpansion |
| Herramientas | PreToolUse, PostToolUse, PostToolUseFailure, PostToolBatch |
| Permisos | PermissionRequest, PermissionDenied |
| Turno | Stop, StopFailure |
| Subagentes y tareas | SubagentStart, SubagentStop, TaskCreated, TaskCompleted, TeammateIdle |
| Contexto | PreCompact, PostCompact, InstructionsLoaded |
| Entorno | FileChanged, CwdChanged, ConfigChange |
| Worktrees | WorktreeCreate, WorktreeRemove |
| Interfaz | Notification, MessageDisplay |
| Elicitation MCP | Elicitation, ElicitationResult |

El orden en que se disparan los eventos dentro de una misma sesión. El bloque de herramienta se repite una vez por llamada a herramienta, y el bloque de prompt entero se repite una vez por turno.
Algunos de estos eventos cambian la forma de pensar el sistema. PostToolUseFailure existe, así que la rama «¿funcionó la herramienta?» es un evento, no algo que se deduzca de un payload. PostToolBatch se dispara una sola vez cuando se resuelve un lote de llamadas a herramientas en paralelo, que es el sitio adecuado para lanzar un linter una vez en lugar de una vez por edición. InstructionsLoaded se dispara cuando se lee CLAUDE.md, lo que te da un punto de enganche para comprobar que el agente cargó realmente las reglas que crees que cargó.
La regla de stdout que se traga la salida de la mayoría de los hooks
Es lo más útil de esta página.
Con código de salida 0, Claude Code analiza stdout en busca de campos JSON de salida. Pero que ese stdout llegue a mostrarse al agente depende del evento, y las excepciones caben en una lista corta. De la referencia:
Para la mayoría de los eventos, stdout se escribe en el log de depuración pero no se muestra en la transcripción. Las excepciones son
UserPromptSubmit,UserPromptExpansionySessionStart, donde stdout se añade como contexto que Claude puede ver y sobre el que puede actuar.
Tres eventos de treinta. Si haces echo "warning: this migration is destructive" desde un hook PostToolUse esperando que el agente lo lea, no lo leerá nunca. Tu texto se fue al log de depuración.
Hay exactamente dos formas de poner texto delante del agente desde cualquier otro evento:
- Salir con 2 y escribir en stderr. Con salida 2, Claude Code ignora stdout y cualquier JSON que contenga, y devuelve stderr al agente como mensaje de error.
- Salir con 0 e imprimir un objeto JSON que lleve
hookSpecificOutput.additionalContext.
Fíjate en la asimetría del primero. Salida 0 significa que stdout cuenta y stderr no. Salida 2 significa que stderr cuenta y stdout se descarta por completo. Invertir esto es la razón por la que un hook puede parecer perfectamente correcto y seguir mudo.
Cualquier otro código de salida es un error no bloqueante. La transcripción muestra un aviso <hook name> hook error con la primera línea de stderr, la ejecución continúa y el stderr completo acaba en el log de depuración.

Qué canal llega al agente según el código de salida. El camino discontinuo es el que todo el mundo da por hecho y no existe.
Exactamente la mitad pueden bloquear
Quince eventos detienen la acción con salida 2. Quince la ignoran y siguen adelante.
Pueden bloquear: PreToolUse, PermissionRequest, UserPromptSubmit, UserPromptExpansion, Stop, SubagentStop, TeammateIdle, TaskCreated, TaskCompleted, ConfigChange, PostToolBatch, PreCompact, Elicitation, ElicitationResult, WorktreeCreate.
No pueden bloquear: PostToolUse, PostToolUseFailure, PermissionDenied, StopFailure, Notification, SubagentStart, SessionStart, Setup, SessionEnd, CwdChanged, FileChanged, PostCompact, WorktreeRemove, InstructionsLoaded, MessageDisplay.
La consecuencia práctica: una barrera de seguridad va en PreToolUse, nunca en PostToolUse. PostToolUse se dispara después de que la herramienta haya tenido éxito. Salir con 2 ahí no deshace la escritura, solo imprime un error mientras el daño ya está en el disco. Si quieres detener un rm -rf, tienes exactamente un sitio donde hacerlo.
Que PostToolBatch bloquee mientras PostToolUse no lo hace merece una segunda mirada. Significa que una comprobación a nivel de lote todavía puede detener el turno después de que aterricen ediciones en paralelo: es lo más parecido a un veto posterior a la escritura que ofrece el sistema.
Los matchers son exactos, hasta que de repente dejan de serlo
El campo matcher cambia de estrategia de evaluación según sus propios caracteres, y nada te dice qué camino ha tomado.
| Matcher | Evaluado como |
|---|---|
"*", "", u omitido | coincide con todo |
Solo letras, dígitos, _, -, espacios, ,, | | cadena exacta, o lista de cadenas exactas separadas por | o , |
| Cualquier otra cosa | expresión regular de JavaScript sin anclar |
La trampa está en «sin anclar». La referencia es explícita: la expresión se prueba con RegExp.prototype.test, que tiene éxito con una coincidencia en cualquier parte del valor. Así que Edit.* coincide con Edit y con NotebookEdit. Si querías una sola herramienta, escribe ^Edit$.
Dos comportamientos que dependen de la versión y conviene conocer antes de depurar lo que no es:
- Los separadores por coma y la tolerancia a los espacios necesitan Claude Code v2.1.191 o posterior.
- Los guiones entraron en el conjunto de caracteres de coincidencia exacta en v2.1.195. Antes de eso, un matcher como
code-reviewerse trataba como una regex sin anclar, así que también se disparaba parasenior-code-reviewer.
En AgentsRoom acotamos nuestro propio hook de atribución de archivos con Write|Edit|MultiEdit|NotebookEdit, que se queda en la vía de la cadena exacta y coincide con esas cuatro herramientas y con nada más. Los hooks de ciclo de vida que instalamos no llevan matcher alguno, porque siempre nos conciernen.
Seis sitios pueden definir hooks, y se fusionan
El instinto es buscar un orden de precedencia. No lo hay, y eso es justo lo interesante.
| Ubicación | Alcance |
|---|---|
~/.claude/settings.json | todos tus proyectos, local a tu máquina |
.claude/settings.json | un proyecto, versionable |
.claude/settings.local.json | un proyecto, gitignorado por Claude Code |
| Managed policy settings | toda la organización, controlado por el administrador |
hooks/hooks.json de un plugin | mientras el plugin esté activado |
| Frontmatter de skill o de agente | mientras el componente esté activo |
De la referencia:
Las entradas de hook se fusionan entre los niveles de settings en lugar de reemplazarse: los settings de usuario, de proyecto y locales añaden sus propios hooks sin quitar los gestionados, y el ajuste
disableAllHooksno puede desactivar hooks gestionados desde fuera de los settings gestionados.
Así que un hook de proyecto nunca reemplaza a uno global, se apila encima. Seis fuentes, todas aditivas. Un formateador PostToolUse definido en tus settings de usuario y otra vez en el proyecto se ejecuta dos veces por edición, y el único síntoma es la sensación de lentitud.

Seis fuentes, un solo conjunto fusionado. Aquí nada reemplaza a nada.
Esto explica también por qué .claude/settings.local.json es el sitio adecuado para que una herramienta instale un hook en el proyecto de otra persona. Está acotado al proyecto, Claude Code lo gitignora y se carga sin ninguna opción de línea de comandos. Ahí es donde AgentsRoom escribe sus entradas, de modo que el .claude/settings.json versionado del usuario no se toca nunca y sus compañeros no heredan jamás una ruta específica de una máquina.
Lo que nos enseñó ejecutar hooks en producción
AgentsRoom instala hooks en cada proyecto que abre, para seguir el estado de los agentes de forma determinista y atribuir los archivos editados al agente correcto. Algunas cosas solo aparecen a esa escala.
Los nombres de evento desconocidos se ignoran en silencio. Esto no está en la documentación, y dependemos de ello. Cuando añadimos un evento de ciclo de vida nuevo a nuestro instalador, los usuarios con un CLI antiguo reciben un settings.local.json con un nombre de evento del que su binario no ha oído hablar jamás. Nada se rompe, nada avisa, la entrada se salta. Eso es lo que hace seguro publicar el instalador antes de una versión del CLI. Y es también, inevitablemente, por lo que una errata produce silencio total en vez de un error.
agent_id es lo que te dice que estás dentro de un subagente. El campo solo está presente cuando el hook se dispara dentro de una llamada a un subagente. Importa más de lo que parece: Stop se dispara cuando un subagente termina su turno, no solo el agente principal. Una regla ingenua del tipo «marcar la sesión como terminada en Stop» da toda la sesión por acabada la primera vez que vuelve cualquier subagente. Nos saltamos los eventos de fin de turno que llevan agent_id exactamente por esto.
No leas transcript_path para el turno en curso. La referencia avisa de que la transcripción se escribe de forma asíncrona y puede ir por detrás de la conversación en memoria, así que los mensajes más recientes pueden no estar todavía ahí cuando tu hook se dispara. Stop y SubagentStop reciben last_assistant_message precisamente para que nunca tengas que competir con el archivo.
Los hooks son la única señal de estado fiable. Antes de los hooks, raspábamos el PTY para averiguar si un agente estaba pensando, esperando o había terminado. Eso se rompe en cuanto el CLI se dibuja a través del buffer de pantalla alternativo del terminal, que es lo que hace /tui fullscreen. Los hooks se disparan igual bajo cualquier renderizador. Si estás construyendo algo que observe a un agente desde fuera, esta es la capa sobre la que construir, y el raspado se queda como plan B en el mejor de los casos.
async: true no cuesta nada. Un comando de hook puede declarar async: true, y el agente no lo espera. Nuestro hook hace un POST a un endpoint local con un tope de 2 segundos y devuelve el control; la latencia del turno del agente no se ve afectada ni siquiera cuando la aplicación receptora está cerrada. Si tu hook solo observa y nunca decide, ponlo en async y deja de pagarlo.
Nunca dejes que un hook escriba basura en el terminal. Nuestro script se traga todas las excepciones, incluso en el nivel superior. Un traceback sin capturar desde un hook no falla discretamente: imprime una traza de pila de Python en la sesión de terminal del usuario, en medio de su trabajo.
Tiempos de espera
Los valores por defecto son generosos, con tres excepciones que no lo son:
| Tipo de hook | Tiempo de espera por defecto |
|---|---|
command, http, mcp_tool | 600 s |
prompt | 30 s |
agent | 60 s |
UserPromptSubmit (command, http, mcp_tool) | 30 s |
MessageDisplay (command, http, mcp_tool) | 10 s |
SessionEnd | 1,5 s compartidos entre todos los hooks, elevado para igualar un timeout por hook más largo, hasta 60 s |
El presupuesto de SessionEnd es el que sorprende. Es un presupuesto compartido, no una asignación por hook, así que tres hooks de limpieza se reparten 1,5 segundos entre ellos salvo que lo subas explícitamente.
La versión corta
- Existen 30 eventos. Seis son famosos.
- stdout llega al agente solo en
UserPromptSubmit,UserPromptExpansionySessionStart. En todos los demás casos, usa salida 2 con stderr, oadditionalContexten JSON. - 15 eventos bloquean con salida 2, 15 la ignoran. Las barreras de seguridad van en
PreToolUse. - Los matchers son cadenas exactas hasta que un carácter especial los convierte en una regex sin anclar.
- Seis fuentes de settings se fusionan de forma aditiva. Nada reemplaza a nada.
- Un nombre de evento mal escrito falla en el silencio más absoluto.
Si prefieres ver estos eventos dispararse en vez de razonar sobre ellos, eso es lo que hemos construido: AgentsRoom muestra cada disparo de hook por agente, por proyecto, por ejecución, a través de decenas de agentes en paralelo y sesiones de subagentes. Los hooks que configuras en tus propios settings siguen funcionando exactamente como los escribiste, porque ejecuta el CLI real.
Seguir leyendo
Cómo Escalar Agentes de Codificación AI en un Equipo de Desarrollo
Un desarrollador con un agente de codificación es una historia de productividad. Cinco desarrolladores con veinte agentes es un problema de coordinación. Aquí está lo que se rompe primero cuando un equipo se expande, y la configuración que se mantiene: archivos de contexto comprometidos, clara propiedad de archivos, revisión por radio de explosión, y costos que realmente puedes ver.
Leer el artículo¿Deberías seguir revisando el código de tu agente de IA?
Tus agentes escriben mejor código que la mitad de las solicitudes de extracción que solías fusionar. Entonces, ¿todavía lees cada línea? El caso honesto para ambos lados, las 10 señales que te dicen que un agente cometió un error y cuánto merece realmente cada cambio una revisión.
Leer el artículo¿Qué Agente de IA Deberías Elegir para Tus Proyectos?
Un agente frontend que escribe tu copia de marketing es un fracaso silencioso. Cómo emparejar cada tarea con el agente de IA adecuado: roles, expertos en catálogo, agentes personalizados y qué hacer cuando no tienes idea de quién debería hacerse cargo del trabajo.
Leer el artículo
Descargar AgentsRoom
Ejecuta tus agentes de IA (Claude, Codex, Antigravity CLI, OpenCode, Aider, Grok Build, Mistral Vibe, Kimi Code) en todos tus proyectos, desde una sola ventana.
App complementaria: supervisa tus agentes en movimiento
Usa Claude, Codex, Antigravity CLI u otro proveedor de IA.
Envía bugs y peticiones directamente a tu backlog público.
Un vistazo a AgentsRoom en acción.