Maîtriser les hooks Claude Code : automatiser ton workflow de dev
Les hooks Claude Code sont probablement la feature la plus sous-exploitée de l’outil. La plupart des devs s’arrêtent aux slash commands et au CLAUDE.md. Pourtant, un hook bien configuré peut te faire gagner des heures par semaine en automatisant ce qui se passe autour de chaque action de Claude : lint après édition, tests avant commit, notifications, logs d’audit.
Ce guide couvre les 4 types de hooks (PreToolUse, PostToolUse, Stop, Notification), donne 8 recettes prêtes à copier-coller, et explique comment debugger quand un hook ne déclenche pas.
Anatomie d’un hook Claude Code
Un hook est un script shell qui s’exécute automatiquement quand Claude Code fait une action précise (lire un fichier, en écrire un, lancer une commande, terminer une session). Tu configures les hooks dans settings.json :
~/.claude/settings.json— config globale, s’applique à toutes tes sessions.claude/settings.jsondans un repo — config spécifique au projet, versionnable
Structure de base :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "echo \"Fichier modifié : $(jq -r '.tool_input.file_path')\" >> ~/claude-log.txt"
}
]
}
]
}
}
Ici : après chaque tool Edit ou Write, Claude exécute la commande shell qui log le chemin du fichier modifié.
Les 4 types de hooks les plus utilisés
PreToolUse
S’exécute avant un tool call. Peut bloquer l’action si le script retourne un code d’erreur. Utile pour :
- Bloquer des commandes dangereuses (
rm -rf,DROP TABLE) - Valider qu’un fichier n’est pas sensible avant écriture
- Demander confirmation sur des actions critiques
PostToolUse
S’exécute après un tool call réussi. Le plus utilisé. Parfait pour :
- Lint/format auto après écriture de fichier
- Lancer les tests après édition
- Logger les actions pour audit
- Backup avant modification
Stop
S’exécute quand Claude termine sa réponse (fin de tour). Idéal pour :
- Notification desktop « Claude a fini »
- Message Slack automatique
- Metrics / télémétrie de fin de session
Notification
S’exécute quand Claude affiche une notification à l’utilisateur (demande de confirmation, erreur). Utile pour router ces events vers Slack ou un dashboard.
8 recettes prêtes à copier-coller
Copie la config dans ton ~/.claude/settings.json ou .claude/settings.json selon le scope souhaité.
Recette 1, Linter auto après édition
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs -I{} npx eslint --fix \"{}\" 2>/dev/null || true"
}
]
}
]
}
}
Chaque fois que Claude édite un fichier, ESLint auto-fix les problèmes stylistiques. || true pour éviter que le hook échoue si le fichier n’est pas supporté par ESLint.
Recette 2, Format Prettier ou Biome après édition
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs -I{} npx prettier --write \"{}\" 2>/dev/null || true"
}
]
}
]
}
}
Formatage automatique à chaque écriture. Le code que Claude génère reste cohérent avec ton style guide.
Recette 3, Tests auto après édition de fichiers critiques
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "FP=$(jq -r '.tool_input.file_path'); if [[ \"$FP\" == *\"/lib/\"* ]]; then npm test -- --run --reporter=default \"$FP\" 2>&1 | tail -20; fi"
}
]
}
]
}
}
Si Claude touche à un fichier dans lib/, lance les tests unitaires correspondants. Empêche les régressions silencieuses.
Recette 4, Notification desktop quand Claude a fini (macOS)
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude a terminé la tâche\" with title \"Claude Code\" sound name \"Glass\"'"
}
]
}
]
}
}
Indispensable pour les tâches longues où tu pars faire autre chose. Dès que Claude finit, tu reçois une notif système. Linux : remplace par notify-send. Windows : via PowerShell [System.Media.SystemSounds]::Asterisk.Play().
Recette 5, Bloquer les commandes dangereuses
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "CMD=$(jq -r '.tool_input.command'); echo \"$CMD\" | grep -qE '(rm -rf|sudo rm|DROP TABLE|truncate|git push -f)' && { echo 'Commande dangereuse bloquée' >&2; exit 2; } || exit 0"
}
]
}
]
}
}
Si Claude essaie de lancer une commande listée (rm -rf, DROP TABLE, git push --force…), le hook sort avec le code 2 (le seul code qui bloque une action — tout autre code non-zéro laisse passer) et écrit la raison sur stderr. Claude voit l’erreur et comprend qu’il doit demander confirmation.
Recette 6, Logger toutes les actions pour audit
{
"hooks": {
"PostToolUse": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "IN=$(cat); echo \"$(date -u +%Y-%m-%dT%H:%M:%SZ) | $(echo \"$IN\" | jq -r '.tool_name') | $(echo \"$IN\" | jq -r '.tool_input.file_path // \"\"')\" >> ~/.claude/audit.log"
}
]
}
]
}
}
Log structuré de chaque tool call (timestamp, tool, fichier). Parse avec grep, awk ou un agrégateur si besoin. Utile en équipe pour comprendre ce que Claude fait sur la codebase partagée.
Recette 7, Backup automatique avant édition
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "FP=$(jq -r '.tool_input.file_path'); if [ -f \"$FP\" ]; then cp \"$FP\" \"/tmp/claude-backup-$(basename \"$FP\")-$(date +%s)\"; fi"
}
]
}
]
}
}
Copie le fichier dans /tmp avant modification. Si Claude casse quelque chose, tu peux restaurer vite. Utile si tu n’as pas commité récemment.
Recette 8, Envoyer un message Slack quand Claude finit
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "curl -s -X POST -H 'Content-type: application/json' --data '{\"text\":\"🤖 Claude a terminé une session sur '\"$(pwd)\"'\"}' $SLACK_WEBHOOK_URL > /dev/null"
}
]
}
]
}
}
À combiner avec une variable d’env SLACK_WEBHOOK_URL. Parfait si tu lances des tâches longues et que tu veux être notifié dans ton canal perso.
Les variables d’environnement accessibles dans les hooks
Claude Code expose plusieurs env vars que tu peux utiliser dans tes scripts :
$CLAUDE_PROJECT_DIR, dossier racine du projet actif (vraie variable d’environnement)$CLAUDE_ENV_FILE, fichier de persistance des variables d’environnement entre commandes Bash.tool_name(JSON stdin), nom du tool (Edit, Write, Bash, etc.).tool_input.file_path(JSON stdin), chemin du fichier impacté (Edit/Write/Read).tool_input.command(JSON stdin), commande exécutée (Bash).session_id/.cwd/.transcript_path(JSON stdin), métadonnées de session
Sauf $CLAUDE_PROJECT_DIR et $CLAUDE_ENV_FILE (vraies variables d’environnement), toutes les infos du tool call arrivent en JSON sur l’entrée standard (stdin) du script, à parser avec jq. C’est ce qui te permet d’écrire des logiques conditionnelles propres dans tes hooks PreToolUse et PostToolUse.
Les 5 pièges courants
Piège 1, Hooks qui plantent silencieusement
Seul exit 2 bloque une action (avec le message sur stderr renvoyé à Claude) ; tout autre code non-zéro laisse l’action passer mais affiche une notice d’erreur. Pour un PostToolUse qui ne doit pas perturber le flux, finis par || true ; pour un PreToolUse qui doit bloquer, sors explicitement avec exit 2.
Piège 2, Oublier les guillemets
Les chemins de fichiers contiennent souvent des espaces. Toujours entourer la variable qui contient le chemin (ex. "$FP" après FP=$(jq -r '.tool_input.file_path')) de guillemets doubles, sinon ton hook plante sur les chemins avec espaces.
Piège 3, Matchers trop larges
Un matcher ".*" match tous les tools, ce qui peut générer trop de bruit. Préfère des matchers précis : Edit|Write, Bash, etc.
Piège 4, Commandes qui prennent trop de temps
Un hook PostToolUse qui tourne 30 secondes ralentit chaque action. Si ton hook est lent (tests complets), run-le seulement sur des matchers restrictifs, ou passe-le en background avec & si tu n’as pas besoin du résultat.
Piège 5, Escape des quotes dans JSON
Le fichier settings.json est du JSON, donc les " dans les commandes shell doivent être échappés avec \\". Éditeur avec coloration JSON recommandé pour éviter les headaches.
Debugger un hook qui ne fire pas
Vérifier que le fichier settings est lu
claude --verbose
# Dans les logs au démarrage, tu vois quels settings.json sont chargés
Tester le matcher
Le matcher est une regex JS appliquée au nom du tool. Teste-la rapidement :
node -e "console.log(/Edit|Write/.test('Edit'))" # true
node -e "console.log(/Edit|Write/.test('Bash'))" # false
Tester la commande shell en standalone
Sors la commande du hook et simule l’entrée JSON sur stdin, puis lance-la en terminal :
CLAUDE_FILE_PATH="/tmp/test.ts" npx eslint --fix "$CLAUDE_FILE_PATH"
Si ça marche en terminal mais pas en hook, c’est probablement un problème d’escape JSON ou de PATH (les hooks peuvent avoir un PATH différent de ton shell interactif).
Logger l’exécution du hook
Ajoute temporairement un log au début de ta commande :
{
"command": "echo \"HOOK FIRED: $CLAUDE_TOOL_NAME on $CLAUDE_FILE_PATH\" >> /tmp/hook-debug.log && "
}
Puis tail -f /tmp/hook-debug.log dans un autre terminal. Tu verras en temps réel si le hook se déclenche.
Combiner plusieurs hooks intelligemment
Rien ne t’empêche d’avoir plusieurs hooks sur le même matcher. Attention : ils s’exécutent en parallèle, dans un ordre non déterministe — ne compte pas sur l’ordre de déclaration. Si tu as besoin d’un ordre précis (ex. prettier puis eslint --fix puis log), enchaîne les commandes dans un seul hook avec && :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true" },
{ "type": "command", "command": "npx eslint --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true" },
{ "type": "command", "command": "echo \"$CLAUDE_FILE_PATH formaté et linté\" >> ~/.claude/actions.log" }
]
}
]
}
}
Attention : les hooks frères s’exécutent tous, même si l’un retourne une décision de blocage (un deny n’empêche pas les autres de tourner) ; c’est la décision la plus restrictive qui l’emporte pour autoriser ou bloquer l’action.
[faq q="Les hooks ralentissent-ils Claude Code ?"]
Un peu, selon ce qu'ils font. Un lint rapide (< 1s) est imperceptible. Des tests complets qui prennent 30s ralentissent chaque action. Règle pratique : garde tes hooks sous 2-3 secondes. Pour les traitements lourds, déclenche-les en background avec & ou mets-les sur des matchers très restrictifs.
[/faq]
[faq q="Où placer ses hooks : global ou par projet ?"]
Les deux, selon la nature. Global (~/.claude/settings.json) : notifications, logs personnels, linter générique. Par projet (.claude/settings.json commité dans le repo) : tests, formatage spécifique au projet, blocks de commandes dangereuses pour l'équipe.
[/faq]
[faq q="Peut-on écrire un hook qui modifie le prompt avant envoi à Claude ?"]
Oui, via l'event UserPromptSubmit (déclenché à la soumission du prompt) : tout ce que le hook écrit sur stdout est injecté dans le contexte de Claude avant traitement. UserPromptExpansion permet aussi d'agir sur l'expansion d'une commande.
[/faq]
[faq q="Un hook peut-il interroger Claude lui-même ?"]
Techniquement oui, tu peux appeler claude --print depuis un hook. Mais c'est un risque de boucle infinie si pas fait avec précaution (imagine un hook qui relance Claude à chaque tool call). À réserver aux cas très spécifiques.
[/faq]
[faq q="Les hooks fonctionnent-ils en mode --dangerously-skip-permissions ?"]
Oui, ils se déclenchent toujours. C'est même une bonne idée de renforcer les hooks PreToolUse si tu utilises ce mode, puisque tu désactives les confirmations manuelles. Un bon garde-fou automatique devient critique.
[/faq]
[faq q="Peut-on partager ses recettes de hooks avec l'équipe ?"]
Absolument. Le fichier .claude/settings.json se commit dans le repo, toute l'équipe a les mêmes hooks automatiquement. Les hooks globaux (~/.claude) restent perso.
[/faq]
[faq q="Existe-t-il un registry de hooks prêts à l'emploi ?"]
Oui, communauté Claude Code actif sur GitHub avec plusieurs repos listant des hooks. Cherche claude-code-hooks ou awesome-claude-code sur GitHub.
[/faq]
[/tutosss-faq]
Pour aller plus loin
- Claude Code : le guide complet 2026, toutes les autres features avancées
- Subagents Claude Code, pour déléguer à des agents spécialisés (complémentaire aux hooks)
- MCP Server : le guide ultime, connecter Claude à des outils externes
Tu as une recette de hook géniale à partager ? Envoie-la à hello@tutosss.com, je l'ajoute au guide avec crédit.