Les règles de lint sont du context engineering appliqué à la base de code
2 mars 2026 · 9 min de lecture
J'ai déployé ce motif dans chacune des entreprises où j'ai travaillé et sur chaque projet que je pilote pour mes clients. Il fonctionne à chaque fois. Voici pourquoi.
Le problème des instructions par prompt#
CLAUDE.md, .cursorrules, copilot-instructions.md, agent.md. Chaque outil de code assisté par IA a sa version de « écrivez vos conventions ici et le modèle les suivra ».
Vous écrivez : « Valide toujours les entrées des routes d'API avec Zod avant de traiter la requête. »
L'IA lit. Acquiesce. Puis écrit ceci quand même :
// routes/users.ts
app.post('/users', async (req, res) => {
const { email, role } = req.body // brut, non validé
await UserService.create({ email, role })
})Vous ajoutez une instruction : « N'écris jamais de requêtes base de données en dehors de la couche de requêtes. »
Même résultat :
// user.service.ts
const user = await db.selectFrom('user').where('id', '=', id).selectAll().executeTakeFirst() // mauvaise couchePourquoi ? Parce que vos instructions entrent en concurrence avec des millions de points de données issus de dépôts publics qui font exactement cela. Elles perdent. À chaque fois.
Une règle de lint n'entre pas en concurrence. Elle impose.
L'économie de la fenêtre de contexte#
Chaque ligne de votre fichier d'instructions consomme des tokens dans la fenêtre de contexte de l'agent. À chaque tour. Que ces instructions soient pertinentes pour la tâche en cours ou non.
Cette fenêtre de contexte est la ressource la plus précieuse dont dispose votre agent. Elle doit contenir la tâche, les fichiers pertinents, l'historique de la conversation — ce qui pilote réellement la qualité de la sortie. Vos trente lignes de règles d'architecture chargées à chaque tour ? Elles entrent en concurrence avec le code sur lequel l'agent essaie de raisonner.
Les règles de lint ne coûtent rien en contexte. Elles vivent entièrement en dehors de l'agent. Le seul moment où elles touchent la fenêtre de contexte, c'est quand elles se déclenchent — et le message d'erreur est alors chirurgical : ciblé sur la violation exacte, actionnable, autonome. Pas un mur de règles que l'agent doit filtrer mentalement à chaque tour.
Les sous-agents en profitent encore davantage. Quand votre agent de code lance des sous-tâches, ces sous-agents héritent automatiquement de la configuration de lint du projet. Aucun contexte à faire suivre. Aucune dilution. Les contraintes d'architecture voyagent avec la chaîne d'outils, pas avec le prompt.
C'est cela, le harness engineering. Vous n'écrivez pas de meilleures instructions : vous concevez l'environnement pour que l'agent se corrige via sa propre boucle de feedback. La fenêtre de contexte reste concentrée sur l'essentiel. L'infrastructure de lint s'occupe du reste.
Le vrai coût de l'absence de garde-fous#
Une IA sans gouvernance n'est pas seulement inconstante. C'est un accélérateur de dette technique.
Chaque tâche que l'IA termine sans contrainte rend la suivante plus difficile. Structures de dossiers incohérentes. Appels bruts à req.body éparpillés sur quarante routes. Requêtes qui fuient dans les contrôleurs. Chaque violation devient un nouveau motif que l'IA réplique, parce qu'elle lit votre base de code comme un signal pour la complétion suivante.
Le calcul est brutal : plus vous laissez dériver, plus elle s'ancre dans la dérive.
Une base de code homogène inverse cette dynamique. Quand chaque fichier suit la même structure, que chaque route valide de la même façon et que chaque requête vit au même endroit, l'IA fait correspondre ses motifs à vos conventions au lieu de lutter contre elles. Sa sortie devient plus rapide et plus propre à chaque tâche.
Cela vaut aussi pour les humains. Un nouvel ingénieur rejoint l'équipe, lit un fichier de service, et sait comment fonctionnent tous les autres. Les erreurs de lint qu'il rencontre dès le premier jour lui enseignent les conventions plus vite que n'importe quel document d'onboarding. La base de code devient auto-enseignante, pour les humains comme pour les agents.
Les règles de lint sont ce qui rend cette homogénéité applicable. Pas seulement souhaitable.
De bout en bout : ce que ça donne en pratique#
Voici la boucle complète, de la sortie de l'IA au diff propre.
Étape 1. L'IA génère une nouvelle route :
router.post('/users', async (req, res) => {
const user = await db.selectFrom('user').where('id', '=', req.body.id).selectAll().executeTakeFirst()
res.json(user)
})Étape 2. ESLint déclenche deux erreurs simultanément :
ESLint: 'POST /users' is missing the validateRequest middleware.
ESLint: Direct database queries are not allowed here. Create a dedicated query file.Étape 3. L'IA lit les deux messages et se corrige : elle crée un fichier de requêtes dédié, ajoute un contract.ts avec les schémas appropriés, et branche validateRequest sur la route. Aucun prompt humain nécessaire.
Étape 4. ESLint tourne à nouveau. Zéro erreur. Le diff est fusionnable.
Aucun commentaire de revue. Aucun second prompt. Aucun humain dans la boucle.
Laissez l'agent nettoyer l'existant#
Une fois la règle branchée sur la CI, vous n'avez pas à corriger manuellement les violations existantes. Vous pointez un agent de code sur la sortie du linter et vous lui demandez de tout corriger.
Lance eslint --format json. Pour chaque erreur, corrige la violation pour
respecter le motif attendu décrit dans le message d'erreur. Ne change
aucune logique métier. Ne corrige que ce que le linter signale. Relance
eslint après chaque correction pour confirmer que l'erreur est résolue
avant de passer à la suivante.Cela fonctionne parce que les erreurs de lint sont une boucle de feedback parfaite pour un agent : déterministes, cadrées, auto-descriptives. L'agent n'a pas besoin de comprendre votre architecture. Il lui suffit de suivre la contrainte jusqu'à ce que la sortie soit verte.
Vous introduisez une nouvelle règle sur une base de code comptant soixante violations. Vous lancez Claude Code avec l'instruction ci-dessus. Soixante erreurs. Moins d'une heure. Zéro restante. Chaque fichier corrigé, CI au vert, sans qu'un humain ait touché une seule ligne.
Ce qui aurait pris à un ingénieur senior une journée entière de travail minutieux et fastidieux prend à un agent moins d'une heure. Avec une meilleure cohérence. Et une barrière de CI qui le prouve.
Cela change l'économie de l'introduction de nouvelles règles. L'objection habituelle à l'ajout d'une règle stricte sur une base de code existante, c'est le backlog qu'elle crée : des centaines de violations, pas le temps de les corriger, la règle reste en warn pour toujours, personne ne la respecte.
Avec un agent, ce backlog n'est plus une raison de temporiser. C'est juste une tâche. Écrire la règle. Lancer l'agent. Fusionner la PR de nettoyage. Passer en error. Terminé.
L'objection que j'entends toujours : « Écrire des règles de lint prend du temps. »#
Voilà l'ironie : c'est l'IA qui les écrit.
Tu es ingénieur en règles ESLint. Je vais décrire une contrainte de code
que je veux imposer dans ma base de code. Ton travail consiste à :
1. Écrire une règle ESLint personnalisée complète et fonctionnelle, au
format CommonJS, avec un bloc meta correct et un module.exports
2. Inclure la logique de la règle et un message d'erreur clair et actionnable
3. Ajouter un correcteur automatique quand la correction est sans ambiguïté
4. Ajouter un fichier RuleTester avec des cas valides et invalides
Contrainte à imposer : [décrivez-la en français courant]Décrivez votre contrainte en une phrase. Récupérez une règle fonctionnelle en un tour. Il faudra parfois itérer sur les cas limites : gestion des chemins en monorepo, imports dynamiques, motifs de composition de middlewares. Mais la structure et la logique sont faites. La partie difficile prend trente secondes. Le reste est du réglage.
L'outil qui gouverne l'IA est construit par l'IA. Le seul effort qui reste est le vôtre : remarquer le problème une fois.
Les règles de lint sont de la documentation vivante#
Chaque règle que vous écrivez est une documentation versionnée et exécutable. Elle vit dans votre dépôt. Elle évolue avec votre architecture. Elle ne peut pas devenir obsolète, parce qu'une règle obsolète casse le build et force sa mise à jour.
Comparez cela à une page de wiki, une section de README ou un fichier d'instructions qui s'éloigne discrètement de la réalité la semaine suivant sa rédaction.
Quand un nouvel ingénieur — ou un agent — demande « comment structure-t-on les requêtes ici ? », la réponse n'est pas enterrée dans un document. Elle est dans la règle qui se déclenche à l'instant où il se trompe.
Par où commencer#
Passez en revue vos vingt dernières revues de code. Pour chaque commentaire, demandez-vous : s'agit-il d'une violation de convention ou d'un problème de logique ?
Les violations de convention sont des candidates à une règle de lint. Les problèmes de logique demandent du jugement humain.
Chaque commentaire de convention qui revient au moins deux fois est une règle qui vaut la peine d'être écrite. Collez-le dans le prompt ci-dessus. Branchez la règle sur la CI. Ce commentaire ne réapparaîtra plus jamais en revue.
Commencez en warn. Mesurez la fréquence. Passez en error. Livrez.
Le vrai basculement#
Les instructions par prompt ne sont pas inutiles. CLAUDE.md, .cursorrules, copilot-instructions.md, agent.md : c'est le bon endroit pour le ton, le style, les préférences de workflow, et tout ce qui n'est pas analysable statiquement. Servez-vous-en pour ça.
Mais l'application des conventions ? Les contraintes d'architecture ? Ce n'est pas une préférence. C'est un contrat.
Votre fichier d'instructions dit à l'IA ce que vous préférez.
Les règles de lint lui disent ce qui n'est pas négociable.
L'un se fait ignorer sous pression. L'autre ne compile pas.
L'un brûle des tokens de contexte à chaque tour. L'autre ne coûte rien tant qu'il n'a pas d'importance.
La barrière à l'écriture de ces règles a disparu. L'IA écrit les règles. L'agent se charge du nettoyage. Il ne vous reste qu'un travail : remarquer le problème une fois.
La règle s'en occupe pour toujours.
Si vous avez lu jusqu'ici, prenons contact ! N'hésitez pas à me suivre et à m'écrire en DM : https://x.com/AxelVincent_