Tu sais déjà écrire un bon contrat pour ton agent : tu lui dis dans l'AGENTS.md comment tu veux qu'il travaille. Le problème, c'est qu'un LLM lit ce contrat et redécide à chaque tour — du coup la règle critique est respectée presque toujours, et ce « presque » est justement celui qui te mord. Les hooks sont l'échelon suivant : tu sors la règle de la tête du modèle et tu la mets dans l'infrastructure, pour qu'elle passe à 100 % sans dépendre de son jugement. Je t'explique les événements du cycle de vie où tu t'accroches, l'anatomie du JSON, où vit chaque hook et pourquoi ça compte, et je te laisse trois hooks réels prêts à coller (auto-formatage, blocage de commandes dangereuses, notification de bureau) tirés de la documentation officielle d'Anthropic. Un seul prompt maître pour monter ton premier avec la sécurité activée — parce qu'un hook exécute du shell avec tes permissions. C'est le saut de « écris le contrat » à « fais en sorte que le contrat s'exécute tout seul ».
Il arrive un point, dans tout projet avec IA, où tu cesses de te fier à la bonne volonté du modèle. Tu lui as écrit dans ton AGENTS.md de formater le code, de ne pas toucher aux fichiers sensibles, de lancer les tests. Et 90 % du temps il le fait. Mais les 10 % restants sont justement ceux qui te mordent : la fois où il a édité le .env de production, la fois où il a sauté le formatage et où le commit est resté sale, la fois où il a exécuté un rm -rf sur le mauvais dossier parce que « ça avait l'air temporaire ».
Le moment des hooks, c'est quand tu penses : « et si ça ne dépendait pas de la décision du modèle de bien faire ? Et si ça arrivait tout simplement, toujours, sans dépendre de son jugement ? ». C'est exactement la promesse que la documentation officielle de Claude Code place au centre de la page des hooks : ils donnent un « contrôle déterministe » sur le comportement de l'agent, « en garantissant que certaines actions se produisent toujours au lieu de dépendre du choix du LLM de les exécuter » (traduction fidèle de l'original en anglais). Cette phrase est la thèse entière de la ressource.
La douleur n'est pas une apocalypse, c'est une érosion. Tu as demandé à l'IA de faire quelque chose « toujours » et parfois elle ne le fait pas, parce qu'un LLM n'est pas déterministe : à chaque tour il redécide, et dans un tour chargé de contexte, ton rappel de formater peut se retrouver enseveli sous mille tokens d'autre chose. Ce n'est pas que l'IA soit désobéissante — c'est que tu demandes de la constance à un système probabiliste. C'est comme demander à quelqu'un de brillant mais distrait de ne jamais oublier de fermer le robinet de gaz : la plupart des soirs il le ferme, et c'est justement pour ça que tu baisses la garde.
.env, un package-lock.json, quelque chose dans .git/.Et voici l'angle qui rend cette ressource avancée : si tu as déjà lu sur l'écriture d'un bon contrat pour ton agent (l'AGENTS.md), les hooks sont l'échelon suivant. Tu passes de « écris le contrat » (déclaratif : tu dis ce que tu veux) à « fais en sorte que le contrat s'exécute tout seul » (déterministe : la machine le respecte pour toi). C'est la différence entre une loi écrite sur un papier et un policier posté au coin de la rue.
Un hook est une commande shell que Claude Code exécute automatiquement à un point précis de son cycle de vie. Tu le déclares une fois dans un fichier settings.json ; à partir de là, chaque fois que ce point du cycle survient, ta commande tourne. Ce n'est pas le modèle qui le déclenche avec son jugement : c'est l'événement qui le déclenche. Voilà la magie — c'est déterministe, pas discutable.
La documentation officielle liste beaucoup d'événements du cycle de vie — il y en a un pour presque tout moment du travail de l'agent. N'apprends pas le nombre ni la liste complète : apprends l'idée et retiens ceux que tu vas vraiment utiliser 95 % du temps. Les voici, avec leurs vrais noms tels qu'ils apparaissent dans la doc :
rm -rf ou une édition sur un fichier protégé.SessionStart avec matcher compact) — autour de la compactation du contexte, pour ne pas perdre l'essentiel quand la mémoire se comprime.Pre. Si tu veux réagir à quelque chose qui a déjà eu lieu (formater, prévenir, journaliser), accroche-toi à Post.Tout hook vit à l'intérieur d'un bloc "hooks" dans ton settings.json. La structure est toujours la même poupée russe : le nom de l'événement → un matcher (à quoi il s'applique) → une liste de hooks avec type: "command" et la command à exécuter. Regarde-le une fois et tu ne l'oublies plus :
{
"hooks": {
"PostToolUse": [ // 1. l'ÉVÉNEMENT du cycle de vie
{
"matcher": "Edit|Write", // 2. À QUELS outils il s'applique
"hooks": [
{
"type": "command", // 3. c'est une commande shell
"command": "...ta commande..." // 4. QUOI exécuter quand ça survient
}
]
}
]
}
}PreToolUse, PostToolUse) il filtre par nom d'outil : "Edit|Write" signifie « seulement quand j'utilise Edit ou Write », "Bash" seulement les commandes shell. Un matcher vide ("") se déclenche toujours, pour tout. La barre | sépare des alternatives (dans les versions récentes de Claude Code la virgule marche aussi : "Edit, Write" est équivalent).L'endroit où tu mets le hook définit sa portée. C'est essentiel : un hook de projet se partage avec ton équipe (il est commité au repo) ; un hook global n'est qu'à toi. Le tableau officiel résume où va chaque chose :
.claude/settings.json et se commite. Ainsi le contrat cesse de vivre dans la tête d'une personne et se met à voyager avec le code. C'est ça le vrai pouvoir : la discipline devient partie du dépôt, pas un post-it que quelqu'un doit se rappeler.Assez de théorie. Voici trois hooks réels, tirés de la documentation officielle, prêts à coller. Commence par celui qui te fait le plus mal aujourd'hui.
Le classique. Chaque fois que Claude édite ou écrit un fichier, Prettier passe automatiquement. Plus jamais un commit au formatage incohérent. Ça va dans le .claude/settings.json de ton projet :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}jq -r '.tool_input.file_path' extrait le chemin du fichier édité de ce JSON, et xargs npx prettier --write le passe à Prettier. jq est un lecteur de JSON en ligne de commande — installe-le avec brew install jq sur macOS ou apt-get install jq sur Debian/Ubuntu.C'est celui qui t'enlève la peur. Un hook PreToolUse qui examine chaque commande Bash avant de l'exécuter et la refuse si elle contient quelque chose de destructeur. Ici un détail technique compte, que la doc rend très clair : on bloque en sortant avec le code 2, et ce que tu écris sur stderr parvient à Claude comme explication pour qu'il se corrige. D'abord le script :
#!/bin/bash # .claude/hooks/block-rm-rf.sh INPUT=$(cat) COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command') if echo "$COMMAND" | grep -q "rm -rf"; then echo "Bloque : 'rm -rf' n'est pas autorise. Supprime des chemins precis, pas de recursif-force." >&2 exit 2 # exit 2 = bloque l'action ; stderr parvient a Claude comme feedback fi exit 0 # exit 0 = pas d'objection ; le flux normal de permissions continue
Rends-le exécutable et enregistre-le dans tes settings en pointant vers le script :
chmod +x .claude/hooks/block-rm-rf.sh
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-rm-rf.sh"
}
]
}
]
}
}grep -q "rm -rf" attrape le cas évident, mais un rm -fr, un rm -rf avec des espaces bizarres ou un rm --recursive --force lui échappent. Il sert de filet visible et de feedback pédagogique pour l'IA, mais ne le confonds pas avec un blindage. La doc elle-même le dit sans détour : le filtrage des hooks est best-effort et « échoue ouvert » (s'il n'arrive pas à parser la commande, il la laisse passer), donc pour une interdiction DURE que personne ne puisse contourner, utilise le système de permissions (permissions.deny), pas un hook. Le bon motif est : un hook pour réagir et prévenir ; des permission rules pour le vrai cadenas.PreToolUse qui renvoie une décision de blocage refuse l'outil MÊME en `bypassPermissions` ou avec `--dangerously-skip-permissions`. Autrement dit : même si toi (ou l'IA) avez baissé toutes les barrières de permissions, ton hook de blocage tient toujours. La règle est asymétrique et c'est voulu exprès : les hooks peuvent durcir la politique, jamais l'assouplir au-delà de ce que permettent les règles de permissions. Un hook de blocage est une règle que même toi tu ne peux pas contourner par accident.Pour arrêter de surveiller le terminal. Quand Claude termine ou a besoin de ta permission, une notification de bureau s'affiche et tu vas faire autre chose. Ça va dans ton ~/.claude/settings.json global (exemple de macOS avec osascript) :
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code a besoin de ton attention\" with title \"Claude Code\"'"
}
]
}
]
}
}notify-send 'Claude Code' 'Claude Code a besoin de ton attention' ; sur Windows (PowerShell) un MessageBox de System.Windows.Forms. La structure du JSON est identique — seule change la ligne du command. Astuce macOS documentée par le guide lui-même : si la notification n'apparaît pas, lance une fois osascript -e 'display notification "test"' puis donne la permission à Script Editor dans Réglages Système → Notifications.Les hooks ne servent pas à tout. La règle mentale est simple : si quelque chose doit arriver toujours, de façon mécanique et sans jugement, c'est un hook. Si quelque chose exige un jugement au cas par cas, ne le force pas avec un hook déterministe — laisse le modèle décider (ou utilise les hooks de type prompt/agent que la doc supporte aussi, mais c'est une autre catégorie).
.env, supprimer en récursif, écrire dans .git/) : c'est un PreToolUse de blocage — appuyé par une règle de permissions pour le cadenas dur.PostToolUse.PostToolUse : il ne peut pas défaire ce qui a déjà eu lieu — il ne fait que réagir. Pour empêcher, toujours PreToolUse. Mettre trop de logique complexe dans un hook le rend fragile ; garde-les courts et à but unique.Voici le détail pratique : la doc elle-même te recommande de demander à Claude de t'écrire le hook en le lui décrivant. Mais pour que ça se passe bien — et que ce soit sûr — mieux vaut lui donner une mission structurée, pas un « mets-moi un hook ». Voici LE prompt maître de la ressource : un seul, puissant, qui conçoit ton premier hook avec les freins de sécurité activés.
Je veux monter mon premier hook de Claude Code pour automatiser une règle de mon flux. La règle que je veux garantir TOUJOURS est : [DÉCRIS LA RÈGLE, ex : "formater avec prettier chaque fichier que tu édites" / "bloquer toute commande qui supprime des fichiers de façon récursive" / "empêcher qu'on édite le .env ou quoi que ce soit dans .git/" / "me prévenir par notification quand tu as fini"]. Avant d'écrire quoi que ce soit, aide-moi à bien le concevoir en répondant à ceci en langage clair (moi je ne programme pas) : 1. L'ÉVÉNEMENT correct du cycle de vie pour cette règle. Si la règle est d'EMPÊCHER quelque chose, ça doit être PreToolUse (survient avant et peut bloquer). Si c'est de RÉAGIR à quelque chose de déjà fait (formater, prévenir, journaliser), ça doit être PostToolUse ou Notification. Dis-moi lequel tu choisis et pourquoi. 2. Le MATCHER exact (à quels outils il s'applique : Edit|Write, Bash, ou vide pour tous) et pourquoi celui-là et pas un autre. Garde-le le plus ÉTROIT possible : un matcher trop large déclenche le hook là où il ne devrait pas. 3. L'ENDROIT où doit vivre le settings.json : - Si la règle doit être respectée par toute l'équipe sur ce repo → .claude/settings.json (se commite). - Si c'est seulement pour ma machine et tous mes projets → ~/.claude/settings.json. - Si c'est local et privé → .claude/settings.local.json. Dis-moi lequel et pourquoi. 4. Le BLOC JSON complet, prêt à coller, avec le hook déjà monté. S'il a besoin d'un script à part (typique pour les blocages avec PreToolUse), donne-moi aussi le script .sh complet et rappelle-moi de le rendre exécutable avec chmod +x. 5. SI C'EST UN HOOK DE BLOCAGE : utilise-le avec exit 2 et un message clair sur stderr qui m'explique pourquoi ça a été bloqué, pour que toi-même (Claude) reçoives la raison et te corriges. Ne le fais pas silencieux. Et PRÉVIENS-MOI si cette règle mérite en plus une règle de permissions (permissions.deny) comme cadenas dur, car un grep dans un hook est best-effort et peut être contourné. 6. SÉCURITÉ, obligatoire : explique-moi en une phrase QUELLE commande shell ce hook va exécuter et confirme-moi qu'elle ne fait rien de destructeur ni n'envoie de données nulle part. Rappelle-moi qu'un hook exécute du shell avec mes permissions et que je ne dois enregistrer que des commandes que je comprends. 7. COMMENT JE LE TESTE : dis-moi comment vérifier que le hook est enregistré (la commande /hooks dans Claude Code) et une façon de tester qu'il se déclenche vraiment, sans rien casser de réel. Montre-moi d'abord SEULEMENT la conception (événement, matcher, endroit), ensuite le JSON et le script si nécessaire, et à la fin l'explication de sécurité et le test. Ne modifie pas encore mon settings.json : je veux relire le bloc avant de le coller moi-même.
Remarque le motif : d'abord tu conçois, tu vérifies la sécurité, et c'est toi qui colles le bloc. Tu ne laisses jamais un hook apparaître dans ta configuration sans l'avoir compris. C'est la même discipline en deux temps qui protège toute automatisation puissante : la machine propose, tu approuves.
Pour que ça ne s'emmêle pas, voici ce que tu peux déléguer à l'IA par le chat et ce qui reste ton affaire :
.sh pour les hooks de blocage, avec son jq, son exit 2 et son message sur stderr.settings.json il doit vivre.chmod +x du script, brew install jq s'il te manque.settings.json — après l'avoir lu et compris. Le filet de sécurité ne peut pas être du code que tu n'as pas relu.PreToolUse pour empêcher, PostToolUse/Notification pour réagir.PreToolUse qui refuse ce qui ne doit pas entrer. C'est la même philosophie qu'un hook, appliquée à une équipe entière au lieu d'un terminal : que la qualité ne soit pas une promesse que quelqu'un se rappelle, mais un capteur sur le tapis qu'on ne peut pas contourner. Toi tu poses la règle une fois ; le système la respecte pour toujours.Join 4,200+ builders. No credit card. Build your first app with AI in minutes.