30 événements de hook se déclenchent dans une session Claude Code. Trois seulement peuvent répondre.
La liste complète des événements de hook de Claude Code, quand chacun se déclenche, lesquels des 15 peuvent bloquer, et la règle de stdout qui avale silencieusement la sortie de la plupart des hooks. Une référence de terrain construite en production sur des milliers de sessions d'agents.
Deux pannes reviennent sans arrêt quand on branche des hooks sur Claude Code, et elles n'ont rien à voir l'une avec l'autre.
La première : vous ajoutez un hook, il ne se passe rien. Pas d'erreur, pas d'avertissement, pas de ligne de journal. Le hook ne s'exécute simplement jamais.
La seconde : le hook s'exécute manifestement, ses effets sont visibles sur le disque, mais le message qu'il imprime pour l'agent n'arrive jamais. L'agent se comporte comme si le hook n'avait rien dit.
Les deux viennent du même endroit. Le système de hooks est plus vaste et moins uniforme que la poignée d'événements dont parlent la plupart des articles, et les règles qui décident de qui peut parler à l'agent ne sont pas celles qu'on devinerait. Voici la référence qu'on aurait aimé avoir. Nous construisons AgentsRoom sur ces hooks, et tout ce qui suit est soit cité de la référence officielle, soit mesuré en production.
Il y a 30 événements, pas six
La plupart des guides couvrent PreToolUse, PostToolUse, UserPromptSubmit, Stop, Notification et SubagentStop. Ces six-là sont réels, et ils portent l'essentiel du travail utile. Ils représentent aussi un cinquième de ce qui existe.
La liste complète, regroupée par ce que chacun observe :
| Groupe | Événements |
|---|---|
| Session | SessionStart, SessionEnd, Setup |
| Prompt | UserPromptSubmit, UserPromptExpansion |
| Outils | PreToolUse, PostToolUse, PostToolUseFailure, PostToolBatch |
| Permissions | PermissionRequest, PermissionDenied |
| Tour | Stop, StopFailure |
| Sous-agents et tâches | SubagentStart, SubagentStop, TaskCreated, TaskCompleted, TeammateIdle |
| Contexte | PreCompact, PostCompact, InstructionsLoaded |
| Environnement | FileChanged, CwdChanged, ConfigChange |
| Worktrees | WorktreeCreate, WorktreeRemove |
| Interface | Notification, MessageDisplay |
| Elicitation MCP | Elicitation, ElicitationResult |

L'ordre de déclenchement dans une même session. Le bloc outil se répète à chaque appel d'outil, et le bloc prompt entier se répète à chaque tour.
Certains de ces événements changent la façon de penser le système. PostToolUseFailure existe : la branche « est-ce que l'outil a marché » est donc un événement, pas quelque chose qu'on déduit d'un payload. PostToolBatch se déclenche une fois après la résolution d'un lot d'appels d'outils parallèles, ce qui est le bon endroit pour lancer un linter une seule fois au lieu d'une fois par édition. InstructionsLoaded se déclenche à la lecture de CLAUDE.md, ce qui donne un point d'accroche pour vérifier que l'agent a réellement chargé les règles que vous croyez.
La règle de stdout qui avale la sortie de la plupart des hooks
C'est le point le plus utile de cette page.
Sur une sortie 0, Claude Code analyse stdout à la recherche de champs JSON. Mais que ce stdout soit un jour montré à l'agent dépend de l'événement, et les exceptions tiennent en une courte liste. La référence dit :
Pour la plupart des événements, stdout est écrit dans le journal de debug mais n'est pas affiché dans la transcription. Les exceptions sont
UserPromptSubmit,UserPromptExpansionetSessionStart, où stdout est ajouté comme contexte que Claude peut voir et exploiter.
Trois événements sur trente. Si vous faites echo "attention : cette migration est destructrice" depuis un hook PostToolUse en espérant que l'agent le lise, il ne le lira jamais. Votre texte est parti dans le journal de debug.
Il n'existe exactement que deux façons de mettre du texte sous les yeux de l'agent depuis un autre événement :
- Sortir avec le code 2 et écrire sur stderr. Sur une sortie 2, Claude Code ignore stdout et tout JSON qu'il contient, et renvoie stderr à l'agent comme message d'erreur.
- Sortir avec 0 et imprimer un objet JSON portant
hookSpecificOutput.additionalContext.
Notez l'asymétrie du premier point. Sortie 0 : stdout compte, stderr non. Sortie 2 : stderr compte, stdout est jeté entièrement. Se tromper de sens, c'est pourquoi un hook peut sembler parfaitement correct et rester muet.
Tout autre code de sortie est une erreur non bloquante. La transcription affiche un avis <nom du hook> hook error avec la première ligne de stderr, l'exécution continue, et le stderr complet atterrit dans le journal de debug.

Quel canal atteint l'agent, selon le code de sortie. Le chemin en pointillés est celui qu'on suppose exister et qui n'existe pas.
Exactement la moitié peuvent bloquer
Quinze événements arrêtent l'action sur une sortie 2. Quinze l'ignorent et continuent.
Peuvent bloquer : PreToolUse, PermissionRequest, UserPromptSubmit, UserPromptExpansion, Stop, SubagentStop, TeammateIdle, TaskCreated, TaskCompleted, ConfigChange, PostToolBatch, PreCompact, Elicitation, ElicitationResult, WorktreeCreate.
Ne peuvent pas bloquer : PostToolUse, PostToolUseFailure, PermissionDenied, StopFailure, Notification, SubagentStart, SessionStart, Setup, SessionEnd, CwdChanged, FileChanged, PostCompact, WorktreeRemove, InstructionsLoaded, MessageDisplay.
Conséquence pratique : un garde-fou se place sur PreToolUse, jamais sur PostToolUse. PostToolUse se déclenche après la réussite de l'outil. Sortir avec 2 à cet endroit n'annule pas l'écriture, ça affiche juste une erreur pendant que les dégâts sont déjà sur le disque. Si vous voulez arrêter un rm -rf, vous avez exactement un endroit où le faire.
Le fait que PostToolBatch bloque alors que PostToolUse ne bloque pas mérite un second regard. Cela veut dire qu'une vérification au niveau du lot peut encore arrêter le tour après que des éditions parallèles ont atterri : c'est ce que le système offre de plus proche d'un veto après écriture.
Les matchers sont exacts, jusqu'à ce qu'ils ne le soient plus
Le champ matcher change de stratégie d'évaluation selon ses propres caractères, et rien ne vous dit quelle voie il a prise.
| Matcher | Évalué comme |
|---|---|
"*", "", ou absent | correspond à tout |
Seulement lettres, chiffres, _, -, espaces, ,, | | chaîne exacte, ou liste de chaînes exactes séparées par | ou , |
| Autre chose | expression régulière JavaScript non ancrée |
Le piège, c'est « non ancrée ». La référence précise que l'expression est testée avec RegExp.prototype.test, qui réussit sur une correspondance n'importe où dans la valeur. Donc Edit.* correspond à Edit et à NotebookEdit. Si vous visiez un seul outil, écrivez ^Edit$.
Deux comportements dépendants de la version, à connaître avant de déboguer la mauvaise piste :
- Les virgules comme séparateurs et la tolérance aux espaces demandent Claude Code v2.1.191 ou plus récent.
- Les traits d'union ont rejoint le jeu de caractères de correspondance exacte en v2.1.195. Avant, un matcher comme
code-reviewerétait traité comme une regex non ancrée, et se déclenchait donc aussi poursenior-code-reviewer.
Dans AgentsRoom, nous restreignons notre propre hook d'attribution de fichiers avec Write|Edit|MultiEdit|NotebookEdit, ce qui reste sur la voie de la chaîne exacte et ne touche que ces quatre outils. Les hooks de cycle de vie que nous installons n'ont aucun matcher, parce qu'ils nous concernent toujours.
Six endroits peuvent définir des hooks, et ils fusionnent
Le réflexe est de chercher un ordre de priorité. Il n'y en a pas, et c'est justement ce qui est intéressant.
| Emplacement | Portée |
|---|---|
~/.claude/settings.json | tous vos projets, local à votre machine |
.claude/settings.json | un projet, versionnable |
.claude/settings.local.json | un projet, gitignoré par Claude Code |
| Managed policy settings | toute l'organisation, contrôlé par l'admin |
Plugin hooks/hooks.json | tant que le plugin est activé |
| Frontmatter de skill ou d'agent | tant que le composant est actif |
La référence dit :
Les entrées de hook fusionnent entre les niveaux de settings au lieu de se remplacer : les settings utilisateur, projet et locaux ajoutent leurs propres hooks sans retirer ceux de la politique gérée, et le réglage
disableAllHooksne peut pas désactiver les hooks gérés depuis l'extérieur des settings gérés.
Donc un hook de projet ne remplace jamais un hook global, il s'empile dessus. Six sources, toutes additives. Un formateur PostToolUse défini dans vos settings utilisateur puis à nouveau dans le projet s'exécute deux fois par édition, et le seul symptôme est une impression de lenteur.

Six sources, un seul jeu fusionné. Rien ici ne remplace quoi que ce soit.
Cela explique aussi pourquoi .claude/settings.local.json est le bon endroit pour qu'un outil installe un hook dans le projet de quelqu'un. Il est limité au projet, Claude Code le gitignore, et il est chargé sans aucun drapeau de ligne de commande. C'est là qu'AgentsRoom écrit ses entrées, pour que le .claude/settings.json versionné de l'utilisateur ne soit jamais touché et que ses collègues n'héritent jamais d'un chemin propre à une machine.
Ce que la production nous a appris
AgentsRoom installe des hooks dans chaque projet qu'il ouvre, pour suivre le statut des agents de façon déterministe et attribuer les fichiers modifiés au bon agent. Certaines choses n'apparaissent qu'à cette échelle.
Les noms d'événements inconnus sont ignorés en silence. Ce n'est pas documenté, et nous en dépendons. Quand nous ajoutons un nouvel événement de cycle de vie à notre installeur, les utilisateurs sur une ancienne version du CLI se retrouvent avec un settings.local.json contenant un nom d'événement que leur binaire n'a jamais connu. Rien ne casse, rien n'avertit, l'entrée est sautée. C'est ce qui rend l'installeur sûr à livrer avant une version du CLI. C'est aussi, forcément, pourquoi une faute de frappe produit un silence total plutôt qu'une erreur.
agent_id est ce qui vous dit que vous êtes dans un sous-agent. Le champ n'est présent que quand le hook se déclenche à l'intérieur d'un appel de sous-agent. Cela compte plus qu'il n'y paraît : Stop se déclenche quand un sous-agent finit son tour, pas seulement l'agent principal. Une règle naïve du type « marquer la session terminée sur Stop » marque toute la session finie dès le premier retour d'un sous-agent. Nous sautons les événements de fin de tour porteurs d'agent_id exactement pour cette raison.
Ne lisez pas transcript_path pour le tour en cours. La référence prévient que la transcription est écrite de façon asynchrone et peut être en retard sur la conversation en mémoire : les messages les plus récents peuvent ne pas encore y être quand votre hook se déclenche. Stop et SubagentStop reçoivent last_assistant_message précisément pour que vous n'ayez jamais à courir après le fichier.
Les hooks sont le seul signal de statut fiable. Avant les hooks, nous analysions le PTY pour déterminer si un agent réfléchissait, attendait ou avait fini. Cela casse dès que le CLI s'affiche via le tampon d'écran alterné du terminal, ce que fait /tui fullscreen. Les hooks se déclenchent à l'identique sous tous les moteurs de rendu. Si vous construisez quoi que ce soit qui observe un agent de l'extérieur, c'est la couche sur laquelle bâtir, et l'analyse de terminal reste au mieux une solution de repli.
async: true ne coûte rien. Une commande de hook peut déclarer async: true, et l'agent ne l'attend pas. Notre hook envoie un POST à un point d'entrée local avec un plafond de 2 secondes puis rend la main ; la latence du tour de l'agent n'est pas affectée, même quand l'application réceptrice est fermée. Si votre hook se contente d'observer sans jamais décider, passez-le en async et arrêtez de le payer.
Ne laissez jamais un hook écrire n'importe quoi dans le terminal. Notre script avale toutes les exceptions, y compris au niveau le plus haut. Une trace d'appels Python non rattrapée depuis un hook n'échoue pas discrètement : elle s'imprime dans la session de terminal de l'utilisateur, au milieu de son travail.
Délais d'expiration
Les valeurs par défaut sont généreuses, avec trois exceptions qui ne le sont pas :
| Type de hook | Délai par défaut |
|---|---|
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 partagé entre tous les hooks, relevé pour s'aligner sur un timeout par hook plus long, jusqu'à 60 s |
Le budget de SessionEnd est celui qui surprend. C'est un budget partagé, pas une allocation par hook : trois hooks de nettoyage se partagent donc 1,5 seconde, sauf à le relever explicitement.
La version courte
- 30 événements existent. Six sont célèbres.
- stdout atteint l'agent sur
UserPromptSubmit,UserPromptExpansionetSessionStartuniquement. Partout ailleurs, sortez avec 2 et stderr, ou passez paradditionalContexten JSON. - 15 événements bloquent sur une sortie 2, 15 l'ignorent. Les garde-fous vont sur
PreToolUse. - Les matchers sont des chaînes exactes jusqu'à ce qu'un caractère spécial les transforme en regex non ancrée.
- Six sources de settings fusionnent de façon additive. Rien ne remplace rien.
- Un nom d'événement mal orthographié échoue dans le silence le plus complet.
Si vous préférez voir ces événements se déclencher plutôt que raisonner dessus, c'est ce que nous avons construit : AgentsRoom montre chaque déclenchement de hook par agent, par projet, par exécution, sur des dizaines d'agents en parallèle et des sessions de sous-agents. Les hooks que vous configurez dans vos propres settings continuent de fonctionner exactement comme écrits, parce qu'AgentsRoom exécute le vrai CLI.
Continuer la lecture
Passer les agents de code à l'échelle d'une équipe
Un développeur avec un agent de code, c'est un gain de productivité. Cinq développeurs avec vingt agents, c'est un problème de coordination. Voici ce qui casse en premier quand une équipe passe à l'échelle, et le dispositif qui tient : fichier de contexte versionné, périmètre de fichiers explicite, relecture proportionnelle au risque, et un coût enfin visible.
Lire l'articleAgentsRoom supporte maintenant Ollama : vos modèles locaux à côté du cloud
Ollama devient un fournisseur dans AgentsRoom. Faites tourner des modèles open source locaux comme Llama, Qwen, Gemma et DeepSeek à côté des agents cloud, avec un curseur local ou cloud par agent, basculable en cours de conversation.
Lire l'articleFaut-il encore relire le code de ses agents IA ?
Vos agents écrivent du meilleur code que la moitié des pull requests que vous mergiez avant. Faut-il encore lire chaque ligne ? Le débat pris au sérieux des deux côtés, les 10 signaux qui trahissent un agent qui a déconné, et le niveau de relecture que mérite vraiment chaque changement.
Lire l'article
Télécharger AgentsRoom
Lancez vos agents IA (Claude, Codex, Antigravity CLI, OpenCode, Aider, Grok Build, Mistral Vibe, Kimi Code) sur tous vos projets, depuis une seule fenêtre.
App companion : suivez vos agents en déplacement
Utilisez Claude, Codex, Antigravity CLI ou un autre fournisseur IA.
Remontez bugs et demandes directement dans votre backlog public.
Aperçu d'AgentsRoom en action.