Analyse complète du mécanisme Claude Code Hooks : cinq types d'événements, contrôle des codes de sortie et quatre configurations réelles pour rendre les actions IA auditables, interceptables et automatisées.
Chaque fois que Claude Code lit un fichier, écrit du code ou exécute une commande, un système d'événements tourne en arrière-plan. Les Hooks sont l'interface pour se connecter à ce système — vous pouvez injecter votre propre logique à n'importe quel moment : lancer des linters automatiquement, enregistrer des opérations, bloquer des actions dangereuses, ou déclencher n'importe quelle commande shell.
Cet article couvre en détail le mécanisme des Hooks, leur configuration et leur utilisation pratique.
Les Hooks sont des commandes shell configurées dans settings.json que Claude Code exécute automatiquement lors d'événements spécifiques.
L'analogie la plus directe : les git hooks. Git peut déclencher des scripts avant et après des opérations comme commit ou push. Les Claude Code Hooks fonctionnent exactement de la même façon — la différence est que les points de déclenchement sont les appels d'outils de l'IA.
Pourquoi est-ce important ?
Plus Claude Code devient capable, plus vous avez besoin d'une couche de contrôle déterministe. Les Hooks fournissent :
- Des garanties d'exécution indépendantes du prompt (Claude peut ignorer des instructions, mais les hooks s'exécutent toujours)
- Des journaux d'opérations auditables
- Des vérifications qualité automatisées
| Type | Déclencheur | Usage typique |
|---|---|---|
PreToolUse |
Avant un appel d'outil | Bloquer des opérations dangereuses, enregistrer l'intention |
PostToolUse |
Après un appel d'outil | Auto-lint, lancer des tests |
PreCompact |
Avant la compaction du contexte | Sauvegarder un snapshot de l'état actuel |
Notification |
Quand Claude envoie une notification | Alertes bureau, messages Slack |
Stop |
Quand Claude termine de répondre | Résumer les logs, déclencher des workflows suivants |
Les plus utilisés sont PreToolUse et PostToolUse, pour intercepter et post-traiter les appels d'outils.
Les Hooks se placent dans ~/.claude/settings.json (global) ou dans .claude/settings.json à la racine du projet (niveau projet) :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npm run lint --silent"
}
]
}
]
}
}
Trois champs essentiels :
matcher : Regex correspondant aux noms d'outils, détermine quels appels déclenchent ce hook. "Write|Edit" se déclenche lors de l'écriture ou de l'édition de fichiers. Laissez vide ou utilisez ".*" pour correspondre à tous les outils.type : Actuellement seulement "command".command : N'importe quelle commande shell.Noms d'outils à connaître pour écrire des matchers :
| Nom | Action |
|---|---|
Write |
Écrire un nouveau fichier |
Edit |
Modifier un fichier |
Bash |
Exécuter une commande shell |
Read |
Lire un fichier |
Glob |
Recherche de fichiers |
Grep |
Recherche de contenu |
TodoWrite |
Mettre à jour la liste de tâches |
Lors de l'exécution, les données sont passées en JSON via stdin :
{
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.rb",
"content": "..."
},
"tool_response": "..."
}
PreToolUse reçoit tool_input (les arguments avant l'appel). PostToolUse reçoit aussi tool_response (la valeur de retour de l'outil).
Exemple de hook avec logique conditionnelle :
#!/bin/bash
input=$(cat)
file=$(echo "$input" | jq -r '.tool_input.file_path')
# Lancer rubocop uniquement sur les fichiers .rb
if [[ "$file" == *.rb ]]; then
rubocop "$file" --autocorrect-all --no-color
fi
Le code de sortie du hook contrôle le comportement suivant de Claude Code :
| Code de sortie | Signification |
|---|---|
0 |
Succès, continuer l'exécution |
2 |
Bloquer : annuler l'appel d'outil en cours, renvoyer la sortie stderr à Claude |
| Autre non-zéro | Enregistrer l'erreur, mais continuer |
Le code de sortie 2 est le plus utile — il permet d'écrire une logique d'interception dans PreToolUse pour empêcher Claude d'effectuer une opération et lui expliquer pourquoi.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" == *.rb ]] && rubocop -A \"$file\" --no-color -q || true'"
}
]
}
]
}
}
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash -c 'cmd=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .command); if echo \"$cmd\" | grep -qE \"rm.*/(migrations|seeds)\"; then echo \"La suppression des répertoires migrations ou seeds est interdite\" >&2; exit 2; fi'"
}
]
}
]
}
}
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|Bash",
"hooks": [
{
"type": "command",
"command": "echo \"$(date '+%Y-%m-%d %H:%M:%S') $CLAUDE_TOOL_NAME: $(echo $CLAUDE_TOOL_INPUT | jq -c .)\" >> ~/.claude/audit.log"
}
]
}
]
}
}
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude a terminé\" with title \"Claude Code\"'"
}
]
}
]
}
}
Les Hooks peuvent être placés à deux endroits :
Global (~/.claude/settings.json) : Règles communes à tous les projets — logs, notifications.
Niveau projet (.claude/settings.json) : Vérifications spécifiques au projet. Les hooks de projet et les hooks globaux fusionnent et s'exécutent tous les deux.
Pour les projets d'équipe, commitez le settings.json du projet dans git pour que tout le monde exécute les mêmes hooks.
Étapes de dépannage quand un hook ne se déclenche pas :
write n'est pas Writeecho "hook triggered" >> /tmp/hook.log pour confirmer le déclenchementLa valeur centrale des Hooks est de connecter le comportement imprévisible de l'IA aux standards d'ingénierie déterministes. Claude peut oublier de lancer les tests, mais un PostToolUse hook ne le fera pas. Claude peut supprimer des fichiers par erreur, mais un intercepteur PreToolUse ne le laissera pas passer.
Commencez par un hook : auto-lint après l'écriture de fichiers. Une fois que ça tourne, ajoutez-en d'autres.