
Claude Code Hooks : le guide complet (2026)
Un skill peut être ignoré. Ce n'est pas un défaut des skills, c'est tout le design : Claude lit la description, décide si la tâche en cours correspond, et ne charge le corps que s'il le pense. La plupart du temps, ce jugement est correct. Parfois non, et la tâche où ça compte le plus, la revue de code juste avant un merge, l'entrée de log qui doit exister quoi qu'il arrive, est exactement la tâche où « probablement » ne suffit pas.
Les hooks sont l'autre moitié de Claude Code. Un hook est une commande shell que le harnais exécute quand un événement spécifique se déclenche, qu'une skill y ait pensé ou non. Aucun jugement de modèle ne s'interpose entre l'événement et la commande. Elle s'exécute, à chaque fois, dans l'ordre, et son code de sortie peut même arrêter Claude net. Si vous avez déjà voulu dire « formate toujours ce fichier après une édition » ou « ne laisse jamais Claude toucher ce répertoire », un hook est l'outil fait pour cette phrase.
Ce guide couvre ce que sont les hooks, le schéma settings.json derrière eux, six recettes que vous pouvez coller aujourd'hui, comment hooks et skills fonctionnent ensemble, et les modes d'échec qui bouffent un après-midi si vous ne savez pas quoi chercher.
Ce qu'est réellement un hook
Claude Code déclenche des événements nommés pendant une session : avant qu'un outil s'exécute, après qu'un outil s'est exécuté, quand Claude termine sa réponse, quand une notification s'afficherait. Un hook lie une commande shell à l'un de ces événements, optionnellement filtrée sur des outils spécifiques. Le harnais exécute votre commande, lui passe le contexte en JSON sur stdin, puis lit le code de sortie pour décider de la suite.
Les événements que vous utiliserez le plus :
- PreToolUse — se déclenche avant qu'un appel d'outil s'exécute. Un hook ici peut bloquer l'appel complètement.
- PostToolUse — se déclenche après qu'un appel d'outil est terminé. Bon pour le formatage, le test, ou la journalisation de ce qui vient de se passer.
- Stop — se déclenche quand Claude termine son tour et s'apprête à vous rendre la main.
- Notification — se déclenche quand Claude Code afficherait une notification système (demandes de permission, invites d'inactivité).
- UserPromptSubmit — se déclenche quand vous soumettez un message, avant que Claude ne le voie.
C'est le mécanisme. La raison pour laquelle il compte, c'est la garantie qu'il donne, une garantie qu'une skill ne peut structurellement pas offrir.
Le modèle mental : déterministe vs discrétionnaire
C'est l'idée à retenir si vous ne retenez rien d'autre de ce guide.
Une skill est discrétionnaire. Claude lit sa description au début d'une session, et décide plus tard, en fonction de votre demande, s'il faut la charger et la suivre. Les bonnes skills se déclenchent de façon fiable, mais « fiable » reste une probabilité, pas une garantie. Claude peut mal lire un prompt ambigu, ou deux skills peuvent avoir des descriptions qui se recoupent et brouillent la correspondance, un mode d'échec que nous couvrons plus en détail dans notre guide sur pourquoi les skills ne se déclenchent pas.
Un hook est déterministe. Il ne demande pas à Claude s'il faut s'exécuter. Il ne lit pas de description et ne juge pas la pertinence. Le harnais voit l'événement, et la commande s'exécute, point final. Si l'événement est PostToolUse sur l'outil Edit, votre formateur s'exécute après chaque édition, y compris celle que Claude a faite en pensant à tout autre chose.
Cette différence détermine directement à quoi se référer :
| Skill | Hook | |
|---|---|---|
| S'exécute quand | Claude juge que c'est pertinent | À chaque déclenchement de l'événement |
| Peut être sauté | Oui, par une mauvaise correspondance ou un contexte chargé | Non |
| Idéal pour | Jugement, structure, « comment bien faire X » | Application forcée, « X doit toujours se produire » |
| Mode d'échec | Non-déclenchement silencieux | Mauvais code de sortie silencieux, ou blocage de tout |
Si la phrase que vous voulez imposer commence par « Claude doit toujours... » ou « Claude ne doit jamais... », vous voulez un hook. Si elle commence par « quand Claude fait X, il devrait l'aborder comme... » vous voulez une skill. Formater le code après chaque édition, c'est un hook ; écrire du Python idiomatique, c'est une skill. Bloquer les commits sur main, c'est un hook ; structurer un bon message de commit, c'est une skill.
Anatomie d'un hook dans settings.json
Les hooks vivent sous la clé hooks dans .claude/settings.json (niveau projet) ou ~/.claude/settings.json (niveau utilisateur), un fichier différent de CLAUDE.md et qu'il vaut mieux ne pas confondre : CLAUDE.md est de la prose que Claude lit, settings.json est de la config que le harnais exécute. Si vous n'avez encore configuré ni l'un ni l'autre, notre guide CLAUDE.md et notre parcours de configuration complet couvrent le reste de la pile dans laquelle ce fichier vit. Voici un exemple de hooks minimal mais complet, annoté :
{
"hooks": {
// Le nom de l'événement — PreToolUse, PostToolUse, Stop, Notification, etc.
"PostToolUse": [
{
// matcher filtre quels appels d'outils déclenchent ce hook.
// Omettez-le (ou utilisez "*") pour matcher chaque outil.
"matcher": "Edit|Write",
"hooks": [
{
// "command" est actuellement le seul type de hook.
"type": "command",
// La commande shell à exécuter. Reçoit le JSON de l'événement sur stdin.
"command": "npx prettier --write \"$(echo $CLAUDE_TOOL_INPUT | jq -r .file_path)\"",
// Optionnel : tuer la commande si elle se bloque.
"timeout": 15
}
]
}
]
}
}
Quelques points qui piègent les gens :
Le champ matcher opère sur le nom de l'outil, pas sur les chemins de fichiers ou le contenu. "Edit|Write" matche les outils Edit et Write ; "Bash" matche les appels shell. Si vous devez filtrer par chemin de fichier ou contenu de commande, faites-le à l'intérieur de votre script en lisant le payload JSON, pas dans le matcher.
Chaque clé d'événement contient un tableau de blocs matcher, et chaque bloc matcher contient un tableau de commandes de hook, donc vous pouvez attacher plusieurs commandes à un matcher, ou une commande à plusieurs matchers, sans dupliquer la config.
La commande reçoit le payload de l'événement en JSON sur stdin : nom de l'outil, entrée de l'outil, et pour PostToolUse, le résultat de l'outil. Un hook agissant sur le fichier spécifique en cours d'édition lit ce JSON plutôt que de supposer que le répertoire de travail du shell raconte toute l'histoire.
Les codes de sortie portent du sens. Sortie 0 veut dire « c'est bon, continue ». Une sortie non nulle sur un hook PreToolUse bloque l'appel d'outil et renvoie stderr à Claude comme raison. Une sortie non nulle sur PostToolUse est simplement journalisée ; l'outil s'est déjà exécuté, il n'y a donc plus rien à bloquer.
Six recettes à utiliser aujourd'hui
Celles-ci sont délibérément étroites. Copiez le bloc, ajustez la commande, et confirmez qu'elle fait ce que vous attendez sur un fichier jetable avant de lui faire confiance sur du vrai travail.
1. Formater automatiquement après chaque édition
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "cd \"$CLAUDE_PROJECT_DIR\" && npx prettier --write . --ignore-unknown"
}
]
}
]
}
}
Exécute Prettier après chaque édition ou écriture. Pour les gros dépôts, remplacez le . général par un chemin dérivé de l'entrée JSON du hook pour ne formater que le fichier touché.
2. Bloquer les éditions sur des chemins protégés
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/guard_paths.py"
}
]
}
]
}
}
guard_paths.py lit le chemin du fichier depuis le JSON sur stdin, le vérifie contre une liste noire (migrations/, .env, infra/prod/), et sort avec le code 1 et un message sur stderr s'il correspond. C'est ce qui se rapproche le plus d'une vraie frontière de permission dure dans Claude Code.
3. Exécuter les tests après des changements de code source
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "cd \"$CLAUDE_PROJECT_DIR\" && npm test -- --onlyChanged --silent"
}
]
}
]
}
}
Donne à Claude un signal immédiat quand une édition casse un test, au lieu d'attendre que vous le remarquiez en revue. Gardez la commande de test étroite (--onlyChanged, un sous-ensemble rapide) ou cela devient la recette six de la section « quand ne pas » plus bas.
4. Notification bureau quand Claude termine
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude finished\" with title \"Claude Code\"'"
}
]
}
]
}
}
Spécifique à macOS (remplacez par notify-send sur Linux). Utile une fois que vous commencez à faire tourner des tours autonomes plus longs et à arrêter de surveiller le terminal en permanence.
5. Journaliser chaque commande bash
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.command' >> \"$CLAUDE_PROJECT_DIR/.claude/bash-history.log\""
}
]
}
]
}
}
Une piste d'audit qui ne dépend pas de votre mémoire pour vérifier la transcription. Sur une machine partagée ou un dépôt avec une exigence de conformité, c'est proche de l'obligatoire.
6. Barrière de lint avant commit
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/block_bad_commit.sh"
}
]
}
]
}
}
block_bad_commit.sh lit stdin, vérifie si la commande est un git commit, et si oui exécute d'abord votre linter, en sortant avec un code non nul s'il échoue. Cela transforme « merci de linter avant de commit » d'une demande que Claude pourrait oublier en une règle qu'il ne peut pas contourner.
PACK DE DÉMARRAGE GRATUIT
Vous configurez des hooks à côté de vos premières skills ? Nous vous envoyons nos 3 skills les mieux notées plus la checklist d'installation que nous suivons avant chaque test SkillProof. Gratuit.
Obtenir le pack de démarrage gratuitHooks et skills ensemble
Ce ne sont pas des outils concurrents ; les meilleures configurations utilisent les deux pour ce que chacun fait bien. Un exemple travaillé : une équipe que nous avons testée voulait que chaque commit soit écrit dans leur style maison, mode impératif, préfixe ciblé, un corps expliquant le pourquoi, et elle voulait aussi que les commits soient bloqués si le diff touchait une migration de base de données sans fichier de rollback correspondant.
La partie style relève du jugement. Ce qui compte comme un bon « pourquoi » varie selon le changement, et il n'existe pas de script shell qui écrit de manière fiable une bonne prose. C'est le travail d'une skill : quelque chose comme Git Workflow Coach chargée dès que Claude s'apprête à commit, enseignant la structure et donnant des exemples de bons vs paresseux messages de commit. Claude la lit, applique son jugement, et écrit un message qui suit le schéma sans être un simple remplissage de modèle. Si l'équipe suit aussi un strict red-green-refactor, Test-Driven Development est le même genre d'ajout jugement-pas-loi : elle façonne la façon dont Claude aborde le travail, un hook ne peut pas faire cette partie.
La règle de migration n'est pas du jugement, c'est de la loi : soit le fichier de rollback existe, soit non, et l'équipe ne voulait pas que « Claude a décidé que celui-ci n'en avait pas besoin » soit une option. C'est le hook PreToolUse de la recette six, adapté pour vérifier la présence du fichier apparié plutôt que d'exécuter un linter, bloquant l'appel git commit complètement s'il manque.
Faites tourner les deux ensemble et vous obtenez un bon message de commit qui passe aussi, garanti, le contrôle de migration, parce que la skill gère la partie qui a besoin d'un cerveau et le hook gère la partie qui a besoin d'un mur. Aucun ne remplace l'autre. La skill ne peut pas garantir la conformité, et un hook qui écrirait « fix: various changes » à chaque commit serait inutile. Notre page meilleures skills de code classe le côté jugement de cette paire par score testé, si vous choisissez une première skill à faire tourner à côté de vos hooks.
Déboguer les hooks
Les hooks échouent plus souvent silencieusement que bruyamment. Ce qui casse habituellement :
Le quoting. Les commandes de hook sont des chaînes shell à l'intérieur de chaînes JSON, donc un " non échappé casse le parsing JSON avant même que votre commande ne s'exécute. Dans le doute, mettez la vraie logique dans un fichier script et faites en sorte que la commande du hook l'invoque simplement (bash .claude/hooks/my-hook.sh) plutôt que d'inliner une ligne complexe.
Des codes de sortie qui ne veulent pas dire ce que vous pensez. Un script de hook qui rencontre une erreur sans rapport (dépendance manquante, permission refusée) sort avec un code non nul, tout comme un hook qui veut délibérément bloquer. Si un hook PreToolUse commence à bloquer chaque appel d'outil et que vous ne l'avez pas écrit pour être aussi strict, vérifiez si le script échoue réellement plutôt que de juger.
Des suppositions sur PATH. Les hooks s'exécutent dans un environnement shell qui peut ne pas correspondre à votre terminal interactif. Une commande qui fonctionne bien quand vous la tapez vous-même peut échouer dans un hook parce que nvm, un virtualenv, ou un outil installé via un plugin shell n'est pas sur le PATH dans ce contexte. Utilisez des chemins absolus vers les binaires, ou sourcez le bon environnement en haut du script.
Des suppositions silencieuses sur stdin. Si votre script attend du JSON sur stdin et n'en reçoit pas, parce que vous l'avez testé en l'exécutant directement plutôt qu'en lui pipant un payload d'exemple, il se comportera différemment sous le harnais que sur votre terminal.
Les timeouts. Un hook sans timeout qui se bloque bloquera tout le tour. Définissez un timeout explicite sur tout ce qui touche le réseau ou un sous-processus lent.
Quand ne pas utiliser les hooks
Les hooks sont peu coûteux à écrire et faciles à surutiliser. Le mode d'échec n'est pas un hook qui fait la mauvaise chose, c'est un hook qui fait la bonne chose trop souvent. Un hook PostToolUse qui exécute votre suite de tests complète après chaque édition transforme un changement de cinq secondes en une attente de deux minutes, répétée pour chacune des vingt éditions d'une session.
La règle générale : si la commande d'un hook prend plus d'une ou deux secondes, restreignez le matcher, restreignez ce qu'il vérifie, ou déplacez-le vers un événement moins fréquent. Tester à chaque édition devient tester à chaque écriture devient tester avant commit à mesure que la vérification devient plus coûteuse. Faites correspondre le coût du hook à la fréquence de son événement, et envisagez si une skill, qui ne fait que charger du contexte sans exécuter de processus, convient mieux pour tout ce qui n'est pas strictement de l'application forcée.
Il vaut aussi la peine de ne pas se tourner vers un hook pour corriger le problème de déclenchement d'une skill. Si une skill ne se déclenche pas quand elle le devrait, la correction est une meilleure description, pas un hook, puisque les hooks exécutent des commandes shell et ne peuvent pas charger le contenu d'une skill. Pour ce mode d'échec, voir pourquoi les skills ne se déclenchent pas.
PACK SKILLPROOF
Associer les hooks aux bonnes skills, c'est la majeure partie d'une bonne configuration Claude Code. Le Developer Toolkit rassemble nos skills de code les mieux notées, pré-vérifiées pour l'absence de conflits de déclenchement, pour que la moitié skill de cette association soit déjà faite pour vous.
Obtenir le Developer Toolkit — 10 $FAQ
Les hooks ralentissent-ils chaque session Claude Code ?
Seulement les événements auxquels vous les attachez, et seulement du temps que prend votre commande. Un hook sur PostToolUse pour Edit s'exécute une fois par édition ; un formateur rapide est imperceptible, une suite de tests complète se fait sentir à chaque édition, ce qui est le cas couvert plus haut sous quand ne pas utiliser les hooks.
Un hook peut-il empêcher Claude de faire complètement quelque chose ?
Oui, c'est à ça que servent les hooks PreToolUse. Sortez avec un code non nul et l'appel d'outil est bloqué avant de s'exécuter, avec stderr généralement renvoyé à Claude comme raison. C'est le mécanisme derrière la recette deux (chemins protégés) et la recette six (barrière de lint).
Où je mets ma config de hooks, settings projet ou utilisateur ?
Niveau projet (.claude/settings.json, commité) si ça doit s'appliquer à tout le monde sur cette base de code : formatage, chemins protégés, contrôles de migration. Niveau utilisateur (~/.claude/settings.json) pour une préférence personnelle, comme la notification bureau de la recette quatre.
Quelle est la différence entre un hook et une skill qui dit « toujours formater le code » ?
Le hook s'exécute réellement toujours. Une skill qui dit à Claude de toujours formater le code reste une instruction que Claude lit et décide de suivre ; c'est un fort coup de pouce, pas une garantie, et cela est en concurrence avec d'autres choses dans le contexte pour l'attention à un tour donné. Si « toujours » est une exigence plutôt qu'une préférence, utilisez un hook.
Mon hook ne s'exécute pas du tout. Que vérifier en premier ?
Confirmez que le fichier settings est du JSON valide (une virgule traînante ou un guillemet non échappé peut désactiver silencieusement tout le bloc hooks) et que le nom de l'événement et le matcher sont orthographiés exactement comme attendu ; les deux sont sensibles à la casse. Ensuite, vérifiez si vous avez édité les settings projet alors que la session lit les settings utilisateur, ou l'inverse.
★ 9.6/10 × 3
Le pack de démarrage gratuit
Les 3 skills avec nos meilleurs scores de test, plus la checklist d'installation — le setup qu'on mettrait sur une machine neuve. Gratuit, par e-mail.