Hooks Claude Code : guide pratique avec exemples

Comment fonctionnent les hooks Claude Code : événements, settings.json, matchers, codes de sortie et JSON, avec des hooks prêts à copier pour formater et bloquer.

Solviera Teknoloji 12 min de lecture

Les hooks Claude Code sont des commandes que Claude Code exécute de lui-même à des moments fixes d’une session : avant un appel d’outil, après une modification de fichier, à l’envoi d’un prompt, quand Claude s’arrête ou a besoin de votre attention. Vous les définissez sous la clé hooks de settings.json. Un hook peut ajouter du contexte, formater un fichier, ou bloquer une action en sortant avec le code 2 ou en renvoyant une décision JSON. Contrairement aux instructions de CLAUDE.md, un hook s’exécute toujours, car c’est l’infrastructure qui le lance, pas le modèle.

Ce guide couvre les événements qui comptent, le format de configuration, les matchers, les codes de sortie et la sortie JSON, trois hooks à copier dès aujourd’hui, et les notes de sécurité à lire avant d’en ajouter. Les faits viennent de la référence des hooks et du guide des hooks officiels. Si vous voulez seulement la définition courte, voir l’entrée du glossaire sur les hooks Claude Code.

Pourquoi utiliser des hooks plutôt que des instructions

Vous pouvez écrire « lance toujours Prettier après une modification » dans CLAUDE.md, et Claude le fera en général. En général est le problème. Les instructions sont des conseils que le modèle pèse face à tout le reste de son contexte. Les hooks sont du code qui s’exécute à chaque déclenchement de l’événement.

Les hooks sont donc l’outil adapté à trois types de règles :

  • Ce qui doit toujours arriver, comme le formatage, le lint ou la journalisation.
  • Ce qui ne doit jamais arriver, comme modifier .env ou lancer rm -rf dans le mauvais dossier.
  • Ce que vous voulez savoir, comme Claude qui attend une réponse à une demande de permission alors que vous êtes dans une autre fenêtre.

Gardez les conseils de style et la connaissance du projet dans CLAUDE.md et mettez les règles strictes dans des hooks.

Les événements de hook que vous utiliserez vraiment

La référence liste plus de trente événements, et la liste grandit à chaque version. La plupart des configurations réelles en utilisent une poignée :

ÉvénementQuand il se déclenchePeut-il bloquer ?
PreToolUseAvant l’exécution d’un appel d’outilOui, bloque l’appel
PostToolUseAprès la réussite d’un appel d’outilNon, l’outil a déjà tourné ; stderr va à Claude
UserPromptSubmitÀ l’envoi d’un promptOui, le prompt n’atteint jamais Claude
NotificationQuand Claude Code envoie une notification, comme une demande de permission ou une attente d’inactivitéNon
StopQuand Claude termine sa réponseOui, Claude continue de travailler
SubagentStart / SubagentStopQuand un subagent démarre ou se termineSeulement SubagentStop
SessionStartAu démarrage, à la reprise, à /clear ou à la compactionNon, mais stdout devient du contexte
PreCompactAvant la compaction du contexteOui, bloque la compaction
PermissionRequestQuand une boîte de dialogue de permission va s’afficherVia JSON uniquement, pas par la sortie 2
SessionEndÀ la fin de la sessionNon

PreToolUse et PostToolUse couvrent la plupart des besoins. Notification et Stop servent à « prévenez-moi quand c’est fini ou bloqué ».

Comment configurer les hooks dans settings.json

Les hooks vivent dans les mêmes fichiers de réglages que les permissions :

FichierPortéePartagé via git ?
~/.claude/settings.jsonTous vos projetsNon
.claude/settings.jsonUn projetOui
.claude/settings.local.jsonUn projet, vous seulNon (ignoré par git)
Réglages de politique géréeToute l’organisationDéfinis par les administrateurs

Les plugins peuvent fournir des hooks dans hooks/hooks.json, et les skills et subagents peuvent définir des hooks dans leur frontmatter.

La structure a trois niveaux : l’événement, un groupe de matchers et une liste de gestionnaires.

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

Le type d’un gestionnaire peut être command (une commande shell), http (un POST vers une URL), mcp_tool (un outil d’un serveur MCP que vous avez connecté), prompt (une vérification oui/non rapide par un modèle) ou agent (une vérification expérimentale par un subagent). Le délai par défaut est de 600 secondes pour les gestionnaires command, HTTP et MCP tool, de 30 secondes pour les hooks prompt et de 60 pour les hooks agent.

Chaque hook reçoit du JSON sur stdin. Les champs courants sont session_id, transcript_path, cwd, permission_mode et hook_event_name. Les événements d’outil ajoutent tool_name, tool_input et tool_use_id. Votre script lit ce JSON, en général avec jq, et décide quoi faire. La variable d’environnement CLAUDE_PROJECT_DIR pointe vers la racine du projet, pratique pour référencer des scripts stockés dans le dépôt.

Tapez /hooks dans Claude Code pour parcourir ce qui est chargé et le fichier d’où vient chaque hook. Le navigateur est en lecture seule : on modifie les hooks en éditant le JSON.

Matchers : quels appels d’outil un hook voit

Le matcher décide quels appels déclenchent un hook. Pour les événements d’outil, il porte sur le nom de l’outil :

MatcherSignification
"*", "" ou pas de matcherTous les appels
"Bash"Exactement l’outil Bash
"Edit|Write"Edit ou Write (une liste)
"mcp__memory__.*"Tous les outils du serveur MCP memory
"mcp__.*__write.*"Tout outil MCP dont le nom commence par write

La règle est simple. Si le matcher ne contient que des lettres, des chiffres, _, -, des espaces, des virgules ou |, c’est un nom exact ou une liste de noms. Tout autre caractère en fait une expression régulière JavaScript. Les outils MCP s’appellent mcp__<server>__<tool>.

Certains événements ignorent le matcher, dont UserPromptSubmit et Stop, faute de quoi comparer. D’autres comparent autre chose qu’un nom d’outil. SessionStart compare la manière dont la session a démarré (startup, resume, clear, compact), et Notification le type de notification, comme permission_prompt ou idle_prompt.

Les événements d’outil acceptent aussi un champ if avec la syntaxe des règles de permission, si bien qu’un hook Bash peut ne s’exécuter que pour, par exemple, "Bash(git *)". La documentation le décrit comme un filtre au mieux : gardez la vraie vérification dans votre script.

Codes de sortie et sortie JSON

Un hook command répond à Claude Code de deux façons : le code de sortie, et du JSON facultatif sur stdout.

Code de sortieCe qui se passe
0Succès. stdout est analysé comme JSON s’il s’agit d’un seul objet JSON. Pour UserPromptSubmit et SessionStart, le texte brut sur stdout est ajouté au contexte de Claude.
2Erreur bloquante. stderr est la raison. Sur PreToolUse l’appel est annulé, sur UserPromptSubmit le prompt est rejeté, sur Stop Claude continue.
Tout autre code, y compris 1Erreur non bloquante. Claude Code la note et poursuit.

Le piège est le code de sortie 1. Beaucoup de scripts échouent avec 1 par défaut, et cela ne bloque rien. Si vous voulez dire « stop », sortez avec 2.

Pour un contrôle plus fin, sortez avec 0 et affichez du JSON. Un hook PreToolUse peut autoriser, refuser ou demander :

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Use rg instead of grep for better performance"
  }
}

permissionDecision accepte allow, deny, ask ou defer. Un hook peut aussi réécrire l’appel avec updatedInput, ou transmettre du texte supplémentaire à Claude avec additionalContext. Les champs valables pour tout événement incluent continue: false (arrêter Claude complètement, avec un stopReason) et systemMessage (un avertissement qui vous est montré).

Quand plusieurs hooks correspondent, ils s’exécutent en parallèle et la réponse la plus restrictive l’emporte : deny bat defer, defer bat ask, ask bat allow. Un allow d’un hook ne passe pas outre une règle deny de vos permissions.

Exemple 1 : formater les fichiers après chaque modification

C’est le hook par lequel la plupart des gens commencent. Il lance Prettier sur tout fichier que Claude écrit ou modifie :

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

Remplacez-le par ruff format, gofmt -w ou rustfmt pour d’autres langages. Comme le formateur s’exécute après la modification, Claude voit le fichier formaté à sa prochaine lecture, et vous ne voyez plus de diffs de pur style en revue.

Exemple 2 : bloquer les commandes dangereuses et les fichiers protégés

Un hook PreToolUse est l’endroit pour les limites strictes. Ce script, adapté du guide officiel, bloque les modifications de fichiers sensibles. Enregistrez-le sous .claude/hooks/protect-files.sh :

#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")

for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
    exit 2
  fi
done

exit 0

Rendez-le exécutable avec chmod +x .claude/hooks/protect-files.sh, puis enregistrez-le :

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}

Le même schéma marche pour les commandes shell. Faites correspondre Bash, lisez .tool_input.command, et sortez avec 2 quand elle contient ce que vous ne voulez jamais, comme rm -rf /, git push --force ou DROP TABLE. Gardez en tête qu’une vérification par chaîne se contourne facilement : voyez-la comme une ceinture de sécurité, pas comme une serrure.

Exemple 3 : recevoir une notification de bureau

Les tâches longues s’arrêtent pour vous attendre plus souvent qu’on ne le voudrait. Un hook Notification vous prévient tout de suite. Sur macOS :

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Sous Linux, utilisez plutôt notify-send 'Claude Code' 'Claude Code needs your attention'. Mettez le matcher à permission_prompt si seules les demandes de permission vous intéressent, ou ajoutez un hook Stop avec la même commande pour savoir quand Claude a fini.

D’autres schémas utiles

  • Réinjecter du contexte après la compaction. Un hook SessionStart avec le matcher compact peut faire un echo d’un court rappel de vos règles. Sa sortie stdout est ajoutée au nouveau contexte.
  • Auditer les changements de configuration. Un hook ConfigChange peut ajouter chaque changement de réglages à un fichier journal.
  • Contrôle qualité sur Stop. Un hook Stop peut lancer vos tests et sortir avec 2 en renvoyant les échecs, pour que Claude continue de corriger. Vérifiez le champ stop_hook_active de l’entrée pour éviter une boucle infinie. Claude Code passe aussi outre un hook Stop après plusieurs blocages d’affilée.
  • Approuver automatiquement un prompt sûr. Un hook PermissionRequest peut répondre à une boîte de dialogue précise avec {"behavior": "allow"} dans son objet de décision. Gardez le matcher étroit.

Notes de sécurité avant d’ajouter des hooks

Les hooks s’exécutent comme des commandes shell avec les droits de votre utilisateur, sans demander. C’est tout l’intérêt, et aussi le risque.

  • Lisez les hooks avant de faire confiance à un dépôt. Le .claude/settings.json d’un projet peut embarquer des hooks. Relisez-les comme vous relisez un script postinstall.
  • Mettez vos variables entre guillemets. L’entrée d’un hook vient du modèle, et le modèle lit des fichiers et des pages web qui peuvent contenir de l’injection de prompt. Utilisez "$VAR", n’évaluez jamais l’entrée avec eval, et préférez jq à un analyseur maison.
  • Utilisez des chemins absolus ou relatifs au projet avec $CLAUDE_PROJECT_DIR, pour qu’un hook ne dépende pas du dossier courant.
  • Gardez les hooks rapides. Un hook PreToolUse lent ralentit chaque appel d’outil. Définissez un timeout.
  • Les hooks ne sont pas un bac à sable. Un hook deny bloque les appels même sous --dangerously-skip-permissions, ce qui est utile, mais un agent déterminé ou confus peut atteindre le même résultat autrement. Combinez hooks, règles deny et isolation, comme expliqué dans la sécurité des agents de code IA et ignorer les permissions en sécurité.
  • Connaissez les interrupteurs. "disableAllHooks": true désactive les hooks, et les administrateurs peuvent définir allowManagedHooksOnly dans les réglages gérés pour bloquer les hooks utilisateur et projet.

Quand un hook se comporte mal, lancez Claude Code avec claude --debug, ou écrivez le journal dans un fichier avec --debug-file /tmp/claude.log, pour voir le matcher, le code de sortie et la sortie de chaque hook.

Comment AgentVera utilise les hooks

AgentVera est une application de bureau qui exécute Claude Code, Codex, Gemini CLI et d’autres CLI de code côte à côte. Les hooks sont une grande part de son fonctionnement avec Claude Code.

  • Vos hooks restent les vôtres. AgentVera passe ses propres hooks à chaque processus Claude Code avec l’option --settings. Claude Code les fusionne avec les hooks de vos fichiers de réglages, et votre settings.json n’est pas modifié.
  • L’état des agents vient des hooks. L’état que chaque agent affiche dans l’application est lu à partir des événements de hook de la CLI elle-même, pas deviné d’après le texte du terminal.
  • Les smart tools sont des hooks. La fonction smart tools ajoute quatre hooks aux agents Claude Code locaux : elle bloque les lectures répétées d’un même fichier, ne lance que les tests concernés par une modification, vérifie les erreurs juste après une modification et partage les résultats entre agents. Ils sont activés par défaut et vous pouvez les désactiver dans Settings → “Token saving”.
  • Pas besoin de script de notification. Notifications et approbations réunit dans une seule file tous les agents en attente d’approbation, envoie des notifications de bureau quand l’application est en arrière-plan, et peut vous alerter sur votre téléphone via Telegram.

Qwen Code reçoit aussi les hooks d’AgentVera, car son système de hooks suit les événements et le format JSON de Claude Code.

Pour conclure

Commencez par un formateur PostToolUse et une garde PreToolUse, vérifiez-les avec /hooks et --debug, et n’en ajoutez que lorsqu’une règle est sans cesse enfreinte. Sortez avec 2 pour bloquer, affichez du JSON quand il vous faut plus de contrôle, et traitez chaque hook comme du code qui s’exécute avec vos permissions.

Pour aller plus loin :

Pour essayer AgentVera, commencez par la page d’accueil.

Questions

Que sont les hooks Claude Code ?

Les hooks sont des commandes shell, des appels HTTP, des outils MCP ou des prompts que Claude Code exécute de lui-même à des moments précis d’une session : avant un appel d’outil, après une modification de fichier, ou quand Claude a besoin de votre attention. Vous les définissez dans settings.json.

Où placer les hooks Claude Code ?

Sous la clé hooks d’un fichier de réglages : ~/.claude/settings.json pour tous vos projets, .claude/settings.json pour un projet partagé via git, ou .claude/settings.local.json pour un projet uniquement sur votre machine. Les plugins, skills et subagents peuvent aussi définir des hooks.

Comment un hook bloque-t-il un appel d’outil ?

Un hook PreToolUse sort avec le code 2 en écrivant la raison sur stderr, ou sort avec 0 et affiche un JSON avec permissionDecision à deny. Claude Code annule l’appel et montre la raison à Claude. Le code de sortie 1 ne bloque pas.

Les hooks s’exécutent-ils encore avec --dangerously-skip-permissions ?

Oui. Un hook qui renvoie deny bloque l’appel d’outil même en mode bypassPermissions. Un hook PreToolUse devient ainsi une dernière garde utile pour les commandes que vous ne voulez jamais, sans être pour autant un bac à sable.

Comment déboguer un hook Claude Code qui ne se déclenche pas ?

Ouvrez /hooks pour voir quels hooks sont chargés et d’où ils viennent, vérifiez que le matcher correspond au nom exact de l’outil, et lancez Claude Code avec --debug ou --debug-file pour voir chaque hook s’exécuter, avec son code de sortie et sa sortie.

Réunissez vos agents sur un seul bureau.

Téléchargez AgentVera gratuitement ; vos CLI installées sont prêtes à l’emploi.

Autres articles