Hooks : des garde-fous et automatismes qui s'exécutent à coup sûr
Automatisez formatage, protections et notifications dans Claude Code grâce aux hooks : événements, codes de sortie, recettes prêtes à l'emploi et débogage.
- Configurer un hook dans settings.json en choisissant l'événement et le matcher adaptés
- Bloquer les actions dangereuses avec un hook PreToolUse et le code de sortie 2
- Automatiser le formatage du code et les notifications de fin de tâche
Vous avez déjà écrit dans votre CLAUDE.md : « pense à formater le code après chaque modification » ? Parfois Claude le fait. Parfois il oublie. Une consigne en langage naturel reste une probabilité, jamais une certitude. Dans ce module, vous allez transformer vos consignes en automatismes : les hooks exécutent vos propres commandes, à coup sûr, aux moments clés de chaque session.
Ce que vous allez apprendre
- Comprendre pourquoi un hook est plus fiable qu’une consigne écrite
- Choisir le bon événement du cycle de vie : PreToolUse, PostToolUse, Stop et les autres
- Écrire un hook complet dans settings.json : événement, matcher, commande
- Bloquer une action dangereuse grâce au code de sortie 2
- Mettre en place trois recettes concrètes : formatage automatique, protection des secrets, notifications
Demander gentiment n’est pas une garantie
Posons le décor. Depuis plusieurs modules, vous savez donner à Claude Code des consignes durables dans le fichier CLAUDE.md. Et cela fonctionne bien. Mais soyons honnêtes : une consigne écrite est une demande, pas un contrat. Claude la lit, la comprend, et la suit… la plupart du temps. Quand la session s’allonge et que le contexte se remplit, il peut passer à côté. Ce n’est pas un caprice : un modèle de langage raisonne en probabilités, comme nous l’expliquons dans notre dossier IA.
Un hook change complètement la donne. Le mot anglais signifie « crochet » : un point d’accroche dans le cycle de vie de Claude Code, c’est-à-dire la suite d’étapes que traverse chaque session — démarrage, prompt, outils, réponse, fin. Sur chacun de ces points d’accroche, vous pouvez brancher une commande shell : une instruction exécutée par votre terminal, exactement comme si vous l’aviez tapée vous-même. La différence est fondamentale. Ce n’est plus Claude qui décide de formater votre code. C’est Claude Code, le logiciel, qui exécute votre commande. Automatiquement. À chaque fois. Sans exception.
Une image du quotidien : la consigne « pense à fermer la porte » dépend de la mémoire de chacun. Le groom de porte, ce bras mécanique qui la referme tout seul, ne dépend de personne. Un hook, c’est le groom de porte de votre projet. Et si un terme technique vous échappe en cours de route, gardez notre glossaire ouvert dans un onglet.
Neuf événements pour agir au bon moment
Un hook s’accroche toujours à un événement : un moment précis du cycle de vie. Petit rappel au passage : un outil, dans Claude Code, c’est une capacité concrète de l’agent — lire un fichier, en écrire un, lancer une commande. Voici les principaux événements, avec un cas d’usage typique pour chacun.
| Événement | Quand se déclenche-t-il ? | Cas d’usage typique |
|---|---|---|
| PreToolUse | Juste avant qu’un outil s’exécute — peut bloquer l’action | Interdire la modification de fichiers sensibles |
| PostToolUse | Juste après qu’un outil a réussi | Formater ou vérifier le fichier modifié |
| UserPromptSubmit | Quand vous validez un prompt | Injecter du contexte, filtrer certaines demandes |
| Notification | Quand Claude Code réclame votre attention | Notification sur le bureau |
| Stop | Quand Claude a fini de répondre | Notification de fin, vérification globale |
| SubagentStop | Quand un sous-agent termine sa tâche | Journaliser le travail délégué |
| PreCompact | Avant le compactage du contexte | Sauvegarder la transcription complète |
| SessionStart | Au démarrage ou à la reprise d’une session | Charger l’état du projet, la branche git |
| SessionEnd | À la fermeture de la session | Nettoyage, journal de bord |
Retenez surtout le duo star. PreToolUse est un vigile : il voit l’action arriver et peut lui barrer la route. PostToolUse est un concierge : il passe derrière et remet tout en ordre. La quasi-totalité de vos hooks utiliseront l’un ou l’autre.
L’anatomie d’un hook dans settings.json
Les hooks se déclarent dans settings.json, le fichier de configuration que vous connaissez depuis le module sur les permissions. Trois emplacements possibles : ~/.claude/settings.json pour vos réglages personnels, .claude/settings.json pour le projet, et .claude/settings.local.json pour vos réglages de projet non partagés.
La structure a trois étages. L’événement, d’abord. Puis le matcher — littéralement « celui qui fait correspondre » — un filtre qui précise quels outils déclenchent le hook. Enfin, la ou les commandes. Regardez ce squelette :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "votre-commande-ici" }
]
}
]
}
}
Le matcher Edit|Write se lit « Edit ou Write » : le hook se déclenche pour l’outil d’édition comme pour l’outil d’écriture de fichiers. Un nom seul, comme Bash, cible un outil précis. Un matcher vide, ou une étoile, cible tout.
Au moment de s’exécuter, votre commande reçoit un colis : une description au format JSON — du texte structuré, lisible par les machines — envoyée sur son entrée standard, le canal appelé stdin par lequel un programme reçoit des données. Voici à quoi ressemble ce colis pour un PreToolUse :
{
"session_id": "abc123",
"cwd": "/home/vous/mon-projet",
"hook_event_name": "PreToolUse",
"tool_name": "Write",
"tool_input": { "file_path": "/home/vous/mon-projet/.env" }
}
Tout y est : quel outil, quel fichier, quelle session. Votre commande dispose de 60 secondes par défaut pour faire son travail ; ce délai se règle hook par hook si besoin.
💡 Astuce — pour lire ce JSON dans un script, l’outil jq est votre meilleur ami. C’est un petit utilitaire en ligne de commande qui extrait n’importe quel champ d’un JSON. Par exemple, jq -r ‘.tool_input.file_path’ renvoie le chemin du fichier concerné. Toutes nos recettes s’appuient dessus.
💡 Astuce — placez vos hooks d’équipe dans .claude/settings.json, versionné avec git : chaque membre du projet hérite des mêmes garde-fous, sans rien configurer.
Le contrat des codes de sortie
Comment votre commande répond-elle à Claude Code ? Par son code de sortie : le nombre qu’un programme renvoie en se terminant, sa façon de dire « mission accomplie » ou « problème ». Le contrat tient en trois lignes, et il faut le connaître par cœur.
Code 0 : tout va bien. L’action suit son cours normalement.
Code 2 : stop. Sur un PreToolUse, l’action est bloquée avant même de commencer. Et surtout, tout ce que votre script a écrit sur stderr — la sortie d’erreur, le canal réservé aux messages de problème — est transmis à Claude. Il lit votre message, comprend le refus, et adapte sa stratégie. C’est un dialogue, pas seulement un mur.
Tous les autres codes : erreur non bloquante. Le souci est signalé, mais l’action n’est pas empêchée.
⚠️ Piège courant — le code 1, réflexe classique en shell pour dire « erreur », ne bloque rien du tout dans un hook. Si votre garde-fou laisse passer des actions qu’il devrait interdire, vérifiez ce point en premier : seul exit 2 bloque.
Pour les cas plus fins, il existe une sortie JSON avancée : au lieu d’un simple code, votre script imprime un JSON qui décide explicitement allow (autoriser), deny (refuser) ou ask (demander confirmation à l’utilisateur). Gardez cette carte pour plus tard : les codes de sortie couvrent déjà l’immense majorité des besoins.
💡 Astuce — soignez vos messages sur stderr. « Modification refusée : ce fichier contient des secrets, propose une autre approche » aide Claude bien davantage qu’un laconique « interdit ».
Trois recettes prêtes à l’emploi
Passons de la théorie à la pratique, avec trois recettes que vous pourrez réutiliser dans tous vos projets.
Recette 1 : formatage automatique après chaque modification
Prettier est un formateur de code très répandu dans l’écosystème JavaScript : il réindente et harmonise le style d’un fichier, toujours de la même manière. Objectif : le lancer après chaque fichier touché. Événement PostToolUse, matcher Edit|Write, et une commande en deux maillons : jq extrait le chemin du fichier depuis le JSON reçu, puis prettier le formate.
Dans .claude/settings.json :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}
Le maillon xargs fait le pont : il prend le chemin sorti par jq et le donne en argument à prettier. Désormais, chaque fichier modifié par Claude ressort formaté. Sans exception, et sans y penser.
Recette 2 : des fichiers intouchables
Deuxième besoin, côté sécurité : interdire toute modification de vos fichiers sensibles. Le fichier .env, qui stocke vos variables d’environnement — clés d’API, mots de passe de base de données. Les fichiers de credentials, c’est-à-dire d’identifiants. Le dossier secrets/. Créez un petit script .claude/hooks/protege-secrets.sh :
#!/bin/bash
# Bloque toute écriture sur les fichiers sensibles
FICHIER=$(jq -r '.tool_input.file_path // empty')
if echo "$FICHIER" | grep -qE '\.env|credentials|secrets/'; then
echo "Refusé : $FICHIER est un fichier sensible, ne pas le modifier." >&2
exit 2
fi
exit 0
Rendez-le exécutable avec chmod +x, puis branchez-le sur PreToolUse :
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/protege-secrets.sh"
}
]
}
]
}
}
La variable CLAUDE_PROJECT_DIR pointe vers la racine de votre projet : le hook fonctionne quel que soit le dossier courant. Sous Windows, ce script bash s’exécute via Git Bash ou WSL. Désormais, si Claude tente d’écrire dans .env, le vigile dit non — et Claude reçoit votre message d’explication.
Recette 3 : être prévenu au bon moment
Troisième recette, côté confort. Claude travaille parfois plusieurs minutes en autonomie. Pendant ce temps, vous faites autre chose — et vous ratez le moment où il attend votre feu vert. Deux événements règlent cela : Notification, quand Claude Code réclame votre attention, et Stop, quand la réponse est terminée. Voici la version macOS, avec la commande osascript qui affiche une notification système :
{
"hooks": {
"Notification": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude attend votre réponse\" with title \"Claude Code\"'"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Tâche terminée\" with title \"Claude Code\"'"
}
]
}
]
}
}
Sous Linux, remplacez la commande par notify-send suivi du titre et du message. Sous Windows, n’importe quelle commande PowerShell d’affichage de notification fera le même travail. Plus besoin de surveiller le terminal du coin de l’œil : c’est lui qui vous appelle.
Configurer, déboguer… et rester prudent
Deux réflexes pour piloter tout cela. Premier réflexe : la commande /hooks, tapée dans la session, affiche tous les hooks actifs — événement, matcher, commande, et leur provenance : réglages personnels, projet ou local. C’est le moyen le plus sûr de vérifier qu’une modification a bien été prise en compte.
Deuxième réflexe : lancez claude —debug pour voir vos hooks vivre. Ce mode détaillé affiche chaque hook exécuté, le JSON qu’il reçoit et son code de sortie. Quand un hook ne se déclenche pas comme prévu, c’est votre première escale : neuf fois sur dix, le coupable est un matcher mal orthographié ou un script non exécutable.
Un dernier mot, le plus important du module. Un hook est une commande arbitraire, exécutée avec vos droits d’utilisateur. Elle peut lire vos fichiers, en supprimer, appeler Internet. C’est sa force. C’est aussi son risque.
⚠️ Piège courant — vous clonez un dépôt trouvé en ligne et l’ouvrez avec Claude Code : les hooks définis dans son .claude/settings.json sont des commandes écrites par quelqu’un d’autre, exécutées chez vous, avec vos droits. Prenez trente secondes pour relire ce fichier avant de travailler dans un projet que vous n’avez pas créé. Trente secondes qui peuvent éviter de gros dégâts.
À vous de jouer
Place à la pratique : installez les deux garde-fous du module et vérifiez qu’ils tiennent leurs promesses.
- Dans un projet de test contenant du JavaScript, créez le fichier .claude/settings.json et copiez-y la recette 1, avec PostToolUse et prettier. Vérifiez que jq est disponible sur votre machine.
- Lancez claude, puis demandez une petite modification volontairement mal indentée dans un fichier. Ouvrez ce fichier : il est parfaitement formaté. Le concierge est passé derrière.
- Créez le script .claude/hooks/protege-secrets.sh de la recette 2, rendez-le exécutable avec chmod +x, puis ajoutez le bloc PreToolUse dans votre settings.json.
- Créez un fichier .env factice contenant une fausse clé, par exemple API_KEY=test123. Demandez ensuite à Claude d’ajouter une variable DEBUG=true dans ce fichier .env.
- Observez le refus : l’écriture est bloquée, et Claude vous explique qu’il ne peut pas modifier ce fichier — il a reçu votre message stderr. Le garde-fou fonctionne vraiment.
- Pour finir, relancez la même expérience avec claude —debug et regardez, en direct, le hook recevoir son JSON et renvoyer son code 2.
En résumé
- Une consigne en langage naturel est une probabilité ; un hook est une certitude : votre commande shell, exécutée automatiquement à un moment précis du cycle de vie.
- Les événements clés : PreToolUse avant un outil — le seul moment pour bloquer —, PostToolUse après, plus UserPromptSubmit, Notification, Stop, SubagentStop, PreCompact, SessionStart et SessionEnd.
- Un hook se déclare dans settings.json : un événement, un matcher comme Edit|Write, une commande ; il reçoit un JSON descriptif sur stdin et dispose de 60 secondes par défaut.
- Le contrat des codes de sortie : 0 tout va bien, 2 bloque et renvoie stderr à Claude, tout le reste signale sans bloquer.
- Trois recettes à réutiliser partout : formatage prettier en PostToolUse, protection des secrets en PreToolUse, notifications sur Notification et Stop.
- /hooks affiche vos hooks, claude —debug les montre en action — et on relit toujours les hooks d’un dépôt cloné avant de s’y installer.
Vos garde-fous montent désormais la garde tout seuls. Au prochain module, vous allez apprendre à déléguer : des sous-agents spécialisés, chacun avec sa mission et son propre contexte, qui travaillent pour vous — parfois même en parallèle.
Testez vos connaissances
Votre hook PreToolUse détecte un problème et se termine avec le code de sortie 1. Que se passe-t-il ?
Le contrat est strict : 0 signifie que tout va bien, 2 bloque l'action et renvoie stderr à Claude, et tous les autres codes — dont le 1 — sont traités comme des erreurs non bloquantes. Un garde-fou qui renvoie 1 laisse donc passer l'action qu'il voulait interdire.
Vous voulez lancer prettier automatiquement après chaque fichier modifié par Claude. Quelle combinaison choisir ?
Le formatage doit intervenir après la modification : c'est le rôle de PostToolUse. Le matcher Edit|Write cible les deux outils qui écrivent dans les fichiers. PreToolUse interviendrait avant la modification (rien à formater), et Stop seulement à la toute fin de la réponse.
Un hook PreToolUse bloque une écriture avec exit 2 et un message sur stderr. Que fait Claude ?
C'est toute la force du code 2 : le contenu de stderr est renvoyé à Claude, qui comprend la raison du refus et cherche une autre approche. D'où l'intérêt d'écrire des messages d'erreur clairs et détaillés plutôt qu'un simple mot.
Vous clonez un dépôt public et l'ouvrez avec Claude Code. Pourquoi relire son fichier .claude/settings.json avant de travailler ?
Un hook est une commande shell exécutée sur votre machine, avec vos droits d'utilisateur. Dans un dépôt cloné, ces commandes ont été écrites par quelqu'un d'autre : on les relit avant de travailler, exactement comme on relirait un script avant de le lancer.
Vous voulez une notification sur votre bureau quand Claude a terminé de répondre. Quel événement utiliser ?
L'événement Stop se déclenche quand Claude a fini de répondre : c'est le bon moment pour une notification de fin. SessionStart intervient au démarrage de la session, PreCompact avant le compactage du contexte, et PreToolUse avant chaque outil.