← Tous les articles

Hooks Claude Code : pourquoi chacun de mes 95 hooks existe

From the guide: Claude Code Comprehensive Guide

J’ai construit 95 hooks pour Claude Code. Chacun existe parce que quelque chose a d’abord mal tourné. Le git-safety-guardian existe parce que Claude a fait un force-push sur main. Le recursion-guard existe parce qu’un sous-agent a engendré des enfants à l’infini. Le blog-quality-gate existe parce que j’ai publié un article avec 7 phrases à la voix passive et une note de bas de page orpheline.1

Les hooks Claude Code sont des commandes shell qui s’exécutent à des points précis du cycle de vie (début de session, avant/après l’utilisation d’un outil, soumission de prompt et fin de réponse), offrant des garde-fous déterministes par-dessus le comportement probabiliste du LLM. Les hooks reçoivent du JSON sur stdin et renvoient des décisions (bloquer, autoriser ou modifier) via stdout. Ils appliquent des politiques telles que le blocage des force-pushes sur main, la prévention des spawns récursifs d’agents, l’injection de contexte par session et le contrôle qualité en sortie que le LLM seul ne peut garantir.

TL;DR

Les hooks Claude Code exécutent des commandes shell à des points précis du cycle de vie lors du développement assisté par IA. Les hooks offrent des garanties déterministes (blocage des commandes git dangereuses, injection de contexte, application de la qualité) par-dessus un système probabiliste (le LLM). Après avoir construit 95 hooks à travers mon infrastructure, j’ai constaté que les meilleurs hooks viennent des incidents, pas de la planification. Cet article couvre l’architecture, les histoires d’origine derrière mes hooks les plus critiques et les modèles que j’ai appris au cours de 9 mois de développement de hooks.


L’architecture

Claude Code expose 26 événements de cycle de vie où les hooks peuvent intercepter, modifier ou bloquer le comportement (en date de la v2.1.116, avril 2026).2 Mes hooks ciblent six des plus courants :

Événements de session

Événement Quand il se déclenche Mes hooks
SessionStart Nouvelle session commence session-start.sh : injecte la date, valide le venv, initialise l’état de récursion
SessionEnd La session se termine Nettoyer les fichiers temporaires

Événements d’exécution d’outils

Événement Quand il se déclenche Mes hooks
PreToolUse Avant l’exécution d’un outil git-safety-guardian.sh, recursion-guard.sh, credentials-check.sh
PostToolUse Après la fin de l’outil post-deliberation.sh, log-bash.sh

Événements de réponse

Événement Quand il se déclenche Mes hooks
UserPromptSubmit L’utilisateur envoie un prompt Injecteurs de contexte (date, branche, infos sur le modèle)
Stop Claude termine sa réponse deliberation-pride-check.sh, reviewer-stop-gate.sh

Chaque hook reçoit du JSON sur stdin et communique via stdout :

{"decision": "block", "reason": "Force push to main is prohibited"}

Ou autorise silencieusement en sortant avec le code 0.3


Histoires d’origine : les hooks qui comptent le plus

Hook 1 : git-safety-guardian.sh (PreToolUse:Bash)

L’incident : lors d’une session Claude Code précoce, j’ai demandé à l’agent de « nettoyer l’historique git ». L’agent a exécuté git push --force origin main. Le force-push a écrasé trois jours de commits sur une branche partagée. J’ai récupéré à partir d’une sauvegarde locale, mais les 4 heures de récupération m’ont convaincu que le jugement probabiliste ne devrait jamais contrôler les opérations git destructrices.

Le hook :

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

# Only check git commands
echo "$COMMAND" | grep -qE '\bgit\b' || exit 0

# Block force push to main/master
if echo "$COMMAND" | grep -qiE 'git\s+push\s+.*--force.*\b(main|master)\b'; then
    cat << EOF
{"decision": "block", "reason": "Force push to main/master blocked by safety hook"}
EOF
fi

La leçon : le hook ne cherche pas à comprendre l’intention. Il fait de la correspondance de motifs sur la chaîne de commande. Simple, déterministe, impossible à contourner par un prompting astucieux. L’agent peut toujours faire un force-push sur des branches de fonctionnalité (parfois légitime), mais main/master sont protégés de façon permanente.4

Interceptions à vie : 8 tentatives de force-push interceptées en 9 mois.

Hook 2 : recursion-guard.sh (PreToolUse:Task)

L’incident : en construisant le système de délibération, j’ai lancé une session qui a engendré 3 sous-agents d’exploration. Chaque sous-agent, n’ayant pas de limite de spawn, a engendré ses propres sous-agents. La récursion a consommé des tokens API à 10 fois le rythme normal. J’ai tué la session manuellement après avoir remarqué l’emballement du burn de tokens.

Le hook :

#!/bin/bash
CONFIG_FILE="${HOME}/.claude/configs/recursion-limits.json"
STATE_FILE="${HOME}/.claude/state/recursion-depth.json"

MAX_DEPTH=2
MAX_CHILDREN=5
DELIB_SPAWN_BUDGET=2
DELIB_MAX_AGENTS=12

# Validate integers safely (((VAR++)) crashes with set -e when VAR=0)
is_positive_int() {
    [[ "$1" =~ ^[0-9]+$ ]] && [[ "$1" -gt 0 ]]
}

La décision de conception clé : les agents héritent d’un budget de spawn de leur parent plutôt que d’incrémenter la profondeur. Un agent racine avec budget=12 peut répartir ce budget sur n’importe quelle forme d’arbre. Les limites basées sur la profondeur sont trop rigides (elles empêchent les chaînes profondes mais étroites qui sont parfaitement sûres).5

Blocages à vie : 23 tentatives de spawn emballées.

Hook 3 : blog-quality-gate.sh (Stop)

L’incident : j’ai publié un article de blog avec 7 phrases à la voix passive, une note de bas de page référencée dans le texte mais absente de la section des références, et « a été implémenté par l’équipe » comme phrase d’ouverture. L’article paraissait soigné dans mon éditeur, mais échouait à des contrôles de qualité basiques que tout relecteur humain attraperait.

Le hook : exécute mon linter de blog à 12 modules sur tout fichier de contenu de blog modifié. Vérifie la voix passive, les notes de bas de page orphelines, les meta-descriptions manquantes, les blocs de code non balisés et l’intégrité des citations. Chaque constat est spécifique : « Ligne 47 : voix passive détectée dans “a été implémenté par l’équipe”. Suggestion : “l’équipe a implémenté”. »

Le parallèle avec le retour humain : le hook critique le travail, pas l’opérateur. Il dit « la ligne 47 contient de la voix passive », pas « vous écrivez mal ». Le même principe qui rend le retour humain constructif rend le retour automatisé utile.


Le modèle derrière 95 hooks

L’architecture pilotée par configuration

Mes hooks ont évolué de valeurs codées en dur vers un comportement piloté par configuration :

~/.claude/configs/
├── recursion-limits.json     # Depth, spawn budgets, timeouts
├── deliberation-config.json  # Consensus thresholds per task type
├── consensus-profiles.json   # security=85%, docs=50%
├── circuit-breaker.json      # Failure mode configurations
└── file-scope-rules.json     # Path-scoped hook application

Déplacer les seuils vers des configurations JSON m’a permis d’ajuster le comportement sans éditer les scripts bash. Lorsque j’ai eu besoin d’un consensus lié à la sécurité à 85 % mais à 50 % pour la documentation, le changement de configuration a pris 30 secondes. Un changement de code aurait nécessité édition, test et redéploiement.6

Le modèle de superposition du cycle de vie

Mes 95 hooks forment un filet de sécurité à quatre couches :

Couche 1 : prévention (PreToolUse) : arrêter les mauvaises choses avant qu’elles n’arrivent. git-safety-guardian, credentials-check, recursion-guard.

Couche 2 : contexte (UserPromptSubmit, SessionStart) : injecter les informations dont l’agent a besoin. Date, branche, contexte du projet, entrées mémoire, principes philosophiques.

Couche 3 : validation (PostToolUse) : vérifier que les actions réalisées respectent les standards. Vérification de consensus post-délibération, journalisation des sorties.

Couche 4 : qualité (Stop) : contrôler la sortie finale. Pride check, quality gate, reviewer stop gate. Cette couche met en œuvre la surveillance métacognitive où l’agent évalue la qualité de son propre raisonnement, pas seulement sa sortie.

Chaque couche est indépendante. Si un hook PreToolUse échoue silencieusement, le hook Stop attrape toujours les problèmes de qualité. Défense en profondeur, appliquée au comportement de l’agent IA.


Configuration

Les hooks vivent dans .claude/settings.json :

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "~/.claude/hooks/git-safety-guardian.sh",
        "timeout": 5000
      }
    ],
    "PreToolUse:Task": [
      {
        "command": "~/.claude/hooks/recursion-guard.sh"
      }
    ]
  }
}

Le champ matcher filtre les outils qui déclenchent le hook. PreToolUse:Task est un raccourci pour un matcher qui ne se déclenche que sur les invocations de l’outil Task. Les hooks asynchrones (async: true) s’exécutent en arrière-plan sans bloquer.7

Hiérarchie de portée

  1. Niveau utilisateur (~/.claude/settings.json) : s’applique à tous les projets. Mes 95 hooks vivent ici.
  2. Niveau projet (.claude/settings.json) : ajoute des hooks spécifiques au projet.
  3. Frontmatter Skill/Subagent : limité au cycle de vie d’un composant spécifique.8

Ce que je ferais différemment

Commencez par 3 hooks, pas 25. Mon premier mois a produit 25 hooks, dont beaucoup ajoutaient du contexte que l’agent avait déjà. Le surcoût du chargement de 25 hooks à chaque appel d’outil était mesurable. J’ai fini par élaguer pour ne garder que les hooks qui produisaient une vraie valeur (prévenant de vrais incidents, attrapant de vrais problèmes de qualité).

Pilotage par configuration dès le premier jour. J’ai passé deux semaines à refactoriser les seuils codés en dur vers des configurations JSON. Cette refactorisation aurait été gratuite si j’avais commencé avec des configurations.

Infrastructure de test tôt. Les 20 premiers hooks n’avaient pas de tests. Lorsque j’ai ajouté le harnais de test (48 tests d’intégration bash), j’ai trouvé 3 hooks qui échouaient silencieusement sur des cas limites. Les tests auraient dû être livrés avec le hook n°1.


Points clés à retenir

Pour les développeurs qui débutent avec les hooks : - Commencez par trois hooks : sécurité git (PreToolUse:Bash), injection de contexte (UserPromptSubmit) et contrôle qualité (Stop) ; n’en ajoutez d’autres que lorsque vous avez des incidents qui les justifient - Utilisez le cadre de timing des décisions : l’architecture des hooks est irréversible (95 hooks en dépendent), donc investissez dans le modèle de cycle de vie avant d’écrire des hooks

Pour les équipes qui standardisent les hooks : - Standardisez les hooks au niveau utilisateur pour que chaque membre de l’équipe obtienne les mêmes garde-fous de sécurité - Suivez les métriques des hooks (opérations bloquées, incidents interceptés) pour justifier le coût de maintenance - Passez en revue les journaux de hooks chaque mois pour identifier de nouveaux motifs qui méritent d’être automatisés


FAQ

Que sont les hooks Claude Code ?

Les hooks sont des scripts shell qui s’exécutent à des points précis du cycle de vie lors des sessions Claude Code. Ils se déclenchent de façon déterministe à des moments précis : avant l’exécution d’un outil (PreToolUse), après sa fin (PostToolUse), lorsque vous envoyez un prompt (UserPromptSubmit), lorsqu’une session commence (SessionStart) et lorsque Claude termine sa réponse (Stop). Les hooks reçoivent du JSON sur stdin avec le contexte complet (nom de l’outil, entrée, ID de session) et peuvent bloquer des opérations, injecter du contexte ou imposer des contrôles qualité. Ils offrent des garanties déterministes par-dessus un LLM probabiliste.

Combien de hooks Claude Code peut-il exécuter et y a-t-il un coût en performance ?

Il n’y a pas de limite stricte sur le nombre de hooks. J’exécute 95 hooks à travers 6 des 26 événements de cycle de vie disponibles (en date de la v2.1.116, avril 2026), avec environ 200 ms de surcoût total par événement. La limite pratique est la latence : chaque hook ajoute du temps d’exécution avant ou après les appels d’outils. L’optimisation clé consiste à utiliser des dispatchers (un par événement, exécutant les hooks séquentiellement à partir de stdin en cache) plutôt que des hooks indépendants qui lisent chacun stdin séparément. Les écritures concurrentes depuis des hooks indépendants provoquaient une corruption du JSON dans ma configuration initiale ; les dispatchers ont entièrement éliminé ce mode de défaillance.

Sur quels événements les hooks Claude Code se déclenchent-ils ?

Claude Code expose 26 événements de cycle de vie pour les hooks en date de la v2.1.116 (avril 2026). Les six plus courants que mes hooks ciblent sont : SessionStart (nouvelle session commence), SessionEnd (la session se termine), PreToolUse (avant l’exécution d’un outil), PostToolUse (après la fin de l’outil), UserPromptSubmit (l’utilisateur envoie un prompt) et Stop (Claude termine sa réponse). D’autres incluent SubagentStart, PermissionRequest, PermissionDenied, TaskCreated, CwdChanged, FileChanged, PreCompact et davantage. PreToolUse et PostToolUse peuvent être affinés avec des matchers comme PreToolUse:Bash ou PreToolUse:Task pour ne se déclencher que sur des types d’outils spécifiques. Chaque événement reçoit du JSON sur stdin avec le contexte pertinent.

Les hooks Claude Code peuvent-ils bloquer des appels d’outils ?

Oui. Un hook qui émet {"decision": "block", "reason": "explanation"} sur stdout empêche l’appel d’outil de s’exécuter. C’est le mécanisme central pour les hooks de sécurité : mon git-safety-guardian bloque les force-pushes sur main, mon credentials-check bloque les lectures des fichiers .env, et mon recursion-guard bloque les spawns excessifs d’agents. Le blocage est déterministe et ne peut pas être contourné par le prompting. Les hooks qui sortent silencieusement avec le code 0 autorisent l’opération à se poursuivre.

Quelle est la différence entre les hooks PreToolUse et PostToolUse ?

PreToolUse se déclenche avant l’exécution d’un outil et peut bloquer entièrement l’opération. Utilisez-le pour les barrières de sécurité : bloquer des commandes dangereuses, vérifier les identifiants, appliquer des budgets de spawn. PostToolUse se déclenche après la fin de l’outil et peut fournir un retour ou déclencher des actions de suivi. Utilisez-le pour la validation : vérifier la qualité de la sortie, journaliser l’activité, vérifier le consensus. Ensemble, ils forment les première et troisième couches d’un filet de sécurité à quatre couches : prévention (PreToolUse), injection de contexte (UserPromptSubmit), validation (PostToolUse) et contrôle qualité (Stop).

Références


  1. Infrastructure de hooks de l’auteur. 95 hooks à travers 6 des 26 événements de cycle de vie disponibles (v2.1.116, avril 2026), développés sur 9 mois (2025-2026). 

  2. Anthropic, « Claude Code Hooks Reference », 2026. 26 types d’événements de cycle de vie en date de la v2.1.116 (avril 2026). 

  3. Anthropic, « Claude Code Documentation », 2025. Format JSON d’entrée/sortie des hooks. 

  4. git-safety-guardian.sh de l’auteur. 8 tentatives de force-push interceptées suivies dans ~/.claude/state/

  5. recursion-guard.sh de l’auteur. Modèle d’héritage de budget documenté dans ~/.claude/configs/recursion-limits.json

  6. Architecture pilotée par configuration de l’auteur. 14 fichiers de configuration JSON encodant tous les seuils et règles des hooks. 

  7. Anthropic, « Claude Code Documentation », 2025. Configuration des hooks et exécution asynchrone. 

  8. Anthropic, « Claude Code Documentation », 2025. Hiérarchie de portée des hooks. 

Articles connexes

Créer des Skills personnalisés pour Claude Code : un tutoriel complet

Construire un skill de revue de code de zero. Structure de repertoire, champs frontmatter, matching base sur LLM, budget…

13 min de lecture

Gestion de la fenêtre de contexte : ce que 50 sessions m'ont appris sur le développement IA

J'ai mesuré la consommation de tokens sur 50 sessions Claude Code. L'épuisement du contexte dégrade la qualité des résul…

8 min de lecture

Tutoriel Hooks Claude Code : 5 hooks de production créés de zéro

Créez 5 hooks Claude Code pratiques de zéro : auto-formatage, portes de sécurité, exécution de tests, alertes de notific…

9 min de lecture