Disparar un Comando de Shell en PostToolUse con Hooks
Un hook PostToolUse es un comando de shell que se ejecuta automáticamente justo después de que una llamada a herramienta coincidente finaliza.
Busca en todas las páginas de la documentación
Un hook PostToolUse es un comando de shell que se ejecuta automáticamente justo después de que una llamada a herramienta coincidente finaliza.
El uso más común es el autoformateo: en el momento en que Claude edita un archivo, un formateador se ejecuta sobre él sin que nadie lo pida.
Los hooks se configuran en settings.json, bajo un nombre de evento como PostToolUse.
Cada entrada de hook tiene un matcher, que lo limita a herramientas específicas como Edit o Write, y uno o más comandos hooks para ejecutar cuando ese matcher se dispara.
A diferencia de un comando de barra (/), nada sobre un hook pasa por el modelo. El harness ejecuta el comando de shell directamente y no le pregunta a Claude si debería hacerlo.
Un hook recibe detalles sobre la llamada a herramienta completada como JSON, típicamente en stdin, incluyendo qué archivo fue tocado.
Debido a que el hook es determinista, es el lugar adecuado para cualquier cosa que deba suceder cada vez, sin excepciones y sin juicios.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$CLAUDE_FILE_PATH\""
}
]
}
]
}
}Cuándo usar esto:
#!/usr/bin/env bash
# .claude/hooks/format-on-edit.sh
# Lee la carga útil del evento PostToolUse desde stdin y formatea el archivo tocado.
set -euo pipefail
payload="$(cat)"
file_path="$(echo "$payload" | jq -r '.tool_input.file_path // empty')"
if [ -z "$file_path" ]; then
exit 0
fi
case "$file_path" in
*.ts|*.tsx|*.js|*.jsx|*.json|*.css|*.md)
npx prettier --write "$file_path"
echo "Formatted: $file_path"
;;
*)
exit 0
;;
esac{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/format-on-edit.sh"
}
]
}
]
}
}Lo que esto demuestra:
matcher limita el hook a las llamadas a herramientas Edit y Write, por lo que nunca se dispara en, por ejemplo, un comando Bash.jq, en lugar de adivinar una variable de entorno.case limita el formateo a los tipos de archivo que Prettier entiende realmente, por lo que el hook no hace nada silenciosamente en los archivos que no debería tocar.set -euo pipefail hace que el script falle ruidosamente ante errores inesperados en lugar de hacer nada silenciosamente.PostToolUse inmediatamente después de que una llamada a herramienta se completa exitosamente.matcher de cada hook PostToolUse registrado contra la herramienta que se acaba de ejecutar; solo se ejecutan los hooks coincidentes.command de cada hook coincidente se ejecuta como un comando de shell simple, con la carga útil del evento (nombre de la herramienta, entrada de la herramienta y resultado) disponible para él, típicamente a través de stdin como JSON.PostToolUse. Ese comportamiento de bloqueo pertenece en cambio a PreToolUse.matchermatcher | Coincide con |
|---|---|
Edit | Solo la herramienta Edit. |
Write | Solo la herramienta Write. |
Edit|Write | Tanto Edit como Write (alternancia de expresiones regulares). |
* o omitido | Cada llamada a herramienta, independientemente de qué herramienta se ejecutó. |
# Prefiere leer entrada estructurada en lugar de depender de variables de entorno
# que pueden o no estar configuradas consistentemente entre implementaciones de hooks.
payload="$(cat)"
file_path="$(echo "$payload" | jq -r '.tool_input.file_path // empty')"
# Protege contra una ruta vacía antes de hacer cualquier trabajo.
[ -z "$file_path" ] && exit 0settings.json, ya que es más fácil de probar, comparar y razonar de forma aislada.PostToolUse se dispara después de que la llamada a herramienta ya se ha completado, por lo que el hook no puede evitar que la edición ocurra. Solución: usa un hook PreToolUse en su lugar si el objetivo es rechazar o bloquear una acción antes de que suceda.matcher y la verificación del tipo de archivo para que solo se ejecute donde importa.matcher y dispararlo en cada llamada a herramienta - un hook sin alcance (sin matcher, o *) se dispara incluso en herramientas no relacionadas como Bash o Read, desperdiciando ciclos y saturando la salida. Solución: establece un matcher que nombre exactamente las herramientas que le importan al hook, como Edit|Write.case anterior) para que el hook salga silenciosamente en los archivos que no está destinado a tocar.| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| Pedirle a Claude que formatee el archivo en el prompt | Una solicitud única, no algo que deba ocurrir en cada edición en el futuro. | El comportamiento debe ser incondicional y automático para todo el equipo, no depender de recordar pedirlo. |
Un hook PreToolUse | El objetivo es validar o bloquear la edición antes de que ocurra, no reaccionar después de que se complete. | La acción es un efecto secundario que debe ejecutarse después de una edición exitosa, como formatear o registrar. |
| Un paso de pipeline de CI | La verificación es costosa (conjunto completo de pruebas, compilación completa) y no necesita ejecutarse en cada edición local. | La retroalimentación rápida en cada edición es más importante que centralizar la verificación en CI. |
No. PostToolUse se dispara después de que la llamada a herramienta ya se ha completado, por lo que la edición ya ha ocurrido cuando se ejecuta el hook. El bloqueo pertenece en cambio a un hook PreToolUse.
La carga útil del evento incluye la entrada de la llamada a herramienta, típicamente entregada como JSON en stdin, que contiene la ruta del archivo para las llamadas a herramientas Edit y Write.
Edit o Write.Edit|Write) permite que una entrada de hook cubra múltiples herramientas.matcher, o usar *, hace que el hook se dispare en cada llamada a herramienta.Sí. Se pueden registrar múltiples entradas de hook bajo PostToolUse, y se ejecuta cada entrada cuyo matcher coincida con la herramienta completada.
La salida no cero generalmente se presenta de nuevo en la sesión como una señal de fallo, lo cual es útil para hooks que realizan validaciones ligeras además de un efecto secundario como el formateo.
No. Debería verificar la extensión (o ruta) del archivo y solo ejecutar el formateador contra tipos que realmente entienda, saliendo silenciosamente en cualquier otra cosa.
Generalmente no, ya que el hook se ejecuta en cada edición coincidente y un hook lento agrega esa latencia a cada edición. Las verificaciones lentas suelen ser mejores para CI o un comando activado manualmente.
En settings.json, bajo un array hooks.PostToolUse, donde cada entrada tiene un matcher y uno o más comandos hooks para ejecutar.
No. El command del hook se ejecuta como un comando de shell independiente, separado del proceso de razonamiento del modelo, y solo su salida y código de salida se informan de vuelta.
Sí. La carga útil del evento generalmente incluye tanto la entrada de la herramienta como su resultado, lo cual es útil para hooks que desean reaccionar de manera diferente dependiendo de lo que produjo la edición.
Sí, y se recomienda, ya que un script de hook con ámbito de proyecto en control de versiones significa que cada compañero de equipo obtiene el mismo comportamiento automático de formateo o registro sin configuración individual.
Un hook PostToolUse se dispara después de que cada llamada a herramienta individual coincidente se completa, mientras que un hook Stop se dispara una vez, cuando finaliza la sesión o el turno, lo que lo hace más adecuado para resúmenes de fin de turno o limpieza en lugar de reacciones por edición.
PostToolUse encaja entre los tres puntos de extensión.Versiones de Stack: Escrito contra la línea de modelos Claude actual a partir de ~junio de 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (el predeterminado) y Claude Haiku 4.5. Los nombres de modelos, precios y características del producto cambian rápidamente; verifique los detalles actuales en platform.claude.com/docs antes de confiar en ellos.
Revisado por Chris St. John·Última actualización: 16 jul 2026