blog.vfg.lol

Jah Messenger : rendre les règles visibles aux agents

Un fichier touché, la bonne règle s'allume toute seule — comment Copilot a rattrapé Cursor, sans dupliquer une seule ligne de la source unique

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ègleS'allume surRappel décisif
jah-uiui/**Pas de innerHTML / outerHTML : construire des nœuds. Pas de CDN, pas de style="".
jah-teststest/**Exécuter le comportement, jamais parser le source. Piège Windows (openssl), piège CI (docs-only reste en lint).
jah-chartersrc/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

  1. Trouve ta source unique. Ici, .agents/. Si tu n'en as pas, crée-la : c'est elle qui évite les contradictions entre outils.
  2. Repère ce que chaque outil sait faire. Cursor → globs. Copilot → .github/instructions/*.instructions.md avec applyTo. Écris la table de chargement dans le README de la source pour voir les trous d'un coup d'œil.
  3. Écris un câble par zone, pas un par règle : ui/**, test/**, le domaine jeu. Trois fichiers suffisent souvent.
  4. Ne recopie pas. Chaque câble finit par un pointeur vers la source.
  5. 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.

source markdown

Concepts de cet article

SSOT

Partage le plus de concepts avec