Aller au contenu
Mastering Claude

Accueil / Étendre : compétences, MCP, sous-agents, hooks, plugins

Étendre : compétences, MCP, sous-agents, hooks, plugins11 minApplication

Les événements de hook, du déclenchement au message

PreToolUse peut empêcher un appel de se produire, PostToolUse ne peut plus que réagir après coup, et la décision d'un hook passe par des champs JSON précis, jamais par une phrase écrite sur la sortie standard.

Un hook PreToolUse s'exécute avant que l'outil ne s'active : sa décision peut empêcher l'appel de se produire. Un hook PostToolUse s'exécute après, une fois l'outil déjà lancé : sa décision ne peut plus rien empêcher, seulement réagir. Cette différence de moment détermine ce qu'un hook peut raisonnablement faire à chaque événement, et elle explique pourquoi un même mécanisme de blocage ne se comporte pas de la même façon selon l'événement qui le porte.

Une trentaine d'événements, du démarrage à la fin de session

La documentation officielle liste une trentaine d'événements du cycle de vie, de SessionStart et UserPromptSubmit jusqu'à PreCompact, WorktreeCreate ou SessionEnd. Chacun couvre un moment précis : un fichier qui change, une bascule de modèle, un sous-agent qui démarre ou se termine, une invite en cours d'expansion. Un automatisme voulu, présenté dans la leçon précédente comme la traduction mécanique d'une règle qu'on espérait voir suivie, se déclare toujours sur l'un de ces événements précis, jamais sur une intention générale.

Le délai d'expiration dépend du type de hook, pas seulement de l'événement

Un hook de type command, http ou mcp_tool dispose par défaut de six cents secondes pour répondre. Trois événements abaissent ce délai à trente secondes, UserPromptSubmit, PreModelSwitch et PostModelSwitch, et un seul le réduit à dix secondes, MessageDisplay. Un hook de type prompt garde un délai fixe de trente secondes, un hook de type agent un délai fixe de soixante secondes, quel que soit l'événement qui le déclenche. SessionEnd fonctionne différemment : l'ensemble de ses hooks partage un budget d'une seconde et demie, extensible jusqu'à soixante secondes seulement si un hook déclare explicitement un délai plus long.

Ce qui atteint réellement le modèle : des champs JSON, pas du texte libre

Un hook ne communique pas sa décision en écrivant une phrase sur la sortie standard. Il renvoie un objet JSON dont le champ hookSpecificOutput.permissionDecision porte la valeur allow ou deny, accompagné d'un permissionDecisionReason qui explique le choix, et le champ hookEventName reprend le nom exact de l'événement déclencheur. Pour ajouter de l'information sans rien bloquer, hookSpecificOutput.additionalContext insère du texte que le modèle lira comme s'il venait d'ailleurs dans la conversation.

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Commande destructive detectee dans le motif teste"
  }
}

Le code de sortie du script compte aussi, indépendamment du JSON : un code de sortie 2 bloque l'action même si le corps JSON affirmait allow. Cette règle souffre d'exceptions nommées, PermissionRequest, StopFailure hors d'une séquence terminale, PermissionDenied, et surtout PostToolUse et PostToolUseFailure, où le code 2 devient non bloquant et se contente d'être affiché à Claude via l'erreur standard : logique, puisque l'outil a déjà fini de s'exécuter quand ce hook se déclenche.

Déférer plutôt que décider

Le champ permissionDecision documente deux valeurs, allow et deny. Pour renvoyer la décision au flux de permission habituel plutôt que de la forcer, un hook n'écrit aucune troisième valeur dans ce champ : il sort avec le code 0 sans rapporter de décision, et l'appel continue son chemin normal d'approbation, comme si ce hook précis n'avait rien eu à en dire.

Figure 1

Délai d'expiration selon le type de hook et l'événement

Délai d'expiration par défautType de hook concernéDélai par défautParticularité
Hook command, http ou mcp_tool ordinairecommand, http, mcp_tool600 secondesS'applique à la majorité des événements du cycle de vie
UserPromptSubmit, PreModelSwitch, PostModelSwitchcommand, http, mcp_tool30 secondesCes trois événements abaissent le délai normalement fixé à 600 secondes
MessageDisplaycommand, http, mcp_tool10 secondesLe délai le plus court de tous les événements documentés
SessionEndTous types confondus1,5 seconde pour l'ensemble des hooks de l'événementExtensible jusqu'à 60 secondes si un hook déclare explicitement un délai plus long
Hook de type promptprompt30 secondesDélai propre au type, indépendant de l'événement déclencheur
Hook de type agentagent60 secondesDélai propre au type, indépendant de l'événement déclencheur
Le tableau croise le type de hook avec son délai par défaut, et isole les événements qui abaissent ce délai ou qui suivent une règle à part comme SessionEnd.
Figure 2

De l'événement à la décision transmise au modèle

01
Événement déclenché
Un outil est sur le point de s'exécuter, ou vient de le faire, selon l'événement enregistré.
02
Hook exécuté
Le harnais lance la commande, l'appel HTTP, l'outil MCP, l'invite ou l'agent déclaré pour cet événement.
03
Décision rendue en JSON
hookSpecificOutput.permissionDecision porte allow ou deny, accompagné de permissionDecisionReason, et hookEventName reprend le nom de l'événement.
04
Contexte ajouté ou action bloquée
additionalContext enrichit ce que le modèle voit, ou l'appel est annulé avant de se produire si l'événement est PreToolUse.
05
Code de sortie 2 en filet
Il bloque l'action même si le JSON dit allow, sauf pour les événements qui ne l'honorent pas, comme PostToolUse où il n'est qu'affiché à Claude via stderr.
La séquence situe le moment où PreToolUse peut encore empêcher l'appel, et celui où PostToolUse ne peut plus que constater ce qui vient de se produire.
Calibrez vous-même

Un développeur configure un hook PostToolUse qui renvoie un code de sortie 2 après chaque appel de l'outil Bash. Il lance ensuite une commande Bash depuis Claude Code et observe que la commande s'exécute jusqu'au bout.

Écrivez en une phrase ce que cette situation établit, et en une phrase ce qu'elle n'établit pas.

Ce qu’il faut retenir
  • PreToolUse peut empêcher un appel d'outil de se produire, PostToolUse ne peut plus que réagir une fois l'outil déjà lancé.
  • Le délai par défaut de six cents secondes pour un hook command, http ou mcp_tool descend à trente secondes sur trois événements et à dix secondes sur un seul.
  • La décision d'un hook passe par le champ hookSpecificOutput.permissionDecision, avec les valeurs confirmées allow et deny, jamais par une phrase écrite sur la sortie standard.
  • Un code de sortie 2 bloque l'action même quand le JSON affirme allow, sauf sur une liste d'événements nommés où il devient un simple message affiché à Claude.
  • Pour déférer au flux de permission habituel plutôt que de forcer allow ou deny, un hook sort avec le code 0 sans rapporter de décision, il n'existe pas de troisième valeur écrite dans permissionDecision.
À faire maintenant

Écrivez un hook PreToolUse minimal qui sort avec le code 0 sans rien écrire sur sa sortie standard, déclarez le sur un événement anodin, et confirmez que l'appel continue son chemin normal d'approbation plutôt que d'être forcé.

Vérifier à la source

Chaque affirmation datable de cette leçon renvoie ici au texte public qui la porte. Une source qui ne s’ouvre pas ne prouve rien.