L'échelle du retour
Si le premier signal d'un agent est une exécution CI rouge vingt minutes après le push — ou une revue humaine le lendemain — chaque erreur coûte un aller-retour complet. La même erreur devient moins coûteuse plus tôt elle est détectée. Les bonnes pratiques de Claude Code le placent en tête de liste : "Donnez à Claude une vérification qu'il peut exécuter : des tests, un build, une capture d'écran à comparer. C'est la différence entre une session que vous surveillez et une dont vous pouvez vous éloigner." [1]
Ce n'est pas nouveau. L'intégration continue a toujours porté sur le retour rapide — Martin Fowler qualifie un build de dix minutes de "parfaitement raisonnable" [9] et DORA décrit la CI comme un retour obtenu en quelques minutes. [10] Les agents ne font que rendre l'aller-retour plus fréquent. Organisez les vérifications comme une échelle :
À chaque modification — agent hooks
Formatez et passez le linter sur le fichier modifié à l'instant où il est écrit : le hook afterFileEdit de Cursor, le hook PostToolUse de Claude Code.
Quand l'agent pense avoir terminé — un stop hook
Exécutez les vérifications ; si elles échouent, renvoyez l'agent au travail. Le stop hook de Cursor peut renvoyer un followup_message ; le hook Stop de Claude Code peut bloquer l'arrêt.
Au commit — un git pre-commit hook
Build, vérification des types, vérification du format, vérification de la complexité. Échouer vite et bloquer le commit.
Au push / à la pull request — CI
Tests complets avec seuils de couverture, linting des workflows.
Avant le merge — la partie coûteuse
Suites end-to-end, revue automatisée, puis un humain.
Cursor et Claude Code documentent tous deux ces hooks. [3] [2] Le tour d'horizon de GitButler montre bien comment les hooks de Cursor se déclenchent en pratique. [4]
Les instructions sont des conseils, les hooks sont des garanties
Une règle dans AGENTS.md, CLAUDE.md ou les règles Cursor est quelque chose que l'agent devrait faire. Un hook qui bloque le commit est quelque chose qu'il ne peut pas éviter. La documentation de Claude Code le dit sans détour :
"Contrairement aux instructions de CLAUDE.md, qui sont consultatives, les hooks sont déterministes et garantissent que l'action a bien lieu." [1]
Placez donc les règles "toujours" dans des hooks. Réservez le fichier d'instructions pour ce qui relève du jugement — comment vous nommez les choses, quels motifs privilégier — et laissez le code imposer le reste. Et précisez dans les instructions de votre agent que --no-verify n'est jamais autorisé, la CI servant de dernier filet pour ce qui passerait quand même.
Écrire des messages d'erreur pour l'agent
Une vérification en échec devrait indiquer quoi faire, pas seulement ce qui ne va pas. "Échec du formatage" envoie l'agent à la recherche ; "Lancez npm run format puis stagez les modifications" se corrige en une étape.
Un exemple tiré de nos propres dépôts : notre vérification de complexité utilise FTA, le Fast TypeScript Analyzer, avec un seuil de 60. L'échelle de FTA elle-même qualifie les scores de "OK", "Pourrait être mieux" et "À améliorer" — sa documentation montre 64.17 comme "À améliorer". [8] Quand un fichier dépasse le seuil, la vérification ne se contente pas d'échouer — elle imprime un brief de refactorisation prêt à l'emploi désignant le pire fichier :
✖ FTA score 71.4 > 60 in src/billing/invoice.ts
Refactor brief:
1. Plan first: list the responsibilities in this file.
2. Separate routing, business logic and data access.
3. Keep behavior unchanged — no new features.
4. Re-run: npm run complexity
5. Then: npm run format && npm run typecheckL'agent lit cela et corrige le problème dans la même exécution. Le message est le prompt le moins cher que vous écrirez jamais, car il arrive exactement quand il faut.
Garder le commit hook rapide
Des secondes, pas des minutes. Un hook lent apprend aux agents — et aux humains — à le contourner. Ne lintez et ne formatez que les fichiers commités : c'est exactement à cela que sert lint-staged, qui exécute des tâches uniquement sur les fichiers en staging. [7] Des gestionnaires de hooks comme Husky font du hook une partie du dépôt, afin qu'il s'installe avec le projet. [6]
Repoussez tout ce qui est lent plus haut dans l'échelle. Dans la CI, annulez les exécutions qu'un push plus récent a rendues obsolètes avec cancel-in-progress: true [11] et imposez la couverture avec des seuils — fixez un seuil de lignes à 90 et l'exécution échoue en dessous de 90 %. [12]
Vérifier que les hooks s'exécutent vraiment dans l'environnement de l'agent
Git cherche les hooks dans .git/hooks par défaut, mais core.hooksPath peut pointer ailleurs. [5] Nous l'avons appris à nos dépens : dans nos environnements Cursor Cloud Agent, core.hooksPath pointait vers le propre répertoire de hooks de l'agent, qui chaînait ensuite vers .git/hooks. Husky dépend lui aussi de core.hooksPath — notre barrière de pre-commit a donc cessé de s'exécuter silencieusement.
Notre solution a été un petit script qui écrit .git/hooks/pre-commit pour chaîner vers le hook Husky, exécuté à l'installation et à chaque démarrage de l'environnement. Cursor exécute désormais aussi des hooks de projet dans les cloud agents : "Cloud agents run command-based hooks from your repository" via .cursor/hooks.json. [3]
Quelle que soit la voie choisie, vérifiez-la : dans l'environnement de l'agent, faites un commit censé échouer et assurez-vous qu'il échoue bien.
Exemple : une configuration gate-zero
Voici la forme que nous utilisons dans chaque dépôt. Une barrière de pre-commit avec build → vérification des types → vérification du format → vérification de la complexité, échouant à la première erreur avec une piste de correction en une ligne. La CI exécute ensuite le lint, les tests avec seuils de couverture (95 % de statements, lines et functions) et le linting des workflows. Les tests end-to-end ne s'exécutent que sur les pull requests étiquetées prêtes à fusionner.
{
"version": 1,
"hooks": {
"afterFileEdit": [{ "command": "./scripts/hooks/format-changed.sh" }],
"stop": [{ "command": "./scripts/hooks/gate.sh", "loop_limit": 3 }]
}
}Un stop hook renvoie l'agent en imprimant un followup_message, pas en échouant ; loop_limit limite le nombre de fois où cela peut arriver (la valeur par défaut de Cursor est 5). [3]
#!/bin/sh
# Cursor stop hook: run the checks; if they fail, send the agent back with the output.
if ! out=$(npm run --silent check 2>&1); then
msg=$(printf 'Checks failed. Fix these before finishing:\n%s' "$out")
jq -n --arg msg "$msg" '{followup_message: $msg}'
fiafterFileEdit reçoit le chemin du fichier modifié en JSON sur stdin (file_path), donc format-changed.sh devrait le lire de là — par exemple avec jq -r .file_path.
npm run build || { echo "Build failed. Fix the errors above."; exit 1; }
npm run typecheck || { echo "Type errors. Fix them before committing."; exit 1; }
npm run format:check || { echo "Run \"npm run format\" then stage the changes."; exit 1; }
npm run complexity # prints a refactor brief when a file scores > 60Notre barrière exécute un build et une vérification des types pour tout le projet car les deux sont rapides dans nos dépôts. Si les vôtres prennent plus de quelques secondes, déplacez-les vers le stop hook ou la CI et limitez le pre-commit aux fichiers en staging.
Considérez les scripts comme un point de départ, pas une solution clé en main. Le schéma compte plus que les outils : les mêmes vérifications, à chaque échelon, de plus en plus lentes et approfondies à mesure que l'on monte.
Où intervient Aerunit
Des vérifications rapides déterminent combien d'allers-retours prend une pull request, et les allers-retours déterminent combien d'agents vous pouvez occuper en parallèle. Les stories d'Aerunit portent la définition du "terminé" — y compris les vérifications qui doivent passer — afin que l'agent connaisse la barre avant de commencer. Quand l'agent ouvre une PR, Aerunit la revoit automatiquement et peut renvoyer les résultats à la session de l'agent : le dernier échelon automatisé avant qu'un humain ne regarde.
Les conventions d'équipe — comme "ne jamais utiliser --no-verify" ou "lancer la vérification de complexité avant de commiter" — vivent une seule fois dans le contexte et les skills partagés d'Aerunit et alimentent chaque story et chaque exécution. Plus de détails sur ce dernier échelon dans notre guide sur la revue des pull requests d'agents.
Terminé, défini
Les stories indiquent quelles vérifications doivent passer avant que l'agent ne commence.
Revue automatique
Chaque PR d'agent est revue, les résultats renvoyés à la même session.
Conventions partagées
Des règles comme "ne jamais utiliser --no-verify" écrites une fois et injectées dans chaque story et exécution.
Questions fréquentes
Les pre-commit hooks ne ralentissent-ils pas l'agent ?
Seulement s'ils sont lents. Gardez le commit hook à quelques secondes : vérifiez uniquement les fichiers en staging et laissez la suite de tests complète à la CI. Un hook rapide fait gagner du temps, car l'agent corrige le problème dans la même exécution au lieu d'attendre une CI rouge et de repousser. [7]
Pre-commit hook ou agent hook — lequel choisir ?
Les deux, pour des rôles différents. Les agent hooks (afterFileEdit et stop de Cursor, PostToolUse et Stop de Claude Code) donnent un retour pendant l'exécution. Un git pre-commit hook protège le commit pour tout auteur, humain ou agent. La CI est le dernier filet pour tout ce qui contourne les deux. [3] [2]
Que ne doit-on jamais mettre dans un pre-commit hook ?
Tout ce qui est lent, instable ou dépendant du réseau : suites end-to-end, builds complets de paquets non liés, appels à des services externes. Cela relève d'un échelon supérieur — la CI, ou seulement quand une pull request est marquée prête à fusionner.
Comment faire fonctionner les mêmes vérifications pour les humains et les agents ?
Placez les vérifications dans le dépôt, pas dans un outil isolé : scripts du package, un git hook installé à la configuration, et une CI qui exécute les mêmes commandes. Les agent hooks et les commits humains appellent alors les mêmes scripts, et personne n'a de version privée des règles.
Sources
- [1]Claude Code Docs — Best practices
- [2]Claude Code Docs — Hooks guide
- [3]Cursor Docs — Hooks
- [4]GitButler (vendor blog) — Cursor hooks deep dive
- [5]Git — githooks documentation
- [6]Husky — Git hooks made easy
- [7]lint-staged — Run tasks against staged files
- [8]FTA — Fast TypeScript Analyzer
- [9]Martin Fowler — Continuous Integration
- [10]DORA — Continuous integration capability
- [11]GitHub Docs — Control workflow concurrency
- [12]Vitest — Coverage configuration