Des règles aux hooks : arrêtez de demander à l’IA, imposez
Les instructions disent à un agent de code IA ce qu’il ne doit pas faire. Les hooks garantissent qu’il ne le peut pas. Quoi mettre où, un exemple minimal, et pourquoi tester le garde-fou.
Par Tenovates6 min de lecture
Rédigé en septembre 2026 · Claude Code
Disponible en anglais
Le problème
Toute équipe qui travaille avec un agent de code IA finit par écrire une
liste de règles. Ne jamais forcer un push. Ne jamais modifier le fichier
d’environnement de production. Toujours lancer les tests avant de dire que
c’est fini. L’endroit naturel pour les écrire, c’est le fichier
d’instructions que l’agent lit au début de chaque session — CLAUDE.md
pour Claude Code, AGENTS.md pour d’autres.
Ça marche. La plupart du temps.
Et « la plupart du temps », c’est justement le problème. Une règle respectée quatre-vingt-dix-neuf fois sur cent finira par être enfreinte le jour où elle compte : une longue session, un contexte résumé, une tâche formulée de telle sorte que la commande interdite ressemble à l’étape évidente. Personne n’a été négligent. La règle n’a simplement jamais été imposée — seulement demandée.
Pourquoi les instructions ne suffisent pas
Un fichier d’instructions, c’est du contexte. Le modèle le lit, le pèse face à tout ce qu’il a lu d’autre, et décide. C’est exactement ce qu’on veut pour des consignes : conventions, préférences, organisation du projet. Ce n’est pas ce qu’on veut pour la poignée d’actions qui ne doivent jamais se produire, quel que soit le contexte.
Pour celles-là, il faut quelque chose qui s’exécute en dehors du jugement du modèle : une vérification qui tourne à chaque fois, et dont la réponse ne se discute pas.
Claude Code en propose deux :
- Les permissions — des règles dans
.claude/settings.jsonqui font qu’une commande demande d’abord votre accord, ou qui l’interdisent. - Les hooks — de petits programmes lancés à des moments précis : avant l’utilisation d’un outil, après son exécution, quand l’agent s’apprête à s’arrêter. Un hook peut bloquer l’action et dire à l’agent pourquoi.
Quoi mettre où
| Type de règle | Où la placer | Pourquoi |
|---|---|---|
| « On utilise les tokens Tailwind, pas des couleurs brutes » | Instructions | Jugement, style, contexte |
| « Un push passe par un humain » | Permission : ask |
Légitime, mais pas en solo |
| « Ne jamais réinitialiser la base » | Hook (ou permission : deny) |
Ne doit jamais arriver |
« Jamais de --force dans un push » |
Hook | Un motif qu’une permission ne sait pas exprimer |
| « Les tests passent avant “terminé” » | Hook d’arrêt | Tourne à chaque fois, pas quand on y pense |
Un bon test : si enfreindre la règle une seule fois vous coûtait une journée, elle ne doit pas vivre uniquement dans les instructions.
Un exemple minimal
Les permissions couvrent les cas simples. Les commandes qui commencent par un préfixe donné demanderont une confirmation :
{
"permissions": {
"ask": ["Bash(git push:*)", "Bash(npm install:*)"]
}
}
Un hook couvre ce qu’un préfixe ne sait pas faire — une option qui peut
apparaître n’importe où dans la commande. On l’enregistre pour l’outil
Bash :
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "node .claude/hooks/guard.mjs" }]
}
]
}
}
Le hook reçoit l’appel d’outil en JSON sur son entrée standard. Le code de
sortie 2 bloque l’appel, et ce qu’il écrit sur la sortie d’erreur est
montré à l’agent comme explication :
// .claude/hooks/guard.mjs
let input = "";
for await (const chunk of process.stdin) input += chunk;
const command = JSON.parse(input).tool_input?.command ?? "";
const rules = [
[/\bgit\s+push\b.*\s(--force|-f)\b/, "Force-push is not allowed. Push normally or ask."],
[/\s--no-verify\b/, "Don't skip the checks: fix what they report."],
];
for (const [pattern, reason] of rules) {
if (pattern.test(command)) {
console.error(`Blocked: ${reason}`);
process.exit(2);
}
}
process.exit(0);
L’agent ne se contente pas d’échouer : il lit la raison et s’adapte — en général en faisant ce qu’il fallait faire.
La même idée fonctionne en fin de tâche. Un hook sur l’événement Stop
peut lancer vos tests et refuser que l’agent termine tant qu’ils échouent.
Prévoyez une porte de sortie : l’entrée du hook indique quand l’agent
réessaie déjà après un blocage (stop_hook_active). Bloquez une fois, et
à la deuxième tentative laissez-le s’arrêter, mais en l’obligeant à dire
que le travail n’est pas terminé — sinon un échec impossible à
corriger devient une boucle infinie.
Testez le garde-fou, pas seulement ce qu’il protège
Un hook est du code, et le code a des bugs. Le type le plus dangereux, c’est un garde-fou qui échoue en laissant passer : il s’exécute, ne dit rien, et l’action interdite passe. Vous ne le remarquerez pas, car un garde-fou silencieux ressemble exactement à un garde-fou qui n’a rien à signaler.
Deux pièges à connaître :
- Les chemins ont plusieurs formes. Sous Windows, un même fichier peut
arriver à votre hook sous la forme d’un chemin avec lettre de lecteur et
barres obliques inverses, ou sous forme Unix,
/c/project/.env. Une vérification qui compare avec une seule forme rate l’autre en silence. Vérifiez ce qui compte vraiment — le nom du fichier, le motif du dossier — plutôt qu’un chemin relatif à une racine qui peut s’écrire autrement. - Les outils résument.
git status --porcelainaffiche un dossier tout neuf sur une seule ligne,?? dossier/, sans les fichiers qu’il contient. Un hook qui cherche des fichiers de code modifiés n’en verra aucun — à moins de les demander avec--untracked-files=all.
La solution est la même dans les deux cas : testez le hook comme n’importe quel programme. Donnez-lui le JSON qu’il recevra, et vérifiez le code de sortie — pour les commandes qui doivent être bloquées et pour celles qui doivent passer :
echo '{"tool_input":{"command":"git push --force origin main"}}' | node .claude/hooks/guard.mjs
echo $? # attendu : 2
echo '{"tool_input":{"command":"git push origin main"}}' | node .claude/hooks/guard.mjs
echo $? # attendu : 0
Le deuxième cas compte autant que le premier. Un garde-fou qui bloque tout sera désactivé par la première personne agacée qui le rencontre.
À retenir
Les instructions guident un agent ; les hooks et les permissions l’encadrent. Gardez le fichier d’instructions pour le jugement et les conventions. Placez les quelques règles qui ne doivent jamais être enfreintes là où l’agent ne peut pas les contourner — et testez ces garde-fous avec le même soin que le code qu’ils protègent.
Check-list
Passer une règle des instructions à une garantie
1. L’enfreindre une fois coûterait-il une journée ou plus ? → l’imposer
2. Est-ce un préfixe de commande (push, install, deploy) ? → permission : ask / deny
3. Est-ce un motif n’importe où dans une commande ou un chemin ? → hook PreToolUse
4. Est-ce « doit être vrai avant de terminer » ? → hook Stop, avec limite de tentatives
5. Tester chaque garde-fou avec des entrées à bloquer ET des entrées à laisser passer
6. Garder aussi la règle dans les instructions — expliquée — pour que l’agent sache pourquoi