Aller au contenu
Développement medium

Claude Code : hooks pour automatiser lint, tests et garde-fous

9 min de lecture

Logo Claude Code - hooks pour automatiser lint et tests

Le rituel ruff + pytest repose sur votre vigilance : vous le lancez à la main, et un oubli casse la boucle. Les hooks Claude Code déclenchent des commandes shell autour des événements de la session (PreToolUse, PostToolUse, Stop, etc.). Vous pouvez exécuter ruff automatiquement après chaque Edit, bloquer rm -rf avant qu’il ne parte, ou notifier qu’une édition a laissé des erreurs de lint — sans dépendre de votre attention.

  • Configurer un hook PostToolUse qui lance ruff après chaque Edit/Write
  • Configurer un hook PreToolUse qui bloque une commande destructive
  • Choisir le bon événement et le bon matcher
  • Lire les codes de sortie pour informer, bloquer ou ignorer

Dans quel contexte utiliser cette fonctionnalité ?

Section intitulée « Dans quel contexte utiliser cette fonctionnalité ? »
  • Vous voulez un rituel déterministe, pas seulement conseillé
  • Vous partagez un projet avec une équipe et voulez garantir que le lint tourne
  • Vous voulez interdire systématiquement une commande (pas juste refuser en live)
  • Vous voulez notifier un événement (ex : un test cassé) sans bloquer

La doc officielle liste beaucoup d’événements. Pour un démarrage pragmatique, concentrez-vous sur ceux-ci :

ÉvénementSe déclencheExemple d’usage
PreToolUseAvant l’exécution d’un outil, peut bloquerInterdire rm -rf, bloquer les curl non whitelistés
PostToolUseAprès exécution réussie d’un outilLancer ruff check après Edit ou Write
PostToolUseFailureAprès échec d’un outilLoguer ou notifier un échec
StopQuand Claude termine son tourLancer pytest -q en fin de session
SessionStartAu démarrage d’une sessionAfficher l’état git courant

Les hooks vivent sous la clé hooks du settings.json. Chaque événement contient une liste d’entrées {matcher, hooks} :

{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "uv run ruff check .",
"timeout": 30
}
]
}
]
}
}

Explication rapide :

  • matcher : filtre sur le nom de l’outil (Edit, Write, Bash, etc.). Edit|Write = l’un ou l’autre
  • type: "command" : exécuter une commande shell
  • command : la commande à lancer
  • timeout : optionnel, en secondes

Objectif : deux hooks utiles immédiatement — lint automatique après édition et blocage systématique des commandes destructives.

  1. Éditez .claude/settings.json et ajoutez la section hooks

    {
    "$schema": "https://json.schemastore.org/claude-code-settings.json",
    "permissions": {
    "allow": ["Bash(uv run ruff check *)", "Bash(uv run pytest *)"],
    "deny": ["Bash(rm -rf *)", "Read(./.env)"]
    },
    "hooks": {
    "PostToolUse": [
    {
    "matcher": "Edit|Write",
    "hooks": [
    {
    "type": "command",
    "command": "uv run ruff check .",
    "timeout": 30
    }
    ]
    }
    ]
    }
    }
  2. Validez la syntaxe JSON

    Fenêtre de terminal
    python3 -c "import json; json.load(open('.claude/settings.json'))" && echo "JSON valide"
  3. Testez dans une session

    Faites-lui modifier un fichier Python. Après l’Edit, ruff check . tourne automatiquement, et le résultat revient dans la conversation.

Un deny dans permissions couvre déjà rm -rf, mais un hook PreToolUse permet d’ajouter un message explicite et de centraliser la politique :

{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash -c 'input=$(cat); echo \"$input\" | grep -qE \"rm -rf|rm -fr\" && { echo \"rm -rf bloque par hook\" >&2; exit 2; } || exit 0'"
}
]
}
]
}
}

Ce qui se passe :

  • Le hook reçoit l’entrée de l’outil sur stdin (JSON)
  • S’il détecte rm -rf, il sort avec exit 2 et un message sur stderr
  • Exit code 2 = Claude voit ça comme un blocage et ne lance pas la commande
Exit codeEffet
0Succès, le tour continue normalement
2Blocage explicite, stderr est renvoyé à Claude comme feedback
autreErreur non bloquante, signalée dans la session

Règle simple :

  • Vous voulez informer sans bloquer → exit 0 et écrire sur stdout
  • Vous voulez bloquer avec un message → exit 2 et écrire sur stderr
MatcherDéclenche sur
"*" ou omisTous les outils
"Edit"Uniquement l’outil Edit
"Edit|Write"Edit ou Write
"Bash"Toutes les commandes shell
"^Notebook"Regex : tous les outils commençant par Notebook
BesoinBon endroit
Interdire complètement une commandepermissions.deny dans settings.json
Déclencher automatiquement autour d’un événementHook
Enchaîner une procédure invoquée à la mainSkill
Conseiller une convention de codeRule ou CLAUDE.md

Les hooks sont le seul mécanisme déterministe : CLAUDE.md, rules et skills sont du contexte, les hooks sont du code exécuté.

SymptômeCause probableCorrection
Le hook ne se déclenche pasMauvais event ou matcher trop strictTester avec "matcher": "*" puis resserrer
timeout atteintCommande trop lente (ex : pytest complet après chaque Edit)Déclencher pytest sur Stop plutôt que sur chaque édition
Blocage non compris par ClaudeExit code autre que 2Utiliser exit 2 pour bloquer explicitement
Hook exécuté trop souventMatcher trop largePréciser "Edit|Write" plutôt que "*"
rm -rf passe quand mêmeHook shell mal quotéVérifier que la commande utilise bien stdin et un grep correct
  • J’ai au moins un hook PostToolUse fonctionnel sur Edit|Write
  • J’ai validé la syntaxe JSON de settings.json
  • J’ai testé un hook bloquant avec exit 2 et un message
  • Je sais où mettre un hook (automatisme) vs un skill (procédure manuelle)
  • Les hooks de validation lourde sont sur Stop, pas sur chaque Edit
  • Les hooks sont le seul garde-fou déterministe de Claude Code
  • PostToolUse + matcher Edit|Write = rituel lint automatique
  • PreToolUse + exit 2 = blocage avec message
  • Gardez les hooks rapides, sinon vous fatiguez la session
  • CLAUDE.md conseille, settings.json autorise, les hooks exécutent

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn