FlotteFleet — deleguer la codebase a plusieurs agents

Flotte : déléguer la codebase à plusieurs agents

Modèle opératoire pour faire travailler N agents Claude Code en parallèle sur BoostEcom, en continu, sans collision ni dérive. Écrit pour un opérateur solo qui passe à l'échelle : tu passes de « je code » à « je pilote une équipe ».

Modele operatoire pour faire travailler N agents Claude Code en parallele sur BoostEcom, en continu, sans collision ni derive. Ecrit pour un operateur solo qui passe a l'echelle : tu passes de « je code » a « je pilote une equipe ».

FichierRepond a
README.md (ce fichier)Comment le systeme fonctionne, et comment on demarre
roster.mdQui fait quoi, avec quels outils, jusqu'ou
protocol.mdLes regles de circulation (branches, PR, conflits, escalade)
../../.claude/fleet/ownership.jsonLa frontiere, en version machine
../../backlog/README.mdComment le travail entre, se prend, et sort

Le principe

Une equipe humaine tient parce que les gens se parlent. Une flotte d'agents ne se parle pas : chaque session demarre amnesique, ne voit pas les autres, et ne saura jamais qu'un collegue edite le meme fichier a la meme seconde. Donc on n'essaie pas de les faire communiquer. On rend la collision structurellement impossible, et on ecrit la coordination dans le repo.

Quatre lois. Tout le reste en decoule.

1. Une question, une source de verite.

QuestionFichier
Qu'est-ce qu'on construit, et pourquoiCLAUDE.md
Comment on ecrit du code iciAGENTS.md
Qui fait quoiroster.md
Ou s'arrete mon perimetreownership.json
Qu'est-ce qui reste a fairebacklog/
Ou on en est, maintenantpnpm fleet:status
Lancer un item en un clic, suivre la session et sa PR/ops/dev (sections Backlog et Runs) (docs/architecture/dev-console.md)
Comment le systeme marche aujourd'huidocs/architecture/
Pourquoi ce choix a ete faitdocs/decisions/
Ce qui ne va pas, a une date donneedocs/audits/
Ce que les chiffres disentdocs/insights/

Un agent qui hesite ne demande pas : il lit. Si la reponse n'existe nulle part, c'est un bug de doc, et le fix c'est d'ecrire la reponse, pas de deviner.

Corollaire : le contexte descend jusqu'au repertoire. Un CLAUDE.md local (src/components/CLAUDE.md, src/components/patterns/CLAUDE.md, messages/CLAUDE.md, src/features/tracking/CLAUDE.md…) se charge automatiquement quand un agent travaille dedans. C'est la ou vivent les conventions d'un pilier : elles arrivent a l'agent sans qu'il ait a les chercher, et chaque pilier ecrit dans son propre fichier, donc deux piliers ne peuvent pas entrer en conflit sur leurs conventions. Quand un pilier se donne une regle, elle va la, pas dans un fichier racine que tout le monde edite.

2. La frontiere est un chemin de fichier, pas une intention.

"Reste dans ton domaine" est une consigne qu'un agent viole de bonne foi. src/modules/billing/** appartient a billing-engineer est une regle qu'un script verifie. Toute la carte vit dans ownership.json, et pnpm fleet:scope la fait respecter en CI. Un agent ne "fait pas attention" : il est borne.

3. Le verrou, c'est le nom de la branche.

Le reflexe naturel (un todo.md ou chacun coche sa ligne) est exactement ce qui produit les conflits : tout le monde ecrit dans le meme fichier. Ici, un item est pris quand une branche fleet/<pillar>/<id>-<slug> existe sur origin. Verifiable en une commande, atomique, zero fichier partage.

4. Chaque PR nourrit l'ecosysteme.

Une PR qui livre du code sans mettre a jour son item de backlog et la doc du pilier qu'elle change n'est pas finie. C'est ce qui fait que le systeme s'enrichit tout seul au lieu de pourrir : la doc n'est pas une corvee de fin de trimestre, c'est une condition de merge.


L'organigramme

                        TOI (owner / arbitre)
                             │
                    @conductor  ← triage, priorites, deblocages,
                             │     serialisation des hot files
        ┌────────────────────┼────────────────────┐
        │                    │                    │
   PILIERS (1 owner)   TRANSVERSES (lecture)   TOI (decision)
        │                    │
  data-platform        qa-engineer         merge des PR
  security-identity    data-analyst        arbitrage produit
  billing              codebase-auditor    budget / priorites
  ai-platform
  integrations
  commerce-systems
  intelligence
  marketplace
  design-system
  growth-web
  platform-ops
  app-shell

Un pilier = un perimetre exclusif en ecriture. Un transverse = droit de lire partout, droit d'ecrire nulle part sauf ses propres surfaces (tests, rapports, backlog). Personne ne merge sa propre PR : c'est toi, ou une regle d'auto-merge que tu decides.

Le detail par role (mission, chemins, outils autorises, definition de termine, regle d'escalade) est dans roster.md. La definition executable est dans .claude/agents/<nom>.md : chaque agent y a son prompt systeme et sa liste d'outils. Pour les transverses, la restriction est aussi mecanique : une PR qui declare Agent: data-analyst et touche du code dans src/ est refusee par pnpm fleet:scope. L'observateur qui corrige devient juge et partie, donc il ne peut pas.


La boucle

Ce qui tourne en continu, indefiniment.

  BACKLOG ──claim──> BRANCHE ──travail──> PR draft ──STOP──> MERGE (owner)
     ▲                                                      │
     └──────── nouvelle branche depuis origin/main ─────────┘
  1. Entree. Un item arrive dans backlog/inbox/ : pousse par toi, par un audit de codebase-auditor, par un rapport de data-analyst, par un incident, ou par un agent qui a trouve un probleme hors de son perimetre.
  2. Triage. @conductor classe : pilier, priorite, taille, dependances. L'item passe dans backlog/<pillar>/ en status: ready.
  3. Claim. L'agent du pilier prend l'item du haut de sa pile, cree fleet/<pillar>/<id>-<slug> depuis origin/main. La branche est le verrou.
  4. Travail. Une PR = un item = un pilier. Push local = hook pre-push (gardes offline rapides). Avant merge, CI : pnpm lint, pnpm typecheck, pnpm test (+ pnpm fleet:scope via fleet-guard).
  5. PR draft puis stop. L'agent ouvre la PR en draft et s'arrete. Review + merge = owner. Pas d'empilement sur la meme branche.
  6. Merge. Toi. L'item passe done, la doc du pilier est a jour dans la meme PR, auto-changelog publie via RoadmapItem.commitSha. Apres merge : nouvelle branche depuis origin/main pour l'item suivant. Ne jamais reutiliser une branche mergee (la supprimer si elle reste sur le remote).
  7. Retour. Ce que le travail a revele (dette, question ouverte, suite) repart en backlog/inbox/. La boucle se referme.

Cadence recommandee

RythmeQuiQuoi
Continupiliersclaim -> PR -> merge
Quotidien@conductorpnpm fleet:status, triage de inbox/, branches orphelines
Hebdocodebase-auditorun audit sur un pilier en rotation -> docs/audits/
Hebdodata-analystKPI + usage -> docs/insights/ -> items backlog
Hebdoqa-engineercouverture des chemins critiques (billing, auth, credits)
HebdoCIfleet-status tourne lundi 08:00 UTC, rapport dans le job summary
Mensueltoirelecture de roster.md et ownership.json : la carte suit le code

Le suivi

Savoir en permanence ou on en est, sans qu'aucun humain ne tienne un tableau a jour. Rien n'est ecrit a la main : une page de statut maintenue manuellement est perimee le lendemain, et une flotte qui lit un statut perime prend des decisions perimees.

pnpm fleet:status              # lisible
pnpm fleet:status --markdown   # pour un job summary CI
pnpm fleet:status --json       # pour tout le reste

Tout est derive du reel au moment ou tu lances la commande : les fichiers de backlog/, les refs fleet/* sur origin et la date de leur dernier commit, les rapports dates de docs/audits/ et docs/insights/, la liste des piliers dans ownership.json.

Le rapport donne trois choses :

BlocRepond a
Totauxcombien en attente, en cours, bloque, livre
Pilierscharge par pilier, qui est en vol, date du dernier audit
Signauxce qui pourrit en silence

Les signaux sont la vraie valeur. Les compteurs, tu les devinerais ; les signaux, non :

SignalCe qu'il detecte
untriagedun item dort dans inbox/ depuis plus de 7 jours
stalledun P0 pret depuis 7j, ou un P1 depuis 14j, que personne n'a pris
dead-lockune branche fleet/* tient un verrou sans commit depuis 72h
audit-overdueun pilier n'a pas ete audite depuis 90 jours
insight-staleaucun rapport analyste depuis 14 jours : on construit sans mesurer
phantom-blockerun item bloque par un item qui n'existe plus
no-triagedes items en entree et rien de triable : la flotte n'a rien a tirer

Le rapport ne bloque jamais rien (exit 0 systematique). C'est fleet:scope qui bloque. Un rapport qui fait echouer un build devient un rapport qu'on desactive.

Le "pourquoi" se suit ailleurs. Un statut dit ou on en est ; il ne dit pas pourquoi le code est comme ca. C'est le role de docs/decisions/ : un ADR par choix structurel, jamais reecrit, remplace et non modifie. C'est ce qui empeche un agent amnesique de "corriger" dans six mois un compromis deliberement pris aujourd'hui. La section Alternatives ecartees d'un ADR vaut souvent plus que la decision elle-meme : elle evite de re-etudier tous les trimestres une option deja tranchee.


Demarrage

Une fois.

  1. Lis roster.md et coupe les piliers que tu n'exploites pas encore. Douze agents actifs sur un repo qui n'a pas douze chantiers, c'est douze PR a relire pour rien. Commence a trois ou quatre.
  2. Verifie que ownership.json couvre bien ton code : pnpm fleet:scope liste les chemins unowned (visible sur n'importe quelle branche non triviale).
  3. Remplis backlog/inbox/ avec ce que tu as en tete aujourd'hui. Le systeme ne demarre pas a vide.

A chaque session d'agent. Le prompt d'ouverture tient en deux lignes :

Tu es @billing-engineer. Lis .claude/agents/billing-engineer.md, docs/team/protocol.md,
puis prends l'item prioritaire de backlog/billing/. Respecte le protocole de bout en bout.

Le reste (perimetre, outils, definition de termine, escalade) est deja ecrit. C'est le point : tu ne re-expliques jamais le contexte, tu pointes un fichier.

Quand tu veux l'orchestrer toi-meme. @conductor sait deja dispatcher :

Tu es @conductor. Fais le triage de backlog/inbox/, dis-moi ce qui devrait tourner
cette semaine et sur quel pilier, et signale les hot files en conflit.

Les modes de panne, et ce qui les bloque

PanneCe qui l'empeche
Deux agents editent le meme fichierPerimetres exclusifs + pnpm fleet:scope en CI
Deux agents prennent le meme itemLe verrou = la branche fleet/... sur origin
Conflit sur schema.prisma / package.jsonHot files serialises par @conductor, trailer Hot-file: obligatoire
Deux implementations du meme patternLoi 1 : on grep et on lit docs/architecture/ avant d'inventer (regle deja dans AGENTS.md)
PR fourre-tout impossible a relireUne PR = un item = un pilier, gate CI
La doc decroche du codeLa doc du pilier se met a jour dans la meme PR, sinon pas de merge
Un agent part en roue libreTrailer Agent: verifie par fleet:scope : writeRestrictedAgents dans .claude/fleet/ownership.json borne les fichiers qu'un transverse peut changer. La liste d'outils des seize fiches .claude/agents/ est IDENTIQUE, Edit/Write compris : cette ligne a annonce une « toolbox restreinte » qui n'a jamais existe, la restriction est mecanique cote PR
Une branche abandonnee bloque un itemRevue quotidienne des branches par @conductor : une branche sans commit depuis 72h est liberee
Le systeme devient obsoleteRevue mensuelle de ownership.json ; les chemins unowned sont rapportes a chaque run

Ce que le systeme ne fait pas

Il ne remplace pas ton arbitrage. Les agents produisent des PR correctes et scopees ; quoi construire, dans quel ordre, et a quel prix, reste ta decision. Le conductor propose, il ne tranche pas.

Il ne garantit pas la qualite d'une PR isolee : c'est le role des gates CI et de la relecture. Il garantit que dix PR simultanees ne se marchent pas dessus.

Et il ne survit pas a une carte perimee. Si tu ajoutes un module et que personne ne le declare dans ownership.json, il devient une zone grise ou les collisions reviennent. pnpm fleet:scope te le dit a chaque PR : ecoute-le.