Aller au contenu principal
Leçon 17 sur 20 · Claude Code en action

Autres types de hooks

Leçon 17 sur 20 Mis à jour le 4 novembre 2026 Développeur
Sur cette page
  1. L’inventaire des événements
  2. Le défi : des entrées qui changent
  3. Astuce : le hook de débogage
  4. Au-delà de la commande shell
  5. À vous de jouer
  6. Points clés à retenir

PreToolUse et PostToolUse 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, le moment où Claude s’arrête, une compaction, un changement de modèle, un fichier qui change sur le disque. Claude Code expose une trentaine d’événements. Cette leçon les classe, explique ce que chacun reçoit, et donne la méthode pour découvrir la forme exacte des données avant d’écrire une ligne de logique.

L’inventaire des événements

MomentÉvénementCe qu’on en fait
SessionSessionStart (matchers startup, resume, clear, compact, fork)Charger du contexte, des variables d’environnement, réinjecter après compaction
SetupPréparation unique en CI (claude --init-only, -p --init)
SessionEnd (matchers clear, resume, logout, prompt_input_exit, other)Nettoyage, statistiques ; 1,5 s de budget
InstructionsLoaded, ConfigChange, CwdChanged, DirectoryAdded, FileChangedJournaliser quel CLAUDE.md a chargé, auditer une modification de réglages, recharger l’environnement, réagir à un fichier qui change
TourUserPromptSubmitEnrichir ou bloquer un prompt, nommer la session ; 30 s de délai par défaut
UserPromptExpansionBloquer l’expansion d’une commande tapée
Stop, StopFailureEmpêcher Claude de s’arrêter tant qu’une condition n’est pas remplie ; réagir à une erreur d’API
Notification (matchers permission_prompt, idle_prompt…)Prévenir ailleurs que dans le terminal
PreCompact (manual, auto), PostCompactBloquer ou accompagner une compaction
PreModelSwitch, PostModelSwitchInterdire un modèle, ajouter du contexte après un changement
OutilPreToolUse, PostToolUse, PostToolUseFailure, PostToolBatchBloquer, réécrire, donner du feedback, arrêter la boucle avant le prochain appel au modèle
PermissionRequest, PermissionDeniedRépondre à une demande de permission à la place de l’utilisateur ; réagir à un refus du mode Auto
AgentsSubagentStart, SubagentStop (matcher = type d’agent), TeammateIdle, TaskCreated, TaskCompletedSuivre et contrôler les sous-agents et les équipes
AutresWorktreeCreate, WorktreeRemove, Elicitation, ElicitationResult, MessageDisplayRemplacer la création de worktree par Git, répondre à un serveur MCP qui pose une question, modifier l’affichage d’un message

Un hook Stop peut vous prévenir par un signal sonore qu’une tâche longue est terminée. Un hook SessionStart injecte 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 : c’est le point d’entrée naturel pour enrichir ou filtrer ce que vous envoyez, et il se déclenche aussi quand une tâche planifiée ou un sous-agent en arrière-plan relance la session.

Le défi : des entrées qui changent

Cette richesse a une contrepartie. L’entrée stdin de vos commandes change selon l’événement, et le tool_input des événements d’outils change selon l’outil. Un script écrit pour Read en supposant un file_path ne trouvera rien de tel branché sur Bash, dont le champ est command. Comparez l’entrée d’un PostToolUse sur Write :

{
  "session_id": "9ecf22fa-…",
  "cwd": "/code/projet",
  "permission_mode": "auto",
  "hook_event_name": "PostToolUse",
  "tool_name": "Write",
  "tool_input": { "file_path": "/code/projet/README.md", "content": "…" },
  "tool_response": { "filePath": "/code/projet/README.md", "type": "create" },
  "tool_use_id": "toolu_01ABC…",
  "duration_ms": 12
}

et celle d’un hook Stop :

{
  "session_id": "af9f50b6-…",
  "cwd": "/code/projet",
  "hook_event_name": "Stop",
  "stop_hook_active": false,
  "last_assistant_message": "J'ai corrigé la validation et les tests passent.",
  "background_tasks": [],
  "session_crons": []
}

Seuls les champs communs survivent : session_id, cwd, transcript_path, hook_event_name, et selon l’événement permission_mode, effort, agent_id. Tout le reste est spécifique. Stop fournit last_assistant_message, le texte de la dernière réponse, pour qu’un hook de lecture à voix haute ou de notification n’ait pas à parser la transcription, et background_tasks pour distinguer « la session est finie » de « elle attend un travail en arrière-plan ». Notification fournit message, title et notification_type. SessionStart fournit source, SessionEnd fournit reason, UserPromptSubmit fournit prompt, SubagentStop fournit agent_type, agent_transcript_path et son propre last_assistant_message.

Le verdict varie aussi. Les événements d’outils utilisent hookSpecificOutput.permissionDecision ; UserPromptSubmit, PostToolUse, Stop et PreCompact un decision: "block" de premier niveau avec reason ; PermissionRequest un objet decision.behavior ; SessionStart, SubagentStart et PostModelSwitch n’ont pas de décision et ne font qu’ajouter du contexte (additionalContext) ; Notification, SessionEnd, PostCompact, InstructionsLoaded n’en ont aucune et servent aux effets de bord. Le tableau Decision control de la référence résume tout cela ; consultez-le avant d’écrire un hook sur un événement nouveau.

Astuce : le hook de débogage

Plutôt que de deviner, faites-vous montrer les données. Ce hook écrit chaque événement d’outil, sur une ligne, dans un fichier :

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "jq -c . >> \"$CLAUDE_PROJECT_DIR\"/.claude/hook-events.jsonl"
          }
        ]
      }
    ]
  }
}

Le matcher * capture tous les outils, jq -c . compacte chaque JSON sur une ligne. Installez-le, menez une session ordinaire en déclenchant l’outil qui vous intéresse, puis ouvrez le fichier : vous y lisez la structure réelle, avec les noms de champs exacts, sur laquelle écrire votre condition. Déclinez-le sur n’importe quel événement (Stop, Notification, SessionStart) pour en découvrir la forme. Prenez l’habitude d’y recourir en premier : dix minutes d’observation vous épargneront une heure d’hypothèses. En complément, claude --debug journalise chaque exécution de hook dans ~/.claude/debug/<session-id>.txt, et la référence donne un exemple d’entrée pour chaque événement.

Au-delà de la commande shell

Les événements ne se limitent pas aux hooks command. Un hook http envoie le même JSON à une URL et lit le verdict dans la réponse, ce qui permet à une équipe de centraliser un service d’audit. Un hook mcp_tool appelle un outil d’un serveur MCP. Les hooks prompt et agent de la leçon précédente portent du jugement là où une règle ne suffit pas. Et les hooks ne vivent pas que dans les fichiers de réglages : une skill ou un sous-agent peut en déclarer dans son en-tête, actifs le temps de leur exécution, et un plugin les embarque dans hooks/hooks.json.

À vous de jouer

  1. Installez le hook de débogage, faites trois actions différentes (lecture, modification, commande), puis lisez .claude/hook-events.jsonl : repérez tool_input pour chaque outil.
  2. Déclinez-le sur Stop et sur Notification, puis comparez les entrées.
  3. Écrivez un hook UserPromptSubmit qui ajoute la branche Git courante en contexte : echo "Branche : $(git branch --show-current)" suffit, puisque le stdout de cet événement est transmis à Claude.
  4. Écrivez un hook PreModelSwitch qui refuse tout passage à un modèle dont le nom contient haiku, avec permissionDecision: "deny".

Sources officielles : Hooks reference · Automate actions with hooks

Points clés à retenir

  • Une trentaine d’événements couvrent la session, le tour, les outils, les agents et le reste du cycle de vie
  • Chaque événement reçoit des champs propres (tool_input par outil, last_assistant_message sur Stop, source sur SessionStart…) et accepte un format de verdict propre
  • Un hook de débogage (jq -c . >> fichier) révèle la structure exacte avant d’écrire la logique ; claude --debug journalise chaque exécution
  • Les hooks http, mcp_tool, prompt et agent complètent les hooks command ; skills, sous-agents et plugins peuvent en déclarer