Autres types de hooks
Mis à jour le 29 juillet 2026
Autres types de hooks
Les hooks PreToolUse et PostToolUse étudiés jusqu’ici partagent une limite : ils ne se déclenchent qu’autour d’un appel d’outil. Or beaucoup d’automatisations utiles se rattachent à d’autres moments de la vie d’une session — son démarrage, sa fin, l’instant où vous soumettez un prompt. Claude Code propose pour cela plusieurs autres types de hooks :
| Hook | Déclenchement |
|---|---|
| Notification | Quand Claude Code envoie une notification (besoin de permission ou inactivité depuis 60 secondes) |
| Stop | Quand Claude Code a fini de répondre |
| SubagentStop | Quand un sous-agent (affiché comme “Task” dans l’UI) a terminé |
| PreCompact | Avant une opération de compactage, manuelle ou automatique |
| UserPromptSubmit | Quand l’utilisateur soumet un prompt, avant que Claude ne le traite |
| SessionStart | Au démarrage ou à la reprise d’une session |
| SessionEnd | Quand une session se termine |
Chacun ouvre des usages que les hooks d’outils ne permettent pas. Un hook Stop peut vous prévenir par une alerte sonore qu’une tâche longue est terminée, pendant que vous travaillez sur autre chose. Un hook SessionStart peut injecter au démarrage un état que Claude ne devinerait pas, comme la branche courante ou les tickets en cours. Un hook UserPromptSubmit intervient avant même que Claude ne voie votre message, ce qui en fait le point d’entrée naturel pour enrichir ou filtrer ce que vous envoyez.
Le défi : des formats d’entrée variables
Cette richesse a une contrepartie, et c’est la partie délicate. L’entrée stdin de vos commandes change selon le type de hook : ce que reçoit un hook PreToolUse n’a pas la même forme que ce que reçoit un hook Notification ou un hook Stop. S’y ajoute une seconde source de variation, puisque le tool_input contenu dans ces données varie selon l’outil appelé. Un script écrit pour l’outil Read en supposant la présence d’un file_path ne trouvera rien de tel une fois branché sur un autre outil.
Comparez plutôt. Voici l’entrée stdin d’un hook PostToolUse surveillant l’outil TodoWrite :
{
"session_id": "9ecf22fa-edf8-...",
"hook_event_name": "PostToolUse",
"tool_name": "TodoWrite",
"tool_input": {
"todos": [
{ "content": "ecrire un readme", "status": "pending" }
]
},
"tool_response": {
"oldTodos": [],
"newTodos": [
{ "content": "ecrire un readme", "status": "pending" }
]
}
}
Et pour comparaison, voici l’entrée d’un hook Stop :
{
"session_id": "af9f50b6-f042-...",
"hook_event_name": "Stop",
"stop_hook_active": false
}
La structure change considérablement selon le type de hook et le matcher utilisé. Seul session_id survit d’un cas à l’autre ; tout le reste est spécifique. Écrire un hook en devinant sa forme d’entrée revient donc à programmer les yeux fermés, et c’est l’explication la plus fréquente des hooks qui « ne font rien » sans produire le moindre message d’erreur exploitable.
Astuce : le hook de debug
Plutôt que de deviner, faites-vous montrer les données. Pour découvrir exactement ce que votre commande recevra, créez un hook de debug qui écrit les données dans un fichier :
{
"PostToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "jq . > post-log.json"
}
]
}
]
}
Le matcher * capture tous les outils. La commande jq . formate le JSON et l’écrit dans post-log.json. Vous pouvez ensuite inspecter ce fichier pour comprendre exactement quelles données votre commande hook devrait traiter. Concrètement : vous installez ce hook, vous menez une session ordinaire en déclenchant l’outil qui vous intéresse, puis vous ouvrez post-log.json et vous y lisez la structure réelle, avec les noms de champs exacts, sur laquelle écrire votre condition.
Cette technique est particulièrement utile quand vous créez un nouveau type de hook, quand vous voulez comprendre les données d’un outil spécifique, ou quand vous déboguez un hook qui ne fonctionne pas comme prévu. Prenez l’habitude d’y recourir en premier, avant d’écrire la moindre ligne de logique métier : dix minutes d’observation vous épargneront une heure d’hypothèses.