Inicio / Extender: habilidades, MCP, subagentes, hooks, plugins
Los eventos de hook, del disparo al mensaje
PreToolUse se ejecuta antes de la herramienta y puede impedir la llamada; PostToolUse se ejecuta después y solo puede reaccionar, incluso sustituyendo el resultado de la herramienta. Un hook comunica su decisión mediante un objeto JSON con campos precisos y mediante su código de salida, nunca con una frase escrita en la salida estándar.
Un hook PreToolUse se ejecuta antes de que la herramienta se active: su decisión puede impedir que la llamada se produzca. Un hook PostToolUse se ejecuta después, una vez que la herramienta ya se ha lanzado: su decisión ya no puede impedir nada, solo reaccionar, incluso sustituyendo el resultado de la herramienta con el campo updatedToolOutput.
Una treintena de eventos, del arranque al fin de sesión
La documentación oficial enumera una treintena de eventos del ciclo de vida, desde SessionStart y UserPromptSubmit hasta PreCompact, WorktreeCreate o SessionEnd. Cada uno cubre un momento preciso: un archivo que cambia, un cambio de modelo, un subagente que arranca o termina, una instrucción en curso de expansión. Prolonga la lección anterior: un automatismo siempre se declara sobre uno de esos eventos, nunca sobre una intención general.
El plazo de expiración depende del tipo de hook, no solo del evento
Un hook command, http o mcp_tool dispone por defecto de seiscientos segundos, tres eventos lo rebajan a treinta segundos y MessageDisplay a diez. Un hook prompt conserva treinta segundos, un hook agent sesenta, sea cual sea el evento.
Lo que llega al modelo: campos JSON, no texto libre
Un hook no comunica su decisión escribiendo una frase en la salida estándar. Devuelve un objeto JSON cuyo campo hookSpecificOutput.permissionDecision lleva el valor allow o deny, acompañado de un permissionDecisionReason que explica la elección, y el campo hookEventName retoma el nombre exacto del evento que lo disparó.
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Commande destructive detectee dans le motif teste"
}
}
El código de salida del script también cuenta, con independencia del JSON: un código de salida 2 bloquea la acción incluso si el cuerpo JSON afirmaba allow. Esta regla sufre excepciones nombradas, PermissionRequest, StopFailure fuera de una secuencia terminal, PermissionDenied, y sobre todo PostToolUse y PostToolUseFailure, donde el código 2 se vuelve no bloqueante y se limita a mostrarse a Claude vía el error estándar: lógico, ya que la herramienta ya ha terminado de ejecutarse cuando se dispara ese hook.
Diferir en lugar de decidir
El campo permissionDecision admite cuatro valores: allow omite la petición de permiso, con excepciones documentadas, deny impide la llamada, ask pide confirmación al usuario, y defer termina el turno para retomar la herramienta más tarde, solo en modo no interactivo con -p. Para devolver la decisión al flujo de permisos habitual en lugar de forzarla, un hook no escribe ninguno de esos valores: sale con el código 0 sin reportar decisión, y la llamada sigue su camino normal de aprobación.
Probar un hook por su entrada estándar
Un error de hook deja pasar la acción y solo se anuncia con un aviso en la transcripción, fácil de pasar por alto: una prueba mal formada devuelve un silencio que parece «el hook no reacciona». El hook lee un JSON en su entrada estándar, así que puedes ejecutarlo a mano, con un caso que debe rechazar y un contratestigo que debe dejar pasar. El script siguiente y sus dos llamadas fabrican sus propios datos:
cat > garde.sh << 'EOF'
#!/bin/sh
ENTREE=$(cat)
case "$ENTREE" in
*"npm publish"*) echo "Rechazado: lance primero npm publish --dry-run." >&2; exit 2 ;;
esac
exit 0
EOF
printf '%s' '{"tool_name":"Bash","tool_input":{"command":"npm publish"}}' | sh garde.sh; echo "code=$?"
printf '%s' '{"tool_name":"Bash","tool_input":{"command":"npm test"}}' | sh garde.sh; echo "code=$?"
Rechazado: lance primero npm publish --dry-run.
code=2
code=0
La primera llamada prueba que el guardia rechaza, la segunda que su silencio significa «autorizado» y no «roto». Escribe el JSON con printf '%s' entre comillas simples: un shell que reduce una barra invertida rompe el JSON sin error visible.
¿Un guardia averiado deja pasar?
Desde octubre de 2026, un hook PreToolUse o PermissionRequest cuya correspondencia falla, o cuya entrada no se serializa, bloquea la llamada en lugar de ser ignorado. En Windows, un guardia sin shell declarado también bloquea cuando falta Git for Windows. Un hook lanzado por PowerShell que salía con el código 2 no bloqueaba antes de la corrección de octubre: relee los guardias escritos antes. Para que un guardia de seguridad bloquee en todos los casos de fallo, declara "onFailure": "block".
Plazo de expiración según el tipo de hook y el evento
| Plazo de expiración por defecto | Tipo de hook implicado | Plazo por defecto | Particularidad |
|---|---|---|---|
| Hook command, http o mcp_tool ordinario | command, http, mcp_tool | 600 segundos | Se aplica a la mayoría de los eventos del ciclo de vida |
| UserPromptSubmit, PreModelSwitch, PostModelSwitch | command, http, mcp_tool | 30 segundos | Estos tres eventos rebajan el plazo normalmente fijado en 600 segundos |
| MessageDisplay | command, http, mcp_tool | 10 segundos | El plazo más corto de todos los eventos documentados |
| SessionEnd | Todos los tipos combinados | 1,5 segundos para el conjunto de los hooks del evento | Ampliable hasta 60 segundos si un hook declara explícitamente un plazo más largo |
| Hook de tipo prompt | prompt | 30 segundos | Plazo propio del tipo, independiente del evento que lo dispara |
| Hook de tipo agent | agent | 60 segundos | Plazo propio del tipo, independiente del evento que lo dispara |
Del evento a la decisión transmitida al modelo
Un desarrollador configura un hook PostToolUse que devuelve un código de salida 2 después de cada llamada de la herramienta Bash. Después lanza un comando Bash desde Claude Code y observa que el comando se ejecuta hasta el final.
Escribe en una frase lo que esta situación establece, y en una frase lo que no establece.
Lo que esto establece: Esta observación establece que, para el evento PostToolUse, un código de salida 2 no bloquea la acción y se trata solo como un mensaje mostrado a Claude vía el error estándar.
Lo que esto no establece: No establece que el código de salida 2 se comporte de la misma manera en todos los eventos de hook, ya que PreToolUse respeta ese mismo código bloqueando la llamada antes de que se produzca.
Los tres calibrados falsos más frecuentes
- Demasiado amplio Esta observación prueba que el código de salida 2 nunca bloquea nada, sea cual sea el evento de hook implicado.
- Demasiado estrecho Esta observación no prueba nada sobre el comportamiento del hook, ya que solo se probó una llamada de la herramienta Bash.
- Fuera de tema Esta observación muestra que el hook tardó más en ejecutarse que el propio comando Bash.
- PreToolUse puede impedir que se produzca una llamada de herramienta, PostToolUse no puede impedir nada pero puede sustituir el resultado una vez lanzada la herramienta.
- Un hook se prueba a mano enviándole un JSON por su entrada estándar, con un caso que rechazar y un contratestigo que dejar pasar.
- La decisión de un hook pasa por el campo hookSpecificOutput.permissionDecision, con los valores allow, deny, ask o defer, nunca por una frase en la salida estándar.
- Un código de salida 2 bloquea la acción incluso cuando el JSON afirma allow, salvo en eventos nombrados donde se convierte en un simple mensaje mostrado a Claude.
- Para diferir al flujo de permisos habitual, un hook sale con el código 0 sin reportar decisión, y un guardia de seguridad declara onFailure: "block" para bloquear también ante un fallo.
Escribe un hook PreToolUse mínimo que salga con el código 0 sin escribir nada en su salida estándar, decláralo sobre un evento anodino, y confirma que la llamada sigue su camino normal de aprobación en lugar de ser forzada.
Cada afirmación datable de esta lección remite aquí al texto público que la respalda. Una fuente que no se abre no prueba nada.
- Claude Code, hooks: updatedToolOutput, onFailure, Windows sin Git Bash consultée le 2026-10-24
- Registro de cambios de Claude Code: guardias de hook que bloquean ante un fallo, PowerShell y código 2 consultée le 2026-10-24