惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
有赞技术团队
有赞技术团队
IT之家
IT之家
博客园 - 聂微东
Jina AI
Jina AI
Hugging Face - Blog
Hugging Face - Blog
Last Week in AI
Last Week in AI
Apple Machine Learning Research
Apple Machine Learning Research
WordPress大学
WordPress大学
小众软件
小众软件
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
Visual Studio Blog
雷峰网
雷峰网
酷 壳 – CoolShell
酷 壳 – CoolShell
阮一峰的网络日志
阮一峰的网络日志
宝玉的分享
宝玉的分享
博客园 - 三生石上(FineUI控件)
大猫的无限游戏
大猫的无限游戏
博客园 - Franky
量子位
月光博客
月光博客
博客园 - 【当耐特】
博客园 - 叶小钗

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
4 incidents, 4 règles : comment mon CLAUDE.md s'est écrit...
Michel Faure · 2026-04-28 · via DEV Community

Si tu as 30 secondes. Un CLAUDE.md efficace ne documente pas, il contraint — chaque règle répond à une fois où l'agent s'est trompé. Cet article donne la structure à quatre couches que j'utilise pour un ERP de 91 000 lignes (CLAUDE.md racine, AGENTS.md, .claude/rules/ par module, skill auto-invoqué), quatre règles opérantes tirées d'incidents datés, et une discipline tenable : écrire l'interdit avant la bonne pratique. Utile si tu pilotes du code avec Claude Code au quotidien et que tu vois ton agent dériver.


Pourquoi pas juste un README

On me demande pourquoi je ne mets pas simplement dans le README ce qui est dans CLAUDE.md. Les deux fichiers n'ont pas le même destinataire. Le README s'adresse à un humain qui le lira une fois, au démarrage, et s'en souviendra selon ses moyens. Le CLAUDE.md s'adresse à un agent qui le relit à chaque session, qui n'a pas de mémoire entre deux sessions, et qui prendra chaque phrase au pied de la lettre. Le README documente, le CLAUDE.md contraint. Pas de paragraphes introductifs, pas de storytelling. Des règles denses formulées pour être lues hors contexte, avec une séparation stricte entre ce qui est autorisé, ce qui est interdit, et ce qui demande une validation humaine.

Version initiale, quarante lignes de naïveté

Le premier CLAUDE.md de Rembrandt, posé le 21 mars 2026, tenait dans une page d'écran. Stack, commandes, arborescence, quelques conventions évidentes du type « Server Components par défaut ». Ce qui me frappe en le relisant, ce n'est pas ce qu'il contient, mais ce qu'il ne contient pas. Rien sur ce que l'agent allait se tromper à faire les jours suivants. Nous écrivons ce que nous savons déjà, alors que la valeur du fichier vient précisément de ce que nous ne savons pas encore. Les règles utiles ne pouvaient pas être formulées au jour 1, parce qu'elles ont été produites par des incidents qui n'avaient pas encore eu lieu.

Quatre incidents, quatre règles

1. Server Component + onClick, le crash silencieux

Jour 4. Catherine passe la tête dans le bureau. « Michel, j'ai cliqué sur le bouton d'émargement et rien. Pas d'erreur, pas de rouge, rien. » Elle ne me dit pas « ça plante », elle me dit « rien ne se passe », ce qui pour un bouton est précisément pire.

Je rouvre la page. Le build TypeScript est vert, Turbopack ne remonte rien, le crash n'apparaît qu'au rendu serveur en prod, avec un message sibyllin, Event handlers cannot be passed to Client Component props, ERROR 3637204658. Nous avons tous tendance à chercher la cause dans le composant qui crashe, et c'est là que le piège se referme. L'erreur vient d'un <select onChange={() => {}}> dans le Server Component parent, pas dans le composant client qu'on suspecte. La phrase de Catherine a produit la règle, ajoutée au CLAUDE.md dès le lendemain.

- Server Components par défaut, `'use client'` uniquement si état interactif requis

Enter fullscreen mode Exit fullscreen mode

Elle paraît anodine écrite comme ça. Pourtant elle porte la cicatrice d'un bouton qui n'a pas répondu à Catherine.

2. RLS + mauvais client Supabase, zéro ligne sans erreur

25 mars. Françoise m'appelle du bureau d'à côté, elle crie. « Bon. Tes inscriptions sur Maisons-Laffitte, il y en a combien ? Moi j'en vois zéro. » J'ouvre la même page sur mon poste, je vois zéro aussi. « Il y a un moment où il faut y aller, parce que là je peux pas pointer. »

Nous venons d'activer RLS sur dix-huit tables. Les policies sont écrites, testées en SQL direct, tout passe. Déploiement en prod. Toutes les pages affichent zéro ligne. Pas d'exception, pas de 500, pas de log d'erreur. Simplement zéro, ce qui est précisément ce qui rend le bug dangereux, parce que Françoise ne voit rien à corriger, elle voit une école vide. Le client SSR avec la anon key est bien en place, le cookie d'auth est bien transmis, mais le JWT ne passe plus. La requête tombe en rôle anon, aucune policy ne matche, résultat vide et silencieux. La règle inscrite dans CLAUDE.md et dans le skill rembrandt-conventions qui s'invoque automatiquement sur tout code ERP, c'est que les Server Components utilisent createSupabaseAdmin, jamais createSupabaseServer. L'auth est déjà vérifiée par le proxy.ts en amont, la clé service_role n'atteint jamais le client. Françoise a retrouvé son pointage le lendemain.

3. Build vert surestimé, la règle qui contraint l'agent à se prouver

10 avril, trois heures trente du matin. La refonte émargement tourne depuis huit heures, l'écran me renvoie pour la quatrième fois « build vert, tous les checks passent ». Je n'y crois plus. Je bascule dans le terminal en local, je relance pnpm build à la main, et la sortie renvoie error TS2307: Cannot find name 'QRCodeSVG'. Trois lignes plus bas, Property 'isSeancePassed' does not exist. Et la colonne motif_absence ajoutée en DB la veille sans régénération des types. Quatre fois « vert », quatre fois faux.

Ce n'est pas un incident technique, c'est une dérive comportementale. L'agent n'a pas menti, il a probablement lancé la commande sur un état intermédiaire, ou il a lu un cache LSP obsolète. La règle qu'il fallait écrire n'était pas technique, elle portait sur la manière de prouver le build.

- Pour toute modif, copier la sortie brute de `pnpm build` dans le rapport.
  Si `error TS` ou `Type error` apparaît, le build n'est pas vert.
- Pour revert ou refactor, `grep -rn "mot_cle" app/ lib/ components/`
  avec zéro occurrence comme preuve.

Enter fullscreen mode Exit fullscreen mode

Sans cette contrainte, l'agent surestime toujours. Avec, il montre ses cartes.

4. 1 inscription = N places, le contre-modèle métier

Cet incident-là, je l'ai raconté ailleurs dans la série, le matin où Françoise compare le chiffre du dashboard à son Excel et lâche son « Oui bah c'est pas ça ». Je le rappelle ici parce qu'il est la mère de toutes les règles métier du CLAUDE.md. La table s'appelle inscriptions, le nom est explicite, et l'agent en a déduit, raisonnablement, que chaque ligne représentait une inscription commerciale. Il a tort. La table stocke des places, une ligne par contact et par cours, index UNIQUE (contact_id, cours_id). Un élève inscrit à deux cours occupe deux lignes, et un COUNT(*) FROM inscriptions compte des places, pas des élèves.

- 1 inscription commerciale = N places cours
- « Nombre d'élèves » → COUNT(DISTINCT contact_id)
- « Places d'un cours » → COUNT(*) WHERE cours_id=X

Enter fullscreen mode Exit fullscreen mode

Le vocabulaire métier n'est pas intuitif, et l'agent ne peut pas le deviner. Le CLAUDE.md est le seul endroit où le contre-modèle peut être posé avant que l'agent ne régénère la mauvaise intuition à chaque session.

La structure actuelle

Quatre fichiers travaillent ensemble. Le CLAUDE.md racine porte la stack, les commandes, les conventions transversales, l'arborescence des modules et les zones interdites (.env.local, lib/supabase-admin.ts, policies RLS existantes, /api/cron/, tables critiques). Cent vingt lignes denses, aucune narration, pas un mot de trop.

L'AGENTS.md tient en cinq lignes brutales qui disent à l'agent de ne pas se fier à sa mémoire pour Next.js 16, et de lire le guide dans node_modules/next/dist/docs/ avant d'écrire la moindre route. Ce fichier a réglé plus de bugs à lui seul que n'importe quelle règle longue.

Le .claude/rules/finance.md rassemble les règles verticales du module Finance, sorties du CLAUDE.md parce qu'elles ne concernent qu'un seul périmètre. Modèle CASH, exonérations TVA AFDAS/FORDIP, GL 512x qui ment, prorata TVA 43 % FY26. Un agent qui ne touche pas à /app/finance/ ne les charge pas.

Le skill rembrandt-conventions, enfin, s'auto-invoque sur tout code ERP. Il consolide les règles avec pointeurs vers les mémoires feedback_*.md qui racontent l'incident source. Quand une règle semble fausse, on remonte à l'incident, pas à l'opinion. Mélanger les règles verticales dans le CLAUDE.md racine noierait l'agent sous du contexte non pertinent à chaque session. La sédimentation par couches permet à chaque tâche de charger exactement ce dont elle a besoin.

Ce que j'ai appris en quatre semaines

Écrire l'interdit avant la bonne pratique. Une règle positive du type « utilisez Server Components par défaut » est lue et oubliée. Une règle négative du type « ne jamais désactiver la 2FA de inscription@, ça casse l'app password Gmail » est lue et retenue parce qu'elle porte sa conséquence.

Citer l'incident. Numéro d'erreur, date, ce qui a crashé. La règle devient opposable. L'agent peut vérifier, le lecteur humain aussi. Les règles abstraites se dissolvent, les règles tracées tiennent.

Séparer le général du vertical. Ce qui vaut partout va dans le CLAUDE.md racine. Ce qui vaut pour un module va dans .claude/rules/<module>.md. Ce qui vaut pour toute la culture projet et peut servir à d'autres agents va dans un skill. Trois régimes, trois fichiers. Melvin Conway l'énonçait en 1968 — les systèmes que vous concevez reflètent la structure de l'organisation qui les conçoit. Un CLAUDE.md en couches qui reflète la structure réelle du projet — général, module, culture — est le versant logiciel de cette loi, et c'est précisément pourquoi il tient : l'agent, quand il lit, reçoit le projet dans la forme même qui l'a produit.

Le CLAUDE.md n'est jamais fini, et c'est précisément pour ça qu'il marche. Un fichier figé au jour 1 n'aurait jamais couvert les quatre incidents racontés plus haut. Le fichier vivant, lui, les a tous intégrés. Nous pourrions dire qu'il est l'empreinte des chocs, et que la qualité d'un projet avec Claude Code se mesure autant à ce qui est dans ce fichier qu'au code lui-même.

Ce que tu peux copier dans ton projet

Un template à quatre couches (CLAUDE.md, AGENTS.md, .claude/rules/module.md) dans le repo compagnon de la série, licence MIT : github.com/michelfaure/rembrandt-samples.

Quatre éléments réutilisables, indépendants de ma stack :

  1. La structure à quatre couches — un CLAUDE.md racine (général, court), un AGENTS.md (si tu utilises plusieurs agents Claude), un dossier .claude/rules/<module>.md (règles verticales), et un skill auto-invoqué par périmètre. Chaque niveau charge exactement ce dont une tâche a besoin
  2. Le format de règle négative : « ne jamais X, parce que Y a crashé le DATE ». Portée explicite, incident cité, date datée. Plus opposable qu'une règle positive
  3. Un numéro d'incident par règle : même approximatif (date, message d'erreur, fichier). La règle devient vérifiable, traçable, discutable
  4. Le versioning : le CLAUDE.md est dans le repo, il suit les migrations. Une régression de règle se remarque dans un git log

Et une discipline : lire son propre CLAUDE.md tous les 15 jours. Si une règle n'a pas été convoquée depuis un mois, soit le problème est résolu (on peut l'archiver), soit la règle est trop abstraite pour s'appliquer (on la réécrit). Un fichier qui dort n'aide pas l'agent.

À vous

Si vous avez un CLAUDE.md qui tient la route, quelle est la règle que vous avez mis le plus de temps à y inscrire, et quel incident l'a produite ? Je suis preneur. Les meilleurs patterns que j'ai vus viennent toujours d'une cicatrice.


Code compagnon : rembrandt-samples/claude-md/ — le template à 4 couches (CLAUDE.md, AGENTS.md, règle verticale, fichier feedback), licence MIT.