Skip to content

Hooks : déclencher automatiquement à des moments précis

📚 Navigation de la série : L'article précédent 32 Styles de sortie (Output Styles) vous a appris comment changer de « personnalité » pour que Claude travaille avec le ton que vous souhaitez. Cet article traite d'un autre type d'« automatisation » — non pas modifier sa façon de parler, mais exécuter systématiquement une action pour vous dès qu'un certain événement se produit : formater automatiquement après la modification d'un fichier, bloquer net les commandes dangereuses, ou vous envoyer une notification lorsqu'il a terminé son travail. Ce sont les Hooks.

Imaginez ce chiffre : au cours d'une semaine donnée, le nombre de fois où vous avez dû exécuter manuellement prettier --write après que Claude a modifié le code était de 23 fois.

23 fois. La même action, répétée mécaniquement 23 fois. Pire encore, vous l'avez oubliée deux fois en chemin — après avoir soumis le code, il a été rejeté par la vérification de formatage de l'intégration continue (CI), et vous avez dû relancer tout le processus.

À ce stade, une question se pose : pourquoi ce genre d'action « qui doit être faite à chaque fois et de manière identique » devrait-elle reposer sur la mémoire humaine ou sur la bonne volonté de Claude ? Vous avez écrit « n'oubliez pas d'exécuter prettier après avoir modifié les fichiers » dans CLAUDE.md, mais il l'oublie une fois sur trois — parce que ce n'est qu'une requête, pas une garantie.

En configurant un Hook, avec une seule ligne de configuration, le problème disparaît complètement : dès lors, chaque fois que Claude modifie un fichier, le formatage s'exécute automatiquement. Vous n'avez plus jamais tapé prettier manuellement, et vous n'avez plus jamais été rejeté par la CI. Cet article vous explique tout sur cet outil de « déclenchement automatique », de sa définition à sa configuration et son débogage.

À la fin de cet article, vous obtiendrez :

  • Une explication en une phrase de ce qu'est un Hook et de sa différence fondamentale avec « une requête écrite dans CLAUDE.md »
  • Quels « moments » du cycle de vie de Claude permettent d'accrocher des hooks (PreToolUse / PostToolUse / Stop / SessionStart, etc.)
  • Dans quel fichier configurer les hooks, et comment utiliser matcher pour restreindre son déclenchement uniquement lors de la modification de fichiers
  • Trois exemples réels prêts à être copiés : formatage automatique après modification, blocage des commandes dangereuses, et envoi de notifications une fois terminé
  • Comment les hooks et Claude communiquent entre eux (le JSON de stdin, les codes de sortie, stdout) — c'est la clé pour tout comprendre
  • Comment diagnostiquer étape par étape les hooks qui ne se déclenchent pas ou qui renvoient des erreurs

01 Comprendre d'abord : Qu'est-ce qu'un Hook et quelle est sa force en matière de « garantie »

Commençons par la conclusion : un Hook est « une commande ou une requête qui s'exécute automatiquement dès qu'un certain événement se produit » — il ne dépend pas de la réflexion de Claude pour décider de s'exécuter ou non, son déclenchement est garanti. (Les plus courantes sont les commandes shell, mais il prend également en charge les points de terminaison HTTP, les outils MCP, les invites LLM, etc.)

La définition officielle est très directe, la voici :

Hooks 是用户定义的 shell 命令,在 Claude Code 生命周期中的特定点执行。它们对 Claude Code 的行为提供确定性控制,确保某些操作始终发生,而不是依赖 LLM 选择运行它们。

Notez deux termes clés ici : « contrôle déterministe » et « se produisent toujours ». C'est là que réside toute la force des hooks.

Analogie : Les règles d'automatisation de votre maison (« Quand... Alors... »). Vous avez probablement configuré ce type de règles pour votre maison connectée — « Quand quelqu'un ouvre la porte, Alors allumer la lumière », « Quand je quitte la maison, Alors éteindre toutes les prises ». Dès que la condition est remplie, l'action se produit inévitablement, sans que personne n'ait à s'en souvenir. Un Hook est ce type de règle appliqué à Claude Code — vous définissez « Quand tel événement se produit, Alors exécuter cette commande », et il s'exécute automatiquement, sans faute.

Voici la différence la plus cruciale à retenir : ce qui est écrit dans CLAUDE.md est une « requête » — Claude a de fortes chances de la suivre, mais peut l'oublier ; ce qui est configuré comme un Hook est une « garantie » — dès que l'événement se produit, l'action est exécutée à coup sûr, peu importe si Claude s'en souvient ou non. Les mots officiels :

CLAUDE.md 或 skill 中的「永远不要编辑 .env」之类的说明是请求,而不是保证。阻止编辑的 PreToolUse hook 是强制执行。

C'est la cause profonde de ces 23 fois du début : « exécuter prettier après modification » écrit dans CLAUDE.md is a request, forgotten once in three times; configured as a Hook is a guarantee, never missed. (C'est la cause profonde de ces 23 fois du début : « exécuter prettier après modification » écrit dans CLAUDE.md est une requête, oubliée une fois sur trois ; configuré en tant que Hook, c'est une garantie, jamais oubliée.)

Voici quelques scénarios que vous rencontrerez très probablement et qui méritent une « garantie », pour vous donner une idée :

  • « Formater / exécuter un lint automatiquement après chaque modification de fichier » — ne le tapez plus manuellement, et ne comptez pas sur sa bonne volonté.
  • « Bloquer strictement les commandes comme rm -rf ou la suppression de bases de données de production » — cela doit être bloqué de manière déterministe, et non pas reposer sur des instructions.
  • « M'envoyer une notification de bureau lorsqu'il a fini de travailler ou qu'il attend ma saisie » — pour que vous puissiez passer à autre chose sans avoir à surveiller le terminal.

💡 En résumé : Un Hook est une « action automatique déclenchée par un événement ». Sa valeur fondamentale est de transformer une « requête » en « garantie » — ce que vous demandez à Claude de faire via CLAUDE.md peut être oublié, mais un Hook est inévitablement exécuté dès que l'événement associé se produit.


02 Quels « moments » peuvent accueillir des hooks : Comprendre les événements du cycle de vie

Vous ne pouvez pas accrocher un Hook n'importe quand ; il doit être associé à un « moment » spécifique du flux de travail de Claude. Ces moments sont appelés officiellement des événements (events). Pour bien utiliser les hooks, la première étape consiste à identifier clairement « quand je veux que cela se produise ».

Rappelez-vous la « boucle de l'agent » présentée dans l'article 03 — Claude travaille en boucle : « Réfléchir → Agir → Observer ». Ces événements sont répartis tout au long de cette boucle. L'organisation officielle les classe en trois catégories selon leur fréquence de déclenchement, ce qui est très facile à retenir :

  • Une fois par session : SessionStart (lorsque la session commence ou reprend), SessionEnd (lorsque la session se termine)
  • Une fois par tour de conversation : UserPromptSubmit (dès que vous soumettez une invite, avant que Claude ne commence à la traiter), Stop (lorsque Claude a fini de répondre pour ce tour)
  • À chaque appel d'outil dans la boucle de l'agent : PreToolUse (juste avant qu'un outil ne soit exécuté), PostToolUse (juste après qu'un outil a été exécuté avec succès)

Dit comme ça, c'est un peu abstrait. Schématisons cela pour comprendre immédiatement où se situent les événements les plus courants :

7 moments des hooks de Claude Code : SessionStart → UserPromptSubmit → Boucle d'outils Pre/Post → Stop → SessionEnd

Ce schéma déroule la boucle « Réfléchir → Agir → Observer » : l'entrée en session déclenche SessionStart, votre message déclenche UserPromptSubmit, puis commence la boucle de décision d'utilisation des outils — chaque appel d'outil est précédé de PreToolUse et suivi de PostToolUse. Une fois la boucle de ce tour terminée, l'événement Stop se produit, et la session se termine avec SessionEnd. Configurez votre action sur l'événement correspondant au moment où vous souhaitez qu'elle se produise.

Ces six événements sont les plus utilisés au quotidien. En réalité, plus d'une trentaine d'événements sont pris en charge officiellement (comme PreCompact/PostCompact pour la compression, FileChanged pour les modifications de fichiers sur le disque, ConfigChange pour les modifications de configuration, ou SubagentStart/SubagentStop pour le démarrage et l'arrêt des sous-agents). Cependant, pour les débutants, maîtriser les quatre événements suivants permet de couvrir 90 % des besoins :

ÉvénementQuand se déclenche-t-ilUtilisation la plus typique
PreToolUseAvant l'exécution d'un outilBloquer des commandes dangereuses, protéger des fichiers sensibles (peut bloquer l'opération)
PostToolUseAprès l'exécution réussie d'un outilFormater automatiquement / lancer un lint après modification de fichiers
StopLorsque Claude a fini de répondre pour ce tourRappeler « le travail n'est pas fini, continue », analyser l'espace de travail
SessionStartAu démarrage ou à la reprise d'une sessionInjecter l'état du projet dans le contexte (comme les derniers commits)

Il y a une astuce pour mémoriser ce tableau : regardez les préfixes Pre et Post dans les nomsPre signifie « avant », donc seul cet événement peut bloquer l'action avant qu'elle ne se produise ; Post signifie « après », l'outil s'est déjà exécuté, donc il ne peut qu'appliquer une action corrective (formatage, journalisation) mais ne peut rien bloquer. Cette différence est détaillée dans la section suivante.

💡 En résumé : Un Hook s'associe à un événement spécifique du cycle de vie de Claude. Les événements sont classés en trois fréquences (par session, par tour, ou par appel d'outil). Les débutants peuvent se contenter de maîtriser ces quatre événements : PreToolUse (avant, peut bloquer), PostToolUse (après, action corrective), Stop (fin de réponse) et SessionStart (démarrage de session).


03 Dans quel fichier configurer les hooks, et comment utiliser matcher pour les restreindre

Maintenant que vous connaissez les événements disponibles, voyons comment configurer les hooks. Les hooks s'écrivent dans le fichier de configuration (settings.json) — le système de configuration présenté en détail dans l'article 31. Le fichier dans lequel vous l'écrivez détermine sa portée :

Fichier de configurationPortée d'applicationPeut-il être partagé avec l'équipe
~/.claude/settings.jsonTous vos projetsNon, uniquement sur votre machine
.claude/settings.json(项目根)Uniquement le projet actuelOui, peut être validé dans git
.claude/settings.local.json(项目根)Uniquement le projet actuelNon, ignoré par gitignore

C'est la même logique que celle du « meuble d'archivage du projet » et du « tiroir de bureau individuel » présentée dans l'article 31 : les hooks qui s'appliquent à toute l'équipe (comme « formater systématiquement après modification ») doivent être écrits dans le fichier .claude/settings.json du projet et suivis par git ; les hooks personnels (comme l'envoi de notifications sur votre propre bureau) doivent être écrits dans ~/.claude/settings.json.

Hook 配置长什么样

Voyons d'abord un exemple minimal complet — « formater automatiquement avec prettier chaque fois qu'un fichier est modifié via Edit ou Write », la configuration qui résout le problème des 23 fois. Ajoutez ceci dans le fichier .claude/settings.json à la racine de votre projet :

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}

Ne vous laissez pas effrayer par cette imbrication, elle ne comporte que trois niveaux. Décortiquons-la ensemble pour comprendre immédiatement :

  1. "PostToolUse" — L'événement auquel s'associer (ici : après l'exécution d'un outil).
  2. "matcher": "Edit|Write" — La restriction aux outils qui déclenchent le hook (ici : uniquement après les outils Edit ou Write, pas après Bash ou Read).
  3. Le tableau hooks interne — L'action concrète à exécuter : "type": "command" indique l'exécution d'une commande shell, et "command" est la commande elle-même.

L'outil jq dans cette commande est un petit utilitaire d'analyse JSON (installable via brew install jq sur Mac ou apt-get install jq sur Ubuntu). Son rôle sera détaillé dans la section suivante — pour faire simple, il permet d'extraire le chemin du fichier fraîchement modifié à partir des données fournies par Claude, puis de le passer à prettier.

matcher:让钩子「只在该触发的时候触发」

Le champ matcher est le champ le plus important à comprendre dans la configuration des hooks. En une phrase : sans lui, le hook se déclenche à chaque occurrence de l'événement ; avec lui, vous pouvez restreindre sa portée.

Analogie : La consigne de sécurité à l'entrée d'un bâtiment — pas de livraison, pas d'accès. Un hook sans matcher est comparable à demander à un agent de sécurité d'« enregistrer l'identité de chaque personne qui se présente », ce qui est inefficace. Avec un matcher, cela devient « enregistrer l'identité uniquement s'il s'agit d'un livreur, laisser passer les autres directement ». Le matcher sert à restreindre la portée du hook.

Pour les événements liés aux outils (PreToolUse/PostToolUse), le matcher effectue sa correspondance sur le nom de l'outil. Il existe trois syntaxes possibles, détaillées dans ce tableau :

Syntaxe du matcherSignificationExemple
"Edit|Write"Correspondance exacte avec ces outils (| signifie « ou »)Déclenché uniquement après Edit ou Write
"Bash"Correspondance exacte avec un seul outilDéclenché uniquement lors de l'exécution d'une commande Bash
"" ou omisCorrespondance globale, déclenché à chaque foisExécuté à chaque occurrence de l'événement

Attention : le matcher est sensible à la casse. Écrire edit ne correspondra pas à l'outil Edit — c'est l'une des erreurs les plus fréquentes pour lesquelles un hook de débutant ne se déclenche pas.

Autre détail souvent omis par les débutants : certains événements ne prennent pas du tout en charge le matcher (comme UserPromptSubmit ou Stop), car ils n'ont pas de « nom d'outil » à filtrer. Ils se déclenchent donc systématiquement à chaque fois. Ajouter un matcher sur ces événements sera ignoré en silence.

💡 En résumé : Les hooks s'écrivent dans settings.json (dans votre répertoire personnel pour la configuration globale, ou dans .claude/ pour le projet). La configuration comporte trois niveaux — l'événement, le matcher, et l'action ; le matcher sert à restreindre le hook aux seuls outils ciblés, et il est sensible à la casse.


04 Comment les hooks et Claude communiquent : stdin, codes de sortie et stdout

Cette section est la clé pour tout comprendre. Comment la commande jq précédente a-t-elle pu récupérer le chemin du fichier ? Comment un hook peut-il « bloquer » une commande ? Les réponses résident entièrement dans ce mécanisme d'échange.

Le mécanisme lui-même est extrêmement simple et repose sur trois canaux : Claude envoie les données de l'événement à votre script via stdin → le script effectue son travail → le script utilise « le code de sortie + stdout » pour indiquer à Claude la marche à suivre. Détaillons chaque élément.

Entrée : Claude vous transmet du JSON via stdin

Dès qu'un événement est déclenché, Claude Code injecte les données associées à cet événement sous forme de JSON dans l'entrée standard (stdin) de votre commande. Par exemple, lorsque Claude s'apprête à exécuter une commande Bash, le hook PreToolUse reçoit des données ressemblant à ceci :

json
{
  "session_id": "abc123",
  "cwd": "/Users/sarah/myproject",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "npm test"
  }
}

Comme vous pouvez le voir — ce que Claude s'apprête à faire, l'outil utilisé et les arguments associés sont entièrement décrits à l'intérieur. La commande jq -r '.tool_input.file_path' vue à la section 03 extrait précisément le chemin tool_input.file_path (le fichier à modifier) de ce bloc JSON. L'utilitaire jq sert à analyser le JSON, et l'option -r lui indique de renvoyer du texte brut (sans guillemets).

Sortie : Indiquer la suite à Claude à l'aide du « code de sortie »

Une fois son travail terminé, le script utilise son code de sortie (exit code) pour transmettre ses instructions à Claude. C'est la convention fondamentale des hooks, il suffit de retenir trois valeurs :

Code de sortieSignificationEffet
0Pas d'objection, continuer normalementL'opération se poursuit (lors d'un PreToolUse, cela ne vaut pas approbation ; le flux d'autorisation habituel s'applique)
2Bloquer !L'opération est empêchée ; le contenu écrit sur stderr est renvoyé comme retour d'information à Claude pour qu'il s'adapte
Autre (ex: 1)Erreur rencontrée, mais sans bloquerL'opération se poursuit, et le terminal affiche un message d'erreur de hook

Le point crucial est exit 2 — c'est le seul moyen pour un hook de « serrer le frein ». Attention à un piège contre-intuitif :

对于大多数 hook 事件,仅退出代码 2 阻止操作。Claude Code 将退出代码 1 视为非阻止错误并继续操作,尽管 1 是传统的 Unix 失败代码。如果您的 hook 旨在强制执行策略,请使用 exit 2

En clair : pour bloquer une opération, vous devez renvoyer exit 2 et non exit 1. Beaucoup de développeurs écrivent exit 1 par habitude Unix, ce qui produit un hook qui « signale une erreur mais ne bloque pas l'exécution », laissant la commande s'exécuter. C'est le piège classique lors de la première écriture d'un hook d'interception — le script a pourtant détecté la commande dangereuse et affiché une alerte, mais à cause d'un simple exit 1 machinal, Claude poursuit son action, ce qui peut donner des sueurs froides.

Un autre détail important concernant la capacité de blocage : seuls les événements de type Pre peuvent réellement bloquer une opération. Si PostToolUse renvoie un exit 2, il ne bloquera rien — l'outil s'est déjà exécuté, les carottes sont cuites, et le hook pourra seulement afficher le contenu de stderr à Claude. C'est l'illustration de la phrase de la section précédente : « Pre peut bloquer, Post ne fait qu'intervenir après coup ».

Avancé : Renvoyer du JSON sur stdout pour un contrôle plus précis

Les codes de sortie ne proposent que deux états (« bloquer / ne pas bloquer »). Si vous souhaitez un contrôle plus fin (comme bloquer tout en indiquant à Claude la raison précise, ou injecter des informations dans son contexte de travail), renvoyez exit 0 et écrivez un bloc JSON sur stdout.

用退出码 2 配 stderr 来「阻止」,或用 JSON 配退出码 0 来做「结构化控制」。两者不要混用:你退出 2 时,Claude Code 会忽略 JSON。

Voici les deux structures JSON les plus courantes :

① Intercepter lors de PreToolUse en fournissant un motif — utiliser permissionDecision :

json
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "这条命令会动生产库,禁止执行"
  }
}

permissionDecision accepte quatre valeurs : "deny" (bloquer et transmettre le motif à Claude), "ask" (demander confirmation via la boîte de dialogue habituelle), "allow" (ignorer la demande de confirmation et autoriser directement l'exécution), et "defer" (différer l'exécution pour reprendre l'outil plus tard, idéal pour des scénarios d'approbation asynchrone en mode non interactif).

Il y a une règle de sécurité absolue à clarifier ici, en lien avec la gestion des autorisations et de la sécurité des articles 20 et 21 : un hook qui renvoie "allow" ne peut pas contourner les règles de refus définies dans votre configuration. Voici les termes officiels :

返回 "allow" 跳过交互式提示但不覆盖权限规则。如果拒绝规则与工具调用匹配,即使你的 hook 返回 "allow",调用也会被阻止。

En d'autres termes : un Hook peut uniquement « resserrer » les restrictions, mais il ne peut jamais les « relâcher » au-delà des limites fixées par vos règles d'autorisation. C'est un aspect fondamental de la sécurité — cela garantit qu'un hook malveillant ne pourra pas désactiver vos barrières de sécurité en renvoyant allow. À l'inverse, la priorité d'interception d'un hook PreToolUse est extrêmement élevée : même si vous utilisez l'option --dangerously-skip-permissions (qui désactive toutes les confirmations), un hook renvoyant deny bloquera tout de même l'opération. Utiliser des hooks pour imposer des règles strictes au sein d'une équipe est donc une méthode infaillible.

② Injecter des informations dans le contexte lors du SessionStart — il suffit d'écrire du texte brut sur stdout (ces événements spécifiques traitent stdout comme du contexte injecté à Claude). Par exemple, lui communiquer les 5 derniers commits dès l'ouverture de la session :

json
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "git log --oneline -5"
          }
        ]
      }
    ]
  }
}

💡 En résumé : Les hooks et Claude communiquent à travers trois canaux — les données JSON entrantes via stdin, les instructions renvoyées par le code de sortie, et le contrôle précis via stdout. Retenez absolument ces trois règles : « seul exit 2 bloque l'opération (pas le 1) », « ne mélangez pas le code de sortie avec du JSON », et « un Hook peut uniquement restreindre les droits, jamais les élargir ». Vous maîtriserez ainsi 70 % du sujet.


05 Trois exemples réels prêts à être copiés

Assez de théorie, passons à trois cas pratiques de hooks courants et immédiatement utilisables. Chaque exemple détaille l'événement cible, sa restriction, et le fichier de configuration associé.

Exemple 1 : Formatage automatique après modification (PostToolUse)

C'est la solution qui corrige le problème des 23 formatages manuels du début du chapitre. Il est très pratique, sans aucun risque, et fortement recommandé pour tous les projets. À écrire dans le fichier .claude/settings.json à la racine de votre projet :

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}

Logique : À chaque fois que Claude modifie un fichier à l'aide de Edit/Write → le hook extrait le chemin du fichier depuis le JSON reçu sur stdin → il le passe à la commande prettier --write pour le formater. Dorénavant, le formatage reste toujours propre sans aucune intervention de votre part. Vous pouvez remplacer prettier par eslint --fix, gofmt ou black selon la même logique.

Exemple 2 : Bloquer les commandes dangereuses (PreToolUse + script)

Cette approche utilise l'interception par exit 2. Lorsque les commandes sont complexes, écrire la logique dans un script indépendant est beaucoup plus propre que de tout imbriquer dans du JSON.

Étape 1 : Enregistrez le script sous .claude/hooks/block-dangerous.sh :

bash
#!/bin/bash
# block-dangerous.sh:拦截 rm -rf 这类危险命令
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')

if echo "$COMMAND" | grep -q "rm -rf"; then
  echo "Blocked: 检测到 rm -rf,已拦截" >&2   # 写到 stderr,会反馈给 Claude
  exit 2                                       # exit 2 = 阻止这次工具调用
fi

exit 0   # 其余命令放行,走正常权限流程

Étape 2 : Rendez le script exécutable (obligatoire sous Mac/Linux, sinon Claude ne pourra pas le lancer) :

bash
chmod +x .claude/hooks/block-dangerous.sh

Étape 3 : Déclarez-le dans .claude/settings.json en l'associant à l'outil Bash sur l'événement PreToolUse :

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-dangerous.sh"
          }
        ]
      }
    ]
  }
}

La variable $CLAUDE_PROJECT_DIR ici présente est une variable d'environnement fournie par Claude Code qui pointe vers la racine du projet — l'utiliser pour construire les chemins permet au hook de localiser le script de manière fiable, quel que soit le sous-répertoire d'exécution, contrairement à un chemin relatif codé en dur.

⚠️ Cette section nous ramène à la ligne directrice sur la sécurité de l'article 21 : les hooks s'exécutent avec vos privilèges utilisateur complets dans le shell et peuvent supprimer tout fichier auquel vous avez accès. Les instructions officielles rappellent à plusieurs reprises qu'il faut auditer la commande de chaque hook avant de l'ajouter, et surtout d'éviter d'insérer des scripts entiers copiés depuis des sources non vérifiées directement dans vos configurations.

Exemple 3 : Envoyer une notification de bureau lorsqu'il a besoin de votre saisie (Notification)

Lorsque Claude s'interrompt pour vous demander une confirmation, ou qu'il a fini de répondre et attend votre prochaine instruction, vous êtes probablement déjà passé sur une autre fenêtre. Associer un hook de notification lui permet de vous appeler de manière proactive. Cela utilise l'événement Notification (déclenché lorsque Claude émet une notification).

Pour macOS, écrivez ceci dans ~/.claude/settings.json (ce type de hook personnalisé relève de vos préférences personnelles et doit être configuré de manière globale) :

json
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code 在等你\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Différences par plateforme (les commandes natives fournies officiellement sont à copier telles quelles) :

PlateformeCommande de notification (à renseigner dans command)
macOSosascript -e 'display notification "..." with title "Claude Code"'
Linuxnotify-send 'Claude Code' '...'
WindowsUtiliser la MessageBox de PowerShell (la documentation officielle contient le fragment complet)

Sous macOS, si la notification ne s'affiche pas, c'est très probablement parce que l'éditeur de script (Script Editor) ne dispose pas des autorisations de notification — allez dans « Réglages Système → Notifications » pour localiser l'éditeur de script et activer l'interrupteur. Lors de la première configuration, il arrive souvent que rien ne se produise et qu'on passe du temps à chercher pour se rendre compte qu'il s'agissait simplement de cette autorisation.

💡 En résumé : Les three examples se classent par risque croissant — le formatage (PostToolUse, risque nul, recommandé pour tous), le blocage de commandes (PreToolUse + script, pensez à chmod +x et exit 2), et l'envoi de notifications (Notification, commandes variables selon l'OS) ; la construction du chemin de script avec $CLAUDE_PROJECT_DIR est la méthode la plus robuste. (💡 En résumé : Les trois exemples se classent par risque croissant — le formatage (PostToolUse, risque nul, recommandé pour tous), le blocage de commandes (PreToolUse + script, pensez à chmod +x et exit 2), et l'envoi de notifications (Notification, commandes variables selon l'OS) ; la construction du chemin de script avec $CLAUDE_PROJECT_DIR est la méthode la plus robuste.)


06 Pratique : Configurer un hook en 5 minutes et le voir s'exécuter

La théorie sans pratique ne permet pas de retenir. Mettons en place un hook très sûr et aux effets immédiatement visiblesenregistrer chaque commande exécutée par Claude dans un fichier journal après chaque appel de l'outil Bash. Cette manipulation ne touche aucun de vos fichiers de code et repose uniquement sur l'ajout d'une configuration simple, dont vous pourrez vérifier le résultat de vos propres yeux.

Cet exercice nécessite jq. S'il n'est pas installé : exécutez brew install jq sur Mac, ou sudo apt-get install jq sous Ubuntu. Son installation ne nécessite pas de configuration réseau particulière.

Étape 1 : Choisissez un répertoire de test et ouvrez son fichier de configuration de projet

Créez un nouveau répertoire vide (n'utilisez pas un projet de production pour vos tests) et créez-y le fichier .claude/settings.json. Si ce fichier existe déjà et contient d'autres configurations, insérez la clé hooks au même niveau sans écraser le reste. Contenu du fichier :

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.command' >> ~/claude-bash-log.txt"
          }
        ]
      }
    ]
  }
}

Ce hook fonctionne ainsi : chaque fois que l'outil Bash termine son exécution (PostToolUse + matcher: "Bash") → il extrait la commande à partir du JSON fourni sur stdin → il l'écrit à la suite dans le fichier claude-bash-log.txt situé dans votre répertoire personnel à l'aide de l'opérateur >>.

Étape 2 : Lancez Claude dans ce répertoire et vérifiez que le hook est bien enregistré

bash
claude

Une fois à l'intérieur, saisissez la commande /hooks :

text
/hooks

Résultat attendu : Un explorateur de hooks en lecture seule s'ouvre, listant tous les événements. Localisez l'événement PostToolUse, qui devrait indiquer la présence d'un hook associé. Sélectionnez-le pour afficher ses détails : l'événement concerné, le matcher (Bash), le fichier source (Project, c'est-à-dire le fichier .claude/settings.json du projet), ainsi que la commande à exécuter. La présence du hook dans cette liste confirme son bon enregistrement.

Le menu /hooks est en lecture seule — il vous permet uniquement de consulter les configurations existantes, sans possibilité d'ajout ou de modification directe. Pour modifier un hook, éditez directement le fichier settings.json, ou demandez à Claude de s'en charger pour vous.

Étape 3 : Demandez à Claude d'exécuter une commande Bash pour déclencher le hook

Appuyez sur Esc pour revenir à la conversation et demandez-lui d'exécuter une commande inoffensive :

text
帮我用 ls 看一下当前目录有哪些文件

Claude va appeler l'outil Bash pour lancer la commande ls. Cette exécution doit normalement déclencher le hook PostToolUse. (Lorsqu'un hook s'exécute correctement, il reste silencieux sans afficher de notification particulière dans le terminal — c'est le comportement normal.)

Étape 4 : Vérifiez que le hook a bien fonctionné en consultant le fichier journal

Ouvrez un nouveau terminal pour lire le journal :

bash
cat ~/claude-bash-log.txt

Résultat attendu : Le fichier doit contenir la commande ls que vous venez de lancer (ainsi que les autres commandes Bash éventuellement exécutées par Claude durant cette session). Le fait que la commande soit enregistrée confirme le bon fonctionnement automatique du hook après chaque appel de Bash ; votre première règle d'automatisation est opérationnelle.

Étape 5 : Nettoyage (facultatif)

Pour retirer la configuration de test, c'est très simple — supprimez simplement la section hooks de votre fichier .claude/settings.json (il n'existe pas de commande spécifique de suppression, il suffit de retirer la déclaration du fichier). Supprimez le fichier journal avec rm ~/claude-bash-log.txt.

En réalisant ces cinq étapes, vous venez de parcourir par vous-même l'ensemble de la chaîne : « Définition de la configuration → Vérification de l'enregistrement avec /hooks → Déclenchement de l'événement → Validation des effets secondaires ». Le déploiement de tout autre hook suivra exactement ce même schéma, seules les variables d'événement, de matcher ou de commande changeront.

💡 En résumé : Pour débuter en toute sécurité, la configuration d'un hook enregistrant les commandes Bash est idéale — écriture dans .claude/settings.json, validation de l'enregistrement avec /hooks, exécution d'une commande par Claude, puis vérification du fichier journal ; observer l'effet concret par vous-même est bien plus efficace que d'apprendre dix définitions par cœr. (💡 En résumé : Pour débuter en toute sécurité, la configuration d'un hook enregistrant les commandes Bash est idéale — écriture dans .claude/settings.json, validation de l'enregistrement avec /hooks, exécution d'une commande par Claude, puis vérification du fichier journal ; observer l'effet concret par vous-même est bien plus efficace que d'apprendre dix définitions par cœur.)


07 Que faire si un hook ne se déclenche pas ou renvoie une erreur

Un hook configuré qui ne réagit pas est l'une des difficultés les plus courantes chez les débutants. Évitez les suppositions et suivez cette liste de vérifications dans l'ordre pour identifier l'origine du problème. Voici une synthèse de la liste officielle structurée par « Symptôme → Méthode de diagnostic » :

SymptômeCause la plus probable / Méthode de diagnostic
Le hook ne se déclenche pas du tout① Lancez /hooks pour vérifier s'il est bien enregistré ; ② Le matcher est sensible à la casse, edit ne correspondra pas à Edit ; ③ L'événement associé est incorrect (pour bloquer une action, utilisez PreToolUse, pas PostToolUse)
Le hook configuré n'apparaît pas dans /hooks① Le format du fichier JSON est incorrect (le JSON n'autorise ni les virgules de fin ni les commentaires) ; ② L'emplacement du fichier est incorrect (les hooks de projet se placent dans .claude/settings.json, les globaux dans ~/.claude/settings.json) ; ③ Si la modification ne s'applique pas, relancez la session
Le terminal affiche hook errorLe script s'est arrêté avec un code de retour non nul. Testez-le manuellement (voir la commande ci-dessous) ; l'erreur command not found indique souvent un chemin de script incorrect, utilisez un chemin absolu ou $CLAUDE_PROJECT_DIR ; l'erreur jq: command not found signifie que jq n'est pas installé
Le script ne s'exécute pasSous Mac/Linux, l'autorisation d'exécution a été oubliée, ajoutez chmod +x
L'opération devait être bloquée mais s'est exécutéeC'est très probablement dû à un code exit 1 au lieu de exit 2 (voir l'avertissement de la section 04)

Voici deux méthodes de diagnostic particulièrement utiles à retenir :

① Injecter manuellement des données de test pour évaluer le script. Il n'est pas nécessaire de provoquer un vrai déclenchement dans Claude ; construisez un flux JSON simulé et transmettez-le à votre script pour analyser son code de sortie :

bash
echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /tmp/x"}}' | ./block-dangerous.sh
echo $?   # 看退出码:拦截脚本这里应该输出 2

C'est la procédure classique pour tester les hooks d'interception — valider le comportement du script de manière autonome avant de le lier à Claude, ce qui évite de multiples essais au sein d'une session de travail réelle.

② Activer les journaux de débogage pour examiner les détails. Pour identifier quels hooks correspondent aux filtres, connaître leurs codes de sortie ainsi que leurs sorties stdout/stderr, démarrez Claude avec l'option --debug. Les journaux seront écrits dans le fichier ~/.claude/debug/<id_session>.txt :

bash
claude --debug

Vous pouvez également lancer la commande /debug directement au cours d'une session pour activer ce mode. Le journal contiendra des entrées similaires à celles-ci, ce qui vous permettra d'identifier instantanément si et comment les hooks se sont exécutés :

text
[DEBUG] Executing hooks for PostToolUse:Bash
[DEBUG] Hook command completed with status 0

Un interrupteur général est également bon à connaître : pour désactiver temporairement tous vos hooks (si vous suspectez l'un d'eux de perturber le fonctionnement), ajoutez simplement la ligne "disableAllHooks": true dans votre fichier de configuration, ce qui vous évite de devoir les retirer individuellement.

💡 En résumé : Si un hook ne réagit pas, évitez les tâtonnements et suivez cet ordre de diagnostic — vérifier l'enregistrement avec /hooks → valider la casse du matcher et le choix de l'événement → tester le script en lui injectant du JSON → consulter les logs avec --debug. Si un blocage échoue, vérifiez d'abord si le script ne renvoie pas un exit 1 par erreur.


08 Résumé

Dans cet article, nous avons exploré les hooks depuis leur concept initial jusqu'à leur mise en œuvre et leur débogage — il s'agit de « règles d'automatisation » intégrées à Claude Code : dès qu'un événement se produit, l'action associée s'exécute systématiquement pour vous.

Synthétisons les points clés à retenir :

ObjectifMise en œuvrePoint clé
Comprendre ce qu'est un HookCommande shell automatique liée à un événementTransforme les « requêtes » en « garanties », sans dépendre de l'autonomie de Claude
Choisir le bon moment d'associationIdentifier les événements du cycle de viePre permet de bloquer, Post applique des actions correctives, Stop signale la fin de la réponse, SessionStart correspond au lancement
Écrire un HookL'ajouter dans settings.jsonTrois niveaux : événement + matcher (sensible à la casse) + action
Gérer la communicationstdin / codes de sortie / stdoutSeul exit 2 permet de bloquer, ne mélangez pas codes de sortie et JSON
Bloquer les opérations dangereusesPreToolUse + scriptPensez à faire un chmod +x, un Hook peut restreindre les droits mais jamais les élargir
Diagnostiquer les dysfonctionnementsSuivre la procédure de diagnosticVérifier l'enregistrement avec /hooks, tester avec du JSON simulé, analyser les logs avec --debug

Vous devriez maintenant être en mesure de : expliquer la différence fondamentale entre un Hook et une « requête dans CLAUDE.md » (garantie vs requête) ; identifier à quel moment du cycle de vie de Claude correspondent PreToolUse, PostToolUse, Stop et SessionStart ; écrire un hook avec un matcher dans settings.json en suivant un modèle ; comprendre comment les hooks communiquent avec Claude par stdin, codes de sortie et stdout, en gardant en tête que « seul exit 2 bloque » ; diagnostiquer un hook défectueux à l'aide de /hooks et de --debug. La corvée des 23 saisies manuelles de prettier présentée au début est désormais résoluble définitivement avec une seule ligne de configuration.

Le Hook est un mécanisme avancé de la catégorie « Configuration et optimisation du système » — il vous offre un contrôle déterministe sur le comportement de Claude, plutôt que de devoir simplement « lui faire confiance ».


L'article suivant, 34 « Manuel de référence de la CLI : Commandes et toutes les options », vous guidera à travers l'écosystème des commandes de Claude. Vous avez déjà utilisé plusieurs commandes commençant par claude ainsi que des options comme --debug ou --dangerously-skip-permissions, mais elles ne représentent que la partie émergée de l'iceberg. Le prochain chapitre passera en revue de manière exhaustive l'ensemble des commandes et options de la CLI de claude, constituant un guide de référence à consulter à tout moment. Pensez-y : combien d'options de la commande claude êtes-vous capable de citer de mémoire actuellement ? Après la lecture de ce prochain volet, vous constaterez que vous passiez à côté d'au moins la moitié des fonctionnalités les plus pratiques.


Lectures recommandées