Claude Code Hooks : automatiser votre workflow
Guide complet sur les hooks de Claude Code. Déclenchez des scripts automatiquement avant ou après les actions de Claude pour sécuriser et optimiser votre workflow.
Les hooks, c’est quoi ?
Les hooks sont des commandes shell qui se déclenchent automatiquement à des moments précis du cycle de vie de Claude Code. Avant qu’il modifie un fichier, après qu’il exécute une commande, quand il termine une tâche : vous définissez des règles, Claude Code les exécute sans intervention.
Concrètement, c’est un système d’événements. Vous configurez des scripts qui réagissent aux actions de Claude Code. Quelques exemples de ce que ça permet :
- Lancer Prettier automatiquement après chaque modification de fichier
- Bloquer toute tentative de
rm -rf /ou degit push --force - Exécuter les tests après chaque changement de code
- Envoyer une notification Slack quand Claude Code termine une tâche longue
- Interdire la modification de certains fichiers sensibles
Les hooks transforment Claude Code d’un outil interactif en un workflow automatisé avec des garde-fous.
Types d’événements
Chaque hook se déclenche sur un événement précis. Voici les événements disponibles :
PreToolUse
Se déclenche avant que Claude Code utilise un outil. C’est le point d’interception le plus puissant : vous pouvez inspecter ce que Claude s’apprête à faire et décider de le bloquer ou de le laisser passer.
Cas d’usage :
- Bloquer l’écriture dans des fichiers protégés
- Empêcher l’exécution de commandes dangereuses
- Valider le contenu avant écriture
PostToolUse
Se déclenche après que Claude Code a utilisé un outil avec succès. Idéal pour les actions de post-traitement.
Cas d’usage :
- Formater le code après modification (Prettier, ESLint, Black)
- Lancer les tests après un changement
- Mettre à jour un index ou un cache
Notification
Se déclenche quand Claude Code envoie une notification (typiquement quand il a besoin d’une action de votre part ou qu’il vous informe de quelque chose).
Cas d’usage :
- Rediriger les notifications vers Slack, Discord, ou un webhook
- Logger les notifications dans un fichier
- Déclencher des alertes système
Stop
Se déclenche quand Claude Code termine son tour de réponse principal (la boucle agentique s’arrête).
Cas d’usage :
- Récapituler les changements effectués
- Lancer une suite de tests finale
- Envoyer un résumé par email ou Slack
- Auto-commit des changements
SubagentStop
Se déclenche quand un sous-agent (lancé via la commande /agent ou les tâches parallèles) termine son exécution. Même logique que Stop, mais pour les sous-agents.
Configuration
Les hooks se configurent en JSON, dans les fichiers de settings de Claude Code.
Où placer la configuration
Trois niveaux sont possibles :
| Fichier | Portée | Usage |
|---|---|---|
.claude/settings.json | Projet (versionné) | Hooks partagés avec l’équipe |
~/.claude/settings.json | Utilisateur (global) | Hooks personnels, actifs partout |
.claude/settings.local.json | Projet (non versionné) | Hooks locaux au projet, personnels |
Structure JSON
La configuration suit cette structure :
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "echo 'Fichier sur le point d être modifié'",
"timeout": 10000
}
]
}
]
}
}
Chaque entrée dans un type d’événement contient :
matcher: filtre optionnel pour cibler des outils ou des patterns spécifiques (détaillé plus loin)hooks: tableau de hooks à exécutertype: toujours"command"pour l’instantcommand: la commande shell à exécutertimeout: timeout en millisecondes (par défaut : 60000, soit 60 secondes)
Matchers : cibler les bons événements
Le champ matcher permet de filtrer précisément quand un hook se déclenche. Si vous omettez le matcher, le hook se déclenche pour tous les appels de l’événement correspondant.
Matcher sur le nom de l’outil
Pour PreToolUse et PostToolUse, le matcher correspond au nom de l’outil Claude Code :
{
"matcher": "Write"
}
Les noms d’outils disponibles :
Write: écriture de fichierEdit: modification de fichier (remplacement de texte)Bash: exécution de commande shellRead: lecture de fichierGlob: recherche de fichiers par patternGrep: recherche dans le contenu des fichiersWebFetch: requête HTTPWebSearch: recherche webNotebookEdit: modification de notebook Jupyter
Matcher avec regex
Le matcher supporte les expressions régulières. Par exemple, pour cibler toutes les écritures et modifications :
{
"matcher": "Write|Edit"
}
Ou pour cibler les outils MCP d’un serveur spécifique :
{
"matcher": "mcp__notion__.*"
}
Exemples pratiques
Auto-formater le code après chaque modification
Le hook le plus courant. Après chaque écriture ou modification de fichier, on lance le formateur :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true",
"timeout": 10000
}
]
}
]
}
}
La variable $CLAUDE_FILE_PATH contient le chemin du fichier concerné. Le || true évite qu’une erreur de formatage ne bloque Claude Code.
Pour ESLint avec auto-fix :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npx eslint --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true",
"timeout": 15000
}
]
}
]
}
}
Bloquer la modification de fichiers protégés
Empêcher Claude Code de toucher à certains fichiers critiques :
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_FILE_PATH\" | grep -qE '(\\.env|package-lock\\.json|yarn\\.lock|pnpm-lock\\.yaml)$'; then echo 'BLOCK: Ce fichier est protégé et ne doit pas être modifié par Claude Code' >&2; exit 2; fi",
"timeout": 5000
}
]
}
]
}
}
Le mot-clé BLOCK dans la sortie stderr combiné au code de sortie 2 indique à Claude Code de ne pas exécuter l’action.
Bloquer les commandes dangereuses
Intercepter les commandes Bash risquées avant leur exécution :
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_COMMAND\" | grep -qE '(rm\\s+-rf\\s+/|git\\s+push\\s+--force|git\\s+push\\s+-f|git\\s+reset\\s+--hard)'; then echo 'BLOCK: Commande dangereuse interceptée' >&2; exit 2; fi",
"timeout": 5000
}
]
}
]
}
}
Lancer les tests après un changement de code
Exécuter automatiquement les tests quand Claude modifie un fichier source :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_FILE_PATH\" | grep -qE '\\.(ts|tsx|js|jsx)$' && ! echo \"$CLAUDE_FILE_PATH\" | grep -q 'node_modules'; then npm test -- --bail --findRelatedTests \"$CLAUDE_FILE_PATH\" 2>&1 | tail -20; fi",
"timeout": 30000
}
]
}
]
}
}
Le --findRelatedTests de Jest ne lance que les tests liés au fichier modifié, ce qui garde le hook rapide.
Notification à la fin d’une tâche
Envoyer une notification quand Claude Code termine :
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "curl -s -X POST 'https://hooks.slack.com/services/XXX/YYY/ZZZ' -H 'Content-Type: application/json' -d '{\"text\": \"Claude Code a terminé sa tâche\"}' > /dev/null",
"timeout": 10000
}
]
}
]
}
}
Sur macOS, vous pouvez aussi utiliser une notification système :
{
"type": "command",
"command": "osascript -e 'display notification \"Tâche terminée\" with title \"Claude Code\"'",
"timeout": 5000
}
Sur Linux :
{
"type": "command",
"command": "notify-send 'Claude Code' 'Tâche terminée'",
"timeout": 5000
}
Auto-commit après des changements réussis
Commiter automatiquement les modifications quand Claude Code termine :
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "cd \"$CLAUDE_PROJECT_DIR\" && if [ -n \"$(git status --porcelain)\" ]; then git add -A && git commit -m 'auto: changements appliqués par Claude Code'; fi",
"timeout": 15000
}
]
}
]
}
}
Attention : utilisez ceci avec précaution. Combinez-le avec des hooks de protection sur les fichiers sensibles pour éviter de commiter des secrets.
Communication des hooks
Les hooks communiquent avec Claude Code via trois canaux :
Sortie standard (stdout)
Tout ce que votre hook écrit sur stdout est renvoyé à Claude Code comme contexte utilisateur. Claude voit cette sortie et peut en tenir compte dans ses prochaines actions.
# Le résultat des tests est visible par Claude
npm test 2>&1
C’est utile pour donner du feedback : si les tests échouent, Claude Code voit les erreurs et peut corriger.
Sortie d’erreur (stderr)
La sortie stderr est utilisée pour les messages de blocage. Quand un hook veut empêcher une action :
echo "BLOCK: Raison du blocage" >&2
exit 2
Codes de sortie
| Code | Signification |
|---|---|
0 | Succès, l’action continue |
1 | Erreur non fatale, l’action continue mais l’erreur est signalée |
2 | Blocage : l’action est annulée (surtout pour PreToolUse) |
Le code de sortie 2 est le mécanisme principal pour bloquer une action dans un hook PreToolUse. Claude Code voit le message BLOCK et comprend pourquoi l’action a été refusée.
Variables d’environnement disponibles
Les hooks reçoivent du contexte via des variables d’environnement. Les variables disponibles dépendent de l’événement et de l’outil :
| Variable | Description | Disponible dans |
|---|---|---|
CLAUDE_FILE_PATH | Chemin du fichier concerné | Write, Edit, Read |
CLAUDE_COMMAND | Commande shell à exécuter | Bash |
CLAUDE_PROJECT_DIR | Racine du projet | Tous les hooks |
CLAUDE_TOOL_NAME | Nom de l’outil déclenché | Tous les hooks PreToolUse/PostToolUse |
CLAUDE_TOOL_INPUT | Input JSON complet de l’outil | Tous les hooks PreToolUse/PostToolUse |
Vous pouvez parser CLAUDE_TOOL_INPUT pour accéder à tous les paramètres de l’outil :
# Extraire le chemin du fichier depuis l'input JSON
FILE=$(echo "$CLAUDE_TOOL_INPUT" | jq -r '.file_path // empty')
Débuguer les hooks
Tester un hook manuellement
Avant de configurer un hook, testez-le dans votre terminal :
# Simuler les variables d'environnement
export CLAUDE_FILE_PATH="src/index.ts"
export CLAUDE_COMMAND="npm test"
export CLAUDE_PROJECT_DIR="/home/user/mon-projet"
# Exécuter le hook
bash -c 'if echo "$CLAUDE_FILE_PATH" | grep -qE "\\.env$"; then echo "BLOCK" >&2; exit 2; fi'
echo $? # Doit afficher 0 (pas de blocage pour src/index.ts)
Mode verbose
Lancez Claude Code en mode verbose pour voir l’exécution des hooks :
claude --verbose
Vous verrez dans les logs :
- Quel hook se déclenche
- La commande exécutée
- La sortie du hook
- Le code de retour
Problèmes courants
Le hook ne se déclenche pas
- Vérifiez que le matcher correspond bien au nom de l’outil (respectez la casse :
Write, paswrite) - Vérifiez que le fichier de settings est au bon endroit
- Relancez Claude Code pour recharger la configuration
Le hook se déclenche mais échoue
- Testez la commande manuellement dans votre terminal
- Vérifiez que les outils utilisés (prettier, eslint, jq) sont installés et dans le PATH
- Vérifiez le timeout : un hook trop lent sera tué
Le hook bloque tout
- Vérifiez la logique de votre condition : un
grepsans-qou unexit 2mal placé peut tout bloquer - Ajoutez du logging temporaire :
echo "DEBUG: FILE=$CLAUDE_FILE_PATH" >> /tmp/hooks.log
Bonnes pratiques
Gardez les hooks rapides
Un hook lent ralentit tout le workflow. Visez moins de 5 secondes par hook. Pour les tâches longues (suite de tests complète, build), limitez-vous aux hooks Stop qui ne bloquent pas l’interaction.
Rendez les hooks idempotents
Un hook peut être exécuté plusieurs fois sur le même fichier. Assurez-vous qu’il produit le même résultat à chaque exécution. Prettier est naturellement idempotent (formater un fichier déjà formaté ne change rien). Un hook qui ajoute du contenu à un fichier ne l’est pas.
Gérez les erreurs gracieusement
Ajoutez || true ou 2>/dev/null quand l’échec du hook ne doit pas bloquer Claude Code. Un formateur qui échoue sur un fichier binaire ne devrait pas arrêter le workflow.
# Bon : l'échec est silencieux
npx prettier --write "$CLAUDE_FILE_PATH" 2>/dev/null || true
# Mauvais : un fichier non supporté crashe tout
npx prettier --write "$CLAUDE_FILE_PATH"
Sécurisez les hooks
Les hooks ont accès complet à votre système. Quelques règles :
- Ne mettez pas de secrets dans les commandes (utilisez des variables d’environnement ou des fichiers)
- Validez les entrées :
$CLAUDE_FILE_PATHpourrait contenir des caractères spéciaux - Limitez les permissions : si un hook n’a pas besoin d’écrire, ne lui donnez pas accès en écriture
- Quotez toujours les variables :
"$CLAUDE_FILE_PATH"et non$CLAUDE_FILE_PATH
Versionnez les hooks d’équipe
Mettez les hooks partagés dans .claude/settings.json et versionnez-les dans Git. Chaque membre de l’équipe bénéficie des mêmes protections (fichiers interdits, formatage automatique, commandes bloquées).
Les hooks personnels (notifications, préférences de formatage) vont dans ~/.claude/settings.json ou .claude/settings.local.json.
Combinez les hooks
Les hooks sont plus puissants combinés. Un setup robuste pour un projet TypeScript :
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_FILE_PATH\" | grep -qE '(\\.env|\\.lock)$'; then echo 'BLOCK: Fichier protégé' >&2; exit 2; fi",
"timeout": 5000
}
]
},
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_COMMAND\" | grep -qE '(rm\\s+-rf|--force|--hard)'; then echo 'BLOCK: Commande dangereuse' >&2; exit 2; fi",
"timeout": 5000
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_FILE_PATH\" | grep -qE '\\.(ts|tsx|js|jsx|json|css|md)$'; then npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true; fi",
"timeout": 10000
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "cd \"$CLAUDE_PROJECT_DIR\" && npm test -- --bail 2>&1 | tail -5",
"timeout": 30000
}
]
}
]
}
}
Ce setup protège les fichiers sensibles, bloque les commandes dangereuses, formate automatiquement et lance les tests en fin de session.