L’usine en un regard
Deux schémas, et une légende qui parle : cliquez une pièce pour la comprendre — elle s’allume dans le schéma. Les vues guidées isolent un chemin à la fois.
Un run de l’usine — les phases d’un SDLC
De gauche à droite, le temps ; de haut en bas, qui décide. Cinq agents proposent, chacun dans sa phase ; sous chacun, une phase code vérifie ce qu’il déclare. Le runner enchaîne, retente, accepte — et trace tout dans factory.db.
Chaque pièce, en une phrase — cliquez pour l’allumer
-
Tout part d’une phrase :
just adws sdlc "ajoute un compteur de caractères". Vous ne parlez jamais à un agent directement — vous lancez un workflow. -
Le chef d’orchestre (adw_modules/runner.py). Il possède le graphe : l’ordre des phases, les reprises, l’acceptation. Une phase agent est un nœud borné ; une phase code coûte zéro token. Chaque verdict part au tracer.
-
Reconnaissance en lecture seule : où vivent les choses dans le repo, quels fichiers la demande concerne. Il rapporte, il ne décide pas et ne change rien — le périmètre le vérifie après coup.
-
Transforme la demande en spec écrite dans specs/ : ce qu’il faut faire, fichier par fichier, sans question à poser au builder. C’est la phase où l’on dépense volontiers (modèle frontier, réflexion haute).
-
Phase code : la spec déclarée dans l’enveloppe existe-t-elle vraiment, non vide ? Sinon inutile de payer un build — le run s’arrête ici, motif à l’appui.
-
Implémente la spec, exactement, et déclare chaque fichier modifié dans son enveloppe. La boucle de correction vit dans cette phase : une gate rouge lui revient en enveloppe, dans la même session, jusqu’à trois fois.
-
La vérité, par le code : bun test, lint, typecheck. Une gate définit « fini ». Verte, on passe à la revue ; rouge, l’échec repart au builder avec la preuve — c’est moins cher qu’un redémarrage, la session est encore vivante.
-
Confirme que ce qui est construit est ce qui était demandé. Il ne peut pas écrire : un reviewer qui ne peut pas corriger ne corrige pas en douce. Il rend un verdict et des findings nommés.
-
Phase code : appliquer le verdict du reviewer. Un refus arrête le run, rouge, findings dans la trace ; une approbation ouvre la dernière phase.
-
Rédige après coup, dans app_docs/, ce qui a changé et pourquoi — pour l’ingénieur qui arrive. Il n’écrit que de la documentation, jamais dans le code.
-
Le bilan : le compte rendu déclaré existe, l’enveloppe finale est imprimée, le run est fermé avec son coût et ses jetons. « L’agent propose, le code dispose » — littéralement.
-
Une spec, du code testé, un compte rendu — ou un run rouge avec le motif exact de l’arrêt. Dans les deux cas, la trace dit quelle phase, combien de tentatives, quel prix.
-
factory.db (SQLite) : runs, phases, événements — verdict, tentatives, coût, jetons, durée. C’est la salle de contrôle : couloirs de nage, export OTel, vitre Grafana lisent ce journal, jamais l’agent.
Les fichiers de l’usine — plume-factory
Trois familles de fichiers : ce que vous éditez (le roster YAML, les briefs, le justfile), ce que vous écrivez une fois (les ADW et le squelette adw_modules/), et ce que l’usine produit (le journal, le payload). Hors du dépôt : le harnais et les modèles, loués au jeton.
Chaque pièce, en une phrase — cliquez pour l’allumer
-
La surface de commandes :
just adws sdlc "…",just obs lanes,just sandbox mount plume. Chaque recette tient en une ligne et appelle un script — la logique n’est jamais dans le justfile. -
Un workflow = un script Python autonome (PEP 723, lancé par uv) : adw_scout, adw_plan, adw_build, adw_sdlc, adw_tdd, adw_bench… Chacun déclare ses phases (PhaseSpec) et ses enveloppes, puis confie le graphe au runner.
-
Le cœur : séquence les phases, mesure coût et jetons par tentative, retente sur enveloppe invalide ou gate rouge, suspend pour un humain (PhaseHold), trace chaque verdict.
-
Les enveloppes JSON typées : la seule chose qui traverse une couture. Un agent termine par une enveloppe (status, summary, champs métier) ; le code la valide avant de continuer.
-
Charge factory.config.yaml : agents, modèle, réflexion, outils, fichiers autorisés (writes), profils d’authentification, contextes. permissions.py relève ce que l’agent a réellement touché — une écriture hors périmètre est une brèche, pas une gate.
-
LE port : aucun script n’appelle pi ou claude directement. Une HarnessRequest entre, un HarnessResult sort, quel que soit le harnais. C’est ici que vivent les dialectes (--model, --tools, sessions) et le coffre .env.
-
Les vérifications déterministes : tests, lint, typecheck, avec la boucle de correction. Une gate rend un motif d’échec rédigé, preuve à l’appui, prêt à repartir vers l’agent.
-
Le journal de l’usine : chaque événement écrit deux fois, JSONL brut puis miroir SQLite, au moment où il arrive. Un run tué net reste « running » — la signature requêtable d’un run interrompu.
-
Ce que vous éditez : factory.config.yaml (le roster par défaut) et ses variantes frontier / open-weights / eco, les briefs par agent et par contexte. Changer de modèle, c’est une ligne ici, aucun script.
-
Le harnais : un processus par phase (
pi -p,claude -p), qui reçoit le brief, la mission et le contrat d’enveloppe, et rend sa réponse. Il ignore qu’il est dans une usine. Les extensions .pi/ de l’annexe le rendent vérifiable. -
Les moteurs : par la passerelle (une clé, tous les modèles) ou par un profil d’authentification (forfait GLM, Claude, Kimi…). Le roster parle le langage du registre ; le port ajoute le préfixe.
-
Le payload et ce que les agents écrivent : Plume (Bun + TypeScript, bun test), les specs du planner, la documentation du documenter. Le livre n’enseigne pas Plume ; il enseigne l’usine qui la travaille.
-
Le runtime, jamais commité : factory.db, les traces JSONL, les enveloppes, les sessions des harnais, les fiches de sandbox, l’instantané de la vitre Grafana. .gitignore le couvre depuis le chapitre 1.
-
La salle de contrôle : obs_lanes (couloirs de nage dans le terminal), obs_export (OTel, Prometheus), obs_grafana (la vitre web). Toutes lisent factory.db après coup — une lecture de plus, jamais une dépendance du run.