Automatiser avec des hooks
Formater après chaque écriture, bloquer une commande dangereuse, notifier en fin de tâche. Sans le demander à chaque fois.
Demander « n'oublie pas de formater » à chaque tâche, c'est une consigne que le modèle peut rater. Un hook, non : c'est le harnais qui l'exécute, pas le modèle qui décide. La distinction change tout dès qu'une règle doit tenir à 100 %.
Le principe
Un hook est une commande shell lancée par Claude Code sur un événement. Elle reçoit le contexte en JSON sur l'entrée standard, et son code de sortie peut bloquer l'action.
| Événement | Se déclenche |
|---|---|
PreToolUse | Avant qu'un outil s'exécute. Peut bloquer |
PostToolUse | Après un outil réussi |
UserPromptSubmit | À chaque message que tu envoies |
Stop | Quand l'agent a fini de répondre |
SessionStart | À l'ouverture d'une session |
Hook ou consigne ?
Consigne pour ce qui demande du jugement. Hook pour ce qui doit arriver à chaque fois, sans exception. « Formate après écriture » est un hook. « Écris du code lisible » n'en sera jamais un.
Avant de commencer
- Claude Code installé
- `jq` installé, pour lire le JSON d'entrée
- Une règle que tu répètes à chaque session
1Formater après chaque écriture
Dans .claude/settings.json :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs -r npx prettier --write"
}
]
}
]
}
}
Le matcher filtre les outils concernés. Le contexte arrive en JSON sur stdin :
jq en extrait le chemin du fichier, xargs le passe au formateur.
xargs -r évite de lancer la commande quand le chemin est vide, ce qui arrive
plus souvent qu'on ne croit.
2Bloquer une commande dangereuse
PreToolUse peut refuser l'action. Un code de sortie différent de zéro annule
l'appel.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.command' | grep -qE 'git push --force|rm -rf /' && { echo 'Commande bloquee par un hook local.' >&2; exit 2; } || exit 0"
}
]
}
]
}
}
Un hook n'est pas une politique de sécurité
C'est un garde-fou contre l'erreur, pas contre un adversaire. Une commande formulée autrement passe à travers. Traite-le comme une ceinture de sécurité, pas comme une serrure.
3Savoir quand c'est fini
Sur les tâches longues, on finit par regarder le terminal au lieu de travailler.
{
"hooks": {
"Stop": [
{
"hooks": [
{ "type": "command", "command": "printf '\\a'" }
]
}
]
}
}
Un bip suffit. Sur macOS, osascript -e 'display notification \"Termine\"'
donne une vraie notification.
4Vérifier que ça se déclenche
Un hook silencieux qui ne part jamais est indiscernable d'un hook qui marche.
Provoque l'événement : demande une modification de fichier pour un
PostToolUse, et vérifie l'effet.
En cas de doute :
claude --debug
Le journal indique quels hooks ont trouvé une correspondance, leur code de sortie et leur sortie.
Où les mettre
| Emplacement | Portée |
|---|---|
.claude/settings.json | Le projet, versionné, partagé avec l'équipe |
.claude/settings.local.json | Le projet, mais toi seulement |
~/.claude/settings.json | Tous tes projets |
hooks/hooks.json d'un plugin | Distribué avec le plugin |
Les pièges
- Un hook lent bloque tout. Il s'exécute dans la boucle. Au-delà d'une seconde ou deux, ça se sent à chaque action.
- Écrire sur stdout. Certains événements interprètent la sortie standard. Les messages destinés à l'humain vont sur
stderr. - Oublier
-rsurxargs. Sans lui, la commande part avec un argument vide et échoue bruyamment. - Trop de hooks. Trois hooks utiles valent mieux que dix qui se marchent dessus. Chacun ajoute de la latence à chaque action.
Tu as d’autres ressources comme ça ?
Ce que tu viens de lire est entièrement gratuit. Une nouvelle ressource part chaque semaine dans la newsletter : guides, modèles à copier et liens triés, sans compte à créer.
Me contacter
Une question, un projet, une envie de collaborer ? Écris-moi.
Cette page est en accès libre, n’hésite pas à la partager.