Protocole : les règles de circulation
Ce que chaque agent applique, à chaque item, sans exception. Court par conception : un protocole qu'on ne relit pas est un protocole qu'on ne suit pas.
Ce que chaque agent applique, a chaque item, sans exception. Court par conception : un protocole qu'on ne relit pas est un protocole qu'on ne suit pas.
1. Cycle de vie d'un item
inbox/ ──triage──> <pillar>/ ready ──claim──> branche ──PR──> merge ──> _archive/
Avant de commencer, dans cet ordre :
git fetch origin main
git ls-remote --heads origin "fleet/*" # qui travaille sur quoi, maintenant
Si une branche fleet/<pillar>/<id>-* existe deja, l'item est pris. Prends
le suivant. La branche est le verrou : elle est atomique, visible par tout le
monde, et ne demande d'editer aucun fichier partage.
Claim :
git checkout -b fleet/<pillar>/<id>-<slug> origin/main
git commit --allow-empty -m "chore(<pillar>): claim <id>"
git push -u origin fleet/<pillar>/<id>-<slug>
Le commit vide pousse immediatement rend le verrou visible avant que le travail commence. C'est la difference entre "je vais prendre cet item" et "cet item est pris".
Le worktree est partage par plusieurs sessions. Une session ne fait jamais
git checkout d'une branche qu'une autre session a en cours : ca emporte
ou ecrase son travail non commite. Chaque session part d'une branche neuve
depuis origin/main, au nom unique, et n'edite que celle-la. Un stash
d'une autre session ne se drop pas et ne se pop pas.
Liberation. Une branche sans nouveau commit depuis 72h est consideree
abandonnee. @conductor la supprime et repasse l'item en ready.
2. Une PR = un item = un pilier
Exception contrôlée : chantiers continus Dev Studio
La règle ci-dessous reste le défaut pour les agents de flotte autonomes
et les demandes indépendantes. Pour un chantier explicitement piloté par
le propriétaire depuis Dev Studio, appliquer
.claude/skills/dev-studio-ship/SKILL.md : examiner les doublons dans
le code, le backlog (y compris archives), les PR et les branches ; regrouper
les items réellement interdépendants dans une PR de chantier avec
plusieurs commits lisibles, sans déploiement pour chaque commit.
Réutiliser la PR déjà ouverte du même chantier avec accord du
propriétaire, pas celle d'un autre agent. Les critères d'acceptation,
les preuves et les IDs d'items doivent apparaître dans la PR.
pnpm fleet:scope, les verrouillages, les hot files et la séparation des
piliers restent en vigueur. Si la PR traverse un pilier nécessairement,
documenter Cross-pillar: avec la raison et les relectures concernées.
Ne jamais regrouper deux changements sans rapport pour réduire le nombre
de PR. Ne pas créer d'exception silencieuse à un gate.
C'est la regle qui rend dix agents simultanes relisables.
pnpm fleet:scope verifie mecaniquement, en local et en CI, que les fichiers
touches appartiennent a un seul pilier. Lance-le avant de pousser.
Traverser un pilier est autorise quand c'est indissociable (une migration plus son usage, un endpoint plus son ecran). Il faut alors :
Cross-pillar: le grant de credits et la route webhook doivent changer ensemble, sinon la fenetre d'idempotence casse
dans le corps de la PR, et une relecture par les deux piliers. Une PR cross-pilier sans raison ecrite est refusee par la CI, pas par un humain.
Ce qui n'est jamais une raison valable : "c'etait sur mon chemin", "petit
fix au passage", "tant qu'a faire". Ces changements deviennent un item dans
backlog/inbox/. Le cout d'ouvrir un item est de trente secondes ; le cout
d'une PR fourre-tout est une relecture impossible et un conflit garanti.
3. Hot files (fichiers chauds)
Certains fichiers sont touches par tout le monde. On les serialise au lieu d'esperer.
prisma/schema.prisma, package.json, pnpm-lock.yaml, vercel.json,
next.config.mjs, tsconfig.json, eslint.config.mjs, components.json,
CLAUDE.md, AGENTS.md, .env.example, src/env/**, src/config/**,
src/types/**, src/app/layout.tsx, src/app/providers.tsx,
src/instrumentation*.ts, .claude/fleet/**, .claude/agents/**,
docs/team/**.
La liste vivante est dans
ownership.json (hotFiles).
Regle. Avant de toucher un hot file : verifier qu'aucune PR ouverte ne le touche deja. Puis declarer dans le corps de la PR :
Hot-file: prisma/schema.prisma — ajout de Credit.expiresAt (workstream 1)
Priorite en cas de collision. Le premier a avoir pousse garde la main. Le
second attend le merge et rebase. On ne resout pas un conflit sur
schema.prisma a deux : on sequence.
4. Gates : push local et PR
Un push par unite logique. Commit local != push distant != deploiement
Vercel. Chaque push d'une branche fleet/* ou claude/* etait un Preview
complet ; le build saute desormais ces previews sauf [deploy preview] dans le
message du commit (scripts/lib/build-policy.mjs). Regroupe les micro-commits
(lien de backlog, stamp de PR, correctif de garde) dans le push de l'unite, et
ne pousse pas apres chaque edition. Detail et chiffres :
docs/ops/finops-2026-10-03.md.
Push local = hook pre-push (gardes offline rapides uniquement). Voir
AGENTS.md : la liste est derivee de package.json.
PR / CI (bloquant au merge) :
pnpm fleet:scope # aussi dans fleet-guard.yml
pnpm lint # eslint --max-warnings 0
pnpm typecheck # tsc --noEmit
pnpm test # vitest run
pnpm db:guard:check # si le schema a bouge
pnpm build est lourd : reserve aux PR qui touchent le graphe de routes, les
frontieres serveur/client, ou la config de build. Le hook pre-push local
lance 21 commandes, pas trois : la liste exacte vit dans
package.json (simple-git-hooks.pre-push) et est reprise, derivee par
pnpm docs:claims, dans AGENTS.md. Ce sont les gardes
offline rapides. lint, typecheck et test ne sont PAS dans le hook :
ils tournent en CI sur chaque PR (platform-ops/2696).
En CI : typecheck, lint, test (avec Postgres), build,
audit-memory-scope, fleet-guard. Une PR rouge ne se merge pas, et ne se
merge pas non plus « parce que c'est un test instable » (flake) sans que le
test instable devienne un item.
5. Format de PR
Titre : conventional commit, en anglais, scope = pilier.
feat(billing): grant rollover credits with a 65-day expiry
Corps :
Backlog: backlog/billing/0042-credit-rollover.md
Roadmap-Item: <id> # si un RoadmapItem existe (alimente auto-changelog)
Cross-pillar: <raison> # seulement si plusieurs piliers
Hot-file: <fichier> — <raison> # seulement si hot file
## Ce que ca change
## Comment c'est verifie
## Risque et rollback
La PR est ouverte en draft. Un agent ne merge pas, n'approuve pas, ne ferme pas d'issue, ne publie pas de release. Ces gestes appartiennent au proprietaire.
Arret apres la PR draft (boucle obligatoire)
Pour un chantier Dev Studio expressément itératif, l'agent peut
continuer à pousser des commits sur la même PR du chantier tant que
le propriétaire a demandé de garder cette PR ouverte pour ses demandes
successives. Il n'en crée pas une nouvelle pour chaque backlog lié.
Avant de transmettre au propriétaire, l'agent doit relire le diff total
de la PR, corriger les défauts, exécuter et tracer les contrôles
disponibles, puis signaler soit « à corriger », soit « en attente de
validation technique », soit « prête pour review humaine ». La review
de l'agent n'est ni une approbation GitHub, ni un substitut à la
review humaine. Merge uniquement par le propriétaire ou son équipe.
Voir .claude/skills/dev-studio-ship/SKILL.md.
claim → branche → commits → push → PR draft → STOP
↑
owner review + merge (manuel)
↓
origin/main a jour → claim item suivant → NOUVELLE branche
Apres gh pr create --draft (ou equivalent), l'agent s'arrete sur cet
item. Pas de commit supplementaire sur la meme branche "en attendant",
pas de deuxieme fonctionnalite greffee, pas de rebase opportuniste. La suite
attend le merge (ou une instruction explicite du proprietaire pour amender
cette PR).
Apres le merge, toujours :
git fetch origin main
git checkout -b fleet/<pillar>/<next-id>-<slug> origin/main
Jamais git checkout de l'ancienne branche mergee pour "continuer". Une
branche mergee n'est plus un verrou de travail : c'est de l'histoire.
Suppression de branche. Le depot a delete_branch_on_merge: true.
Si la branche fleet/... est encore sur origin apres merge, la
supprimer (git push origin --delete <branch>) plutot que d'y pousser
de nouveaux commits (ce qui la recree et casse le verrou). Une branche
recreee apres merge n'est pas un claim : c'est une fuite.
6. Nourrir l'ecosysteme
Une PR n'est finie que quand elle a rendu le systeme plus lisible qu'avant. Dans la meme PR :
| Situation | Ce qui doit bouger |
|---|---|
| Toujours | l'item de backlog passe done et va dans backlog/_archive/<pillar>/ |
| Le comportement change | la doc du pilier dans docs/architecture/ ou docs/ops/ |
| Une convention nouvelle interne au pilier | le CLAUDE.md local du repertoire concerne (auto-charge par les agents qui y travaillent) |
| Un choix structurel, un compromis assume, une contrainte externe | un ADR dans docs/decisions/ |
| Une approche essayee et abandonnee | un ADR rejected : ca evite qu'on la re-propose dans six mois |
| Une nouvelle route / table / cron | CLAUDE.md (hot file : trailer requis, regroupe si possible) |
| Un travail revele une suite | un nouvel item dans backlog/inbox/ |
Un ADR n'est pas un formalisme par PR. Il s'ecrit quand la reponse a "pourquoi pas plus simple ?" n'est pas evidente en lisant le code. Il n'est jamais modifie apres acceptation : il est remplace par un nouveau qui le reference.
Regle anti-conflit sur la doc : on n'ajoute jamais a la fin d'un fichier partage.
Un rapport, un audit, un insight = un fichier date qui lui est propre
(docs/audits/2026-08-25-billing.md). Deux agents qui ajoutent une section au
meme fichier le meme jour, c'est un conflit ; deux fichiers, c'est zero.
7. Escalade
Un agent ne sort jamais de son perimetre de sa propre initiative. Quand il a besoin d'autre chose :
| Situation | Geste |
|---|---|
| Besoin d'un changement dans un autre pilier | ouvrir un item dans backlog/<pillar-cible>/, referencer sa PR, continuer sur ce qu'il peut faire |
| Bloque net par cette dependance | pousser ce qui est fait, marquer la PR blocked-by: <item>, prendre l'item suivant |
| Faille de securite | @security-engineer en item prioritaire, immediatement, sans attendre le triage |
| Contradiction entre deux docs | corriger la source de verite si c'est son pilier, sinon item vers @conductor |
| Ambiguite produit | item vers @conductor avec les deux lectures possibles et une recommandation |
| Le code contredit la doc | croire le runtime, verifier le plan de controle, puis corriger la doc (regle AGENTS.md) |
Attendre n'est jamais la bonne reponse. Il y a toujours un item suivant.
8. Limites dures
Ce qu'aucun agent ne fait, quel que soit le pilier :
pnpm db:reset,prisma migrate reset,db:push --force-resetsur une base partagee- push sur
main, force-push sur la branche d'un autre - merge, approbation, fermeture d'issue, publication de release
- ecriture sur le theme Shopify
MAINsans{ allowLive: true } - ajout d'une dependance sans item de backlog et sans trailer
Hot-file:surpackage.json - commit d'un secret, d'un
.env*, ou d'une donnee personnelle - desactivation d'un gate CI pour faire passer sa propre PR
9. Prompt d'ouverture de session
Le seul texte que tu ecris a la main. Tout le reste est deja dans le repo.
Tu es @<agent>. Lis .claude/agents/<agent>.md, docs/team/protocol.md, AGENTS.md.
Verifie les branches fleet/ existantes, prends l'item prioritaire de backlog/<pillar>/,
et deroule le protocole jusqu'a la PR draft.
Pour orchestrer :
Tu es @conductor. Lance pnpm fleet:status, trie backlog/inbox/, propose le plan
de la semaine par pilier, et signale les collisions de hot files sur les PR ouvertes.
10. Savoir ou on en est
pnpm fleet:status
Derive du reel : items de backlog, branches fleet/* et leur inactivite,
rapports dates de docs/audits/ et docs/insights/. Rien n'est tenu a la main,
donc rien ne perime.
Lance-le avant de prendre un item (pour voir ce qui est deja en vol) et au
triage (pour voir ce qui pourrit). En CI il tourne sur chaque PR et chaque lundi
08:00 UTC, dans le job summary. Il ne bloque jamais : fleet:scope est le gate,
fleet:status est le tableau de bord.