TL;DR
Dans Jah Messenger, toute la connaissance qui pilote les agents vit dans un seul dossier :
.agents/. Chaque outil d'IA (Copilot, Cursor, Claude, Codex) n'a qu'un petit panneau qui
pointe vers lui. Le 30 septembre, on a trouvé un trou : Cursor savait allumer une règle
automatiquement quand on touche un fichier d'interface ou de test ; Copilot, non. Un agent qui
modifiait ui/** pouvait donc ignorer que innerHTML est interdit ici.
La correction tient en trois petits fichiers — qui ne recopient rien, ils pointent. Après quoi : un fichier touché, la bonne règle s'allume toute seule.
1. Le décor : une source unique, des panneaux minces
Le dépôt a une constitution répartie dans quelques fichiers :
.agents/ <- LA source (une seule)
├── RULES.md autonomie, gates humaines, technique non négociable
├── UI.md vanilla, CSP, pas de innerHTML, pas de CDN
├── TESTS.md tester le comportement, caveats Windows, modes CI
├── CHARTER.md charte de jeu, serveur autoritaire, six maillons
└── skills/ session-boot, phase-slice, verify, ship-gate
Chaque outil a ensuite un adaptateur : un fichier court qui dit « la vérité est là-bas ».
┌────────────────────────────────┐
│ .agents/ (LA source) │
│ RULES · UI · TESTS · CHARTER │
└───────────────▲────────────────┘
│ tout pointe ici
┌────────────┬─────────────┼─────────────┬──────────────┐
│ │ │ │ │
┌───┴───┐ ┌────┴───┐ ┌────┴───┐ ┌────┴─────┐
│Cursor │ │ Claude │ │ Codex │ │ Copilot │
└───────┘ └────────┘ └────────┘ └──────────┘
La règle d'or : un adaptateur ne recopie jamais la connaissance, il la cite. Deux copies d'une même règle finissent toujours par se contredire.
2. Le trou : Cursor s'allumait tout seul, Copilot non
Cursor a une capacité que Copilot n'avait pas : des règles attachées à des fichiers. On écrit
globs: ui/**/*, et dès qu'on touche un fichier de l'interface, la règle s'active.
Cursor : je touche ui/... -> la règle UI s'allume AUTOMATIQUEMENT [OK]
Copilot : je touche ui/... -> rien ne s'allume, l'agent doit deviner [MANQUE]
Conséquence mesurable. Un agent qui modifie un écran pouvait livrer un innerHTML — interdit
par la charte — parce que rien ne le lui avait rappelé au moment d'éditer. Ce n'est pas un bug
de l'agent : c'est un bug de plomberie. La règle existait, elle n'était juste pas branchée.
AVANT
┌──────────────┐ ┌──────────────┐
│ UI.md │ │ test/** │ l'agent édite...
│ (la règle) │ │ TESTS.md │
└──────┬───────┘ └──────┬───────┘
│ │ ... et devine
└────────┬───────────┘
▼
⚠️ pas de câble vers l'éditeur
3. La correction : trois câbles, zéro copie
On a donné à Copilot les mêmes règles automatiques que Cursor, au format Copilot
(.github/instructions/*.instructions.md). Trois fichiers, trois zones :
FICHIER TOUCHÉ RÈGLE QUI S'ALLUME POINTE VERS
─────────────────────────────────────────────────────────────────────────
ui/** jah-ui.instructions.md .agents/UI.md
test/** jah-tests.instructions.md .agents/TESTS.md
src/play, src/world jah-charter.instructions.md .agents/CHARTER.md
Résultat : le câble manquant est posé.
APRÈS
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ UI.md │ │ TESTS.md │ │ CHARTER.md │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
┌──────┴───────┐ ┌──────┴───────┐ ┌──────┴───────┐
│ jah-ui │ │ jah-tests │ │ jah-charter │ <- les câbles
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
▼ ▼ ▼
edite ui/** edite test/** edite world/**
=> règle chargée => règle chargée => règle chargée
Ce que dit chaque règle (l'essentiel, en une ligne)
| Règle | S'allume sur | Rappel décisif |
|---|---|---|
jah-ui | ui/** | Pas de innerHTML / outerHTML : construire des nœuds. Pas de CDN, pas de style="". |
jah-tests | test/** | Exécuter le comportement, jamais parser le source. Piège Windows (openssl), piège CI (docs-only reste en lint). |
jah-charter | src/play/**, src/world/** | Réciprocité, pull par défaut, pas de faux vivant, serveur autoritaire. |
4. Pourquoi ça ne duplique rien
Chaque nouveau fichier est court et se termine par « SSOT : .agents/… ». Il cite la
source, il ne la recopie pas. Le jour où la règle change dans .agents/UI.md, les trois câbles
suivent tout seuls — parce qu'ils n'en contiennent pas de copie.
Principe : lier, pas embarquer. Un adaptateur qui recopie devient un menteur en retard.
C'est exactement la même discipline que les adaptateurs racine déjà en place (AGENTS.md pour
Codex, CLAUDE.md pour Claude Code, .cursor/rules/*.mdc pour Cursor). Le 30 septembre, Copilot
est simplement rentré dans le rang.
5. La preuve
Rien de cassé. Le garde-fou statique du dépôt passe :
npm run lint
-> 902 fichiers vérifiés, aucune erreur
-> 148 avertissements « dead-export » (cliquet connu, ouvert par décision FG)
Un point de méthode : la preuve est une commande, pas une intention. « J'ai ajouté trois fichiers » ne prouve rien ; « le lint passe sur 902 fichiers » se rejoue.
6. Le pas à pas, si tu veux le refaire
- Trouve ta source unique. Ici,
.agents/. Si tu n'en as pas, crée-la : c'est elle qui évite les contradictions entre outils. - Repère ce que chaque outil sait faire. Cursor →
globs. Copilot →.github/instructions/*.instructions.mdavecapplyTo. Écris la table de chargement dans le README de la source pour voir les trous d'un coup d'œil. - Écris un câble par zone, pas un par règle :
ui/**,test/**, le domaine jeu. Trois fichiers suffisent souvent. - Ne recopie pas. Chaque câble finit par un pointeur vers la source.
- Rejoue la preuve (
npm run lint, ou l'équivalent chez toi) avant de conclure.
7. Ce que ça change, vraiment
Avant, la règle « pas de innerHTML » vivait dans un fichier que l'agent devait penser à
ouvrir. Maintenant, elle s'allume au moment précis où il ouvre un écran. La connaissance
n'est pas plus nombreuse : elle est au bon endroit, au bon moment.
Une petite plomberie, un grand effet : moins de règles oubliées, moins de reprises. Et une leçon qui vaut au-delà de Jah — une règle qu'il faut se rappeler de lire n'est pas une règle, c'est un espoir.