Tu demandes à Claude de toujours lancer Prettier après avoir modifié un fichier. Il le fait… la plupart du temps. Une instruction dans CLAUDE.md, c'est une consigne : le modèle la suit en général, mais rien ne le garantit.
Les hooks règlent ce problème. Ce sont des commandes que Claude Code exécute lui-même, à des moments précis de son cycle de travail, quel que soit le choix du modèle. Formatage, vérifications, notifications, garde-fous : tout ce qui doit arriver à chaque fois a sa place dans un hook.
Les versions de mi-mars (2.1.75 à 2.1.80) ont apporté plusieurs nouveautés et corrections autour des hooks. L'occasion de faire le point.
Un hook, c'est trois choses :
- un événement : le moment où il se déclenche ;
- un matcher, optionnel : le filtre qui dit pour quels outils il s'applique ;
- une commande : ce qui est exécuté.
Claude Code transmet à la commande un JSON sur l'entrée standard, avec le contexte de l'événement : le nom de l'outil, ses paramètres, l'identifiant de session… Ta commande peut s'en servir pour décider quoi faire.
| Événement | Quand |
|---|
PreToolUse | avant l'exécution d'un outil |
PostToolUse | après l'exécution d'un outil |
UserPromptSubmit | quand tu envoies un message |
Notification | quand Claude Code envoie une notification |
Stop | quand Claude termine sa réponse |
SubagentStop | quand un sous-agent termine |
PreCompact | avant la compaction du contexte |
SessionStart / SessionEnd | au début et à la fin d'une session |
Les plus utiles au quotidien sont PreToolUse (pour contrôler) et PostToolUse (pour réagir).
Les hooks se déclarent dans les fichiers de réglages :
~/.claude/settings.json pour tous tes projets ;
.claude/settings.json dans un projet, à partager avec l'équipe via Git ;
.claude/settings.local.json pour tes réglages personnels sur un projet.
La commande /hooks permet aussi de les consulter depuis une session.
Le cas d'usage classique. À chaque fois que Claude modifie ou crée un fichier, on lance le formateur :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
]
}
]
}
}
Le matcher Edit|Write limite le hook aux outils de modification de fichiers. La commande lit le chemin du fichier dans le JSON reçu, puis le formate. Plus besoin de le rappeler à Claude.
Un hook PreToolUse peut empêcher une action. La convention est simple : si la commande se termine avec le code de sortie 2, l'action est bloquée, et le message écrit sur la sortie d'erreur est renvoyé à Claude pour qu'il comprenne pourquoi.
Un script .claude/hooks/garde-fou.sh :
#!/bin/bash
cmd=$(jq -r '.tool_input.command')
if echo "$cmd" | grep -q 'rm -rf /'; then
echo "Commande interdite par le garde-fou du projet" >&2
exit 2
fi
exit 0
Et sa déclaration, avec le matcher Bash :
{
"hooks": {
"PreToolUse": [
{ "matcher": "Bash", "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/garde-fou.sh" } ] }
]
}
}
Pense à rendre le script exécutable (chmod +x). Le motif testé ici est volontairement simpliste : adapte-le à tes besoins. Le code de sortie 0 laisse passer. Un autre code non nul signale une erreur sans bloquer.
Tu lances une tâche longue et tu vas faire autre chose. Un hook Stop peut jouer un son ou envoyer une notification système quand Claude a terminé. Sur macOS, par exemple, une commande osascript ou afplay suffit. Sur Linux, notify-send.
Les versions 2.1.75 à 2.1.80, publiées entre le 13 et le 19 mars, apportent plusieurs changements liés aux hooks.
De nouveaux événements :
PostCompact (2.1.76) se déclenche après la compaction du contexte. On peut par exemple s'en servir pour réinjecter une information importante qui aurait pu être résumée.
Elicitation et ElicitationResult (2.1.76) accompagnent l'arrivée de l'élicitation MCP : un serveur MCP peut désormais demander une saisie structurée en cours de tâche, et ces hooks permettent d'intercepter ou de modifier la réponse avant qu'elle ne soit renvoyée.
StopFailure (2.1.78) se déclenche quand un tour se termine à cause d'une erreur d'API : limite de débit, échec d'authentification… Idéal pour être alerté quand une session longue s'arrête sur une erreur.
Plus de transparence :
- en 2.1.75, quand un hook demande une confirmation, l'invite de permission indique d'où il vient : réglages, plugin ou skill. Utile quand tu installes des plugins tiers ;
- toujours en 2.1.75, les messages de fin des hooks asynchrones sont masqués par défaut (visibles avec
--verbose).
Des corrections importantes :
- 2.1.77 corrige un problème de sécurité : un hook
PreToolUse qui renvoyait « allow » contournait les règles de refus, y compris celles des réglages gérés par l'entreprise. Si tu utilises des règles deny, mets à jour ;
- 2.1.78 corrige une boucle infinie quand une erreur d'API déclenchait des hooks de fin qui renvoyaient des erreurs bloquantes au modèle ;
- 2.1.78 corrige aussi le chargement des skills et des hooks depuis le dossier du worktree avec
--worktree ;
- 2.1.79 corrige les hooks
SessionEnd qui ne se déclenchaient pas en changeant de session avec /resume.
- Garde tes hooks rapides. Ils s'exécutent pendant la session : un hook de 30 secondes après chaque modification ralentit tout.
- Relis les hooks que tu installes. Un hook exécute des commandes avec tes droits, sans passer par les permissions de Claude. Un plugin ou un dépôt cloné peut en apporter : vérifie ce qu'ils font.
- Versionne les hooks d'équipe dans
.claude/settings.json, et garde tes préférences personnelles dans settings.local.json.
- Utilise des matchers précis plutôt que de tout intercepter.
- Un hook ne remplace pas les permissions. Les règles
allow et deny restent la base ; les hooks ajoutent de la logique par-dessus.
- Un hook exécute ta commande à un moment précis, à chaque fois, sans dépendre du bon vouloir du modèle.
PreToolUse contrôle (code de sortie 2 pour bloquer), PostToolUse réagit.
- Mi-mars : nouveaux événements PostCompact, Elicitation, ElicitationResult et StopFailure, source des hooks affichée dans les invites, et une correction de sécurité en 2.1.77 sur les règles de refus.