Ingénierie agentique

SwarmForge décrypté : comment l'essaim d'Uncle Bob fonctionne vraiment

Six agents IA, six worktrees git, une file de messages durable, et un ensemble de barrières qualité qui sont des commandes shell plutôt que de bonnes intentions. La partie tmux est ce qu'il y a de moins intéressant.

Le problème qu'il cherche à résoudre

Confiez une vraie fonctionnalité à un seul agent de codage : il écrira l'implémentation et les tests d'un même souffle, depuis la même compréhension, avec les mêmes angles morts. S'il a mal lu l'exigence, les tests encodent l'erreur de lecture et passent. Demandez au même agent de relire son travail et il sera d'accord avec lui-même, parce que le raisonnement qui a produit le code est encore dans son contexte et paraît toujours solide. Le volume aggrave les choses au lieu de les améliorer : la production est plausible, abondante et peu coûteuse, donc l'humain qui relit devient le goulot d'étranglement et commence à survoler. SwarmForge parie sur une réponse précise à cela : la qualité ne peut pas venir de l'auteur, donc chaque discipline de relecture obtient son propre agent, son propre contexte, son propre arbre de travail, et une vérification qui se termine par zéro ou pas du tout.

La décision porteuse n'est pas le parallélisme. C'est que les rôles ne communiquent qu'à travers du code commité. Un agent relecteur ne voit jamais l'explication de l'auteur sur les raisons pour lesquelles le code est bon — il voit un commit et un nom de tâche, et il lance ses propres outils dessus.

Ce qu'il est, mécaniquement

SwarmForge est un harnais en shell et Babashka autour de primitives que la plupart des équipes possèdent déjà. Chaque rôle est une fenêtre tmux exécutant une CLI d'agent sur son propre worktree git sous .worktrees/, de sorte que deux agents ne touchent jamais le même répertoire de travail. Le comportement vient de texte brut : une constitution.prompt qui revendique la préséance sur tout le reste et dit à l'agent de lire et d'obéir à chaque fichier de swarmforge/constitution/articles/ au démarrage et à chaque tâche, plus un prompt de rôle dans swarmforge/roles/<role>.prompt. Les articles partagés couvrent les règles d'ingénierie, de passation et de workflow ; les articles locaux sont là où un projet les surcharge. La communication est une file basée sur des fichiers, propriété d'un démon, et les deux seuls types de message qu'un agent peut envoyer sont une passation git et une note. Le script ./swarm n'est qu'une amorce : il récupère l'archive des scripts si le répertoire manque, puis passe la main à swarmforge/scripts/swarmforge.sh.

Trois formes d'essaim

Chaque branche est une réponse différente à la question de savoir combien de processus une tâche mérite. main est documentaire ; les topologies exécutables vivent sur les branches pack. Le flux est un anneau, pas une file.

two-pack

coder → cleaner → coder

Un coder qui travaille en test-first et un cleaner qui fait le nettoyage, la revue CRAP et DRY, et les corrections d'architecture. La plus petite boucle qui sépare encore l'écriture du jugement, et la seule forme dont le coût se justifie facilement sur du travail ordinaire.

four-pack

specifier → coder → refactorer → architect → specifier

Les spécifications d'acceptation Gherkin entrent en tête. Un refactorer nettoie sans changer le comportement et complète la couverture, un architect revoit la structure et le sens des dépendances avant que l'anneau ne revienne à la spécification.

six-pack

specifier → coder → cleaner → architect → hardener → QA

Ajoute une passe de durcissement qui mute le code pour trouver où la suite est aveugle, et un rôle QA indépendant qui vérifie par l'interface utilisateur. Quatre des six rôles tournent en mode batch pour que l'outillage s'amortisse sur toute une bande de priorité.

Comment un changement parcourt réellement l'anneau

Voici le six-pack, et il vaut mieux le lire comme un pipeline de critères de sortie que comme une liste d'intitulés de poste. Chaque ligne est un prompt de rôle du dépôt, et chaque condition de sortie est une commande qui doit réussir.

1

specifier

→ coder
Reçoit
Une demande de l'humain, dans le worktree master
Fait
Écrit les spécifications d'acceptation Gherkin et la spécification de la suite QA de bout en bout, pose des questions là où l'intention est ambiguë, et réduit les paramètres d'exemple aux valeurs qui influent réellement sur la mutation d'acceptation.
Critère de sortie
Ne commite pas avant l'approbation explicite de l'humain. C'est la seule barrière humaine de l'anneau, et elle est en tête, là où elle coûte le moins cher.
2

coder

→ cleaner
Reçoit
Une passation git nommant un commit et un nom de tâche stable
Fait
Écrit des tests unitaires ciblés qui expriment le comportement demandé et, selon les termes du prompt de rôle, échoueraient pour une implémentation plausible mais fausse. Puis écrit juste assez de code de production pour les faire passer. Les tests d'acceptation générés ne sont explicitement pas acceptés comme substituts aux tests unitaires.
Critère de sortie
La vérification locale passe. Il ne lance ni mutation, ni CRAP, ni DRY — cela appartient aux rôles suivants, pour que le coder ne puisse pas noter son propre travail.
3

cleaner

→ architect
Reçoit
Un lot de passations de priorité égale
Fait
Lance d'abord l'outil CRAP et ramène la complexité à 6 ou moins, puis l'outil DRY pour retirer la duplication, puis l'outil de mutation en mode analyse et comptage uniquement — en découpant tout fichier dépassant 100 sites de mutation — et augmente la couverture là où c'est raisonnable.
Critère de sortie
Comportement inchangé, tests toujours verts, complexité et duplication réduites. Interdit explicitement de lancer des tests de mutation ou d'ajouter du comportement.
4

architect

→ hardener
Reçoit
Un lot de commits nettoyés
Fait
Partitionne le code en modules aux frontières réelles, garde les dépendances tournées vers l'intérieur, chasse les cycles et les fuites de framework, et isole la politique applicative de l'UI, du système de fichiers, de la base et du réseau. Ajoute des contrôles d'architecture automatisés quand c'est praticable.
Critère de sortie
Comportement préservé et suite verte. Interdiction de lancer git merge à la main : la fusion passe uniquement par ready_for_next.sh.
5

hardener

→ QA
Reçoit
Un lot de commits revus structurellement
Fait
Lance l'outil de mutation du langage fichier par fichier, en différentiel contre les manifestes existants, avec jusqu'à huit workers parallèles, et corrige les mutants survivants avant de continuer. Puis une passe de mutation d'acceptation Gherkin en niveau soft, puis CRAP, puis DRY, dans cet ordre exact.
Critère de sortie
Chaque outil de la chaîne doit être propre avant que le suivant ne tourne. C'est le rôle qui décide si les tests testent réellement quelque chose.
6

QA

→ specifier
Reçoit
Un lot de commits durcis
Fait
Vérification finale indépendante : la spécification d'acceptation, la suite de bout en bout pilotée par l'interface utilisateur sans raccourcis d'API, les tests unitaires et de propriété, et les contrôles de release du projet. Reproduit toute défaillance avant de changer du code.
Critère de sortie
Relance CRAP et DRY avant de terminer. Si la suite QA contredit le Gherkin ou les tests unitaires, elle s'arrête et demande à un humain au lieu de désigner un gagnant.

Le transport est la partie inhabituelle

La plupart des frameworks d'agents laissent les agents se parler. SwarmForge s'y refuse délibérément : un démon possède la livraison, le système de fichiers est la file, et tmux ne sert qu'à réveiller une fenêtre inactive.

La topologie tient dans un fichier de configuration

conf

Le six-pack livré met chaque rôle sur le même backend avec le contournement des permissions activé, et marque toute la seconde moitié de l'anneau comme consommatrice de lots. Le nom du rôle doit correspondre au nom du fichier de prompt, orthographié hardender dans ce dépôt.

# swarmforge/swarmforge.conf
# window-invisible <role> <agent> <worktree> [task|batch] [extra-cli-args...]
window-invisible specifier codex master           --yolo
window-invisible coder     codex coder            --yolo
window-invisible cleaner   codex cleaner    batch --yolo
window-invisible architect codex architect  batch --yolo
window-invisible hardender codex hardender  batch --yolo
window-invisible QA        codex QA         batch --yolo

La file est un répertoire, et l'emplacement est l'état

text

Pas de base de données, pas de broker en mémoire. La position d'une passation dans l'arbre est son statut, le nom de fichier trie par priorité puis par heure, et les en-têtes portent la piste d'audit. Un essaim qui a planté reprend en lisant le disque.

.swarmforge/handoffs/
  outbox/
    tmp/            # drafts land here, then get renamed in atomically
  sent/
  failed/           # malformed or undeliverable, with diagnostics
  inbox/
    new/
    in_process/
    completed/

# filename sorts the queue for you
<priority>_<timestamp>_<sequence>_from_<sender>_to_<recipients>.handoff
# priority 00-99, lower first; UTC YYYYMMDDTHHMMSSZ

Un agent ne peut que demander, jamais livrer

sh

L'agent écrit un brouillon avec quatre en-têtes et appelle le script-barrière. Il ne peut écrire ni id, ni from, ni recipient, ni aucun horodatage — ces champs sont réservés, donc la provenance dans la piste d'audit ne peut pas être falsifiée par ce qui est audité. Il ne tape pas non plus de SHA : le script canonicalise et valide le commit comme un objet réel et non ambigu de dix caractères.

# ./tmp/handoff.txt — drafted inside the assigned worktree
type: git_handoff
to: hardender
priority: 00
task: task-1-cave-setup

# hand it to the protocol gate; the daemon does delivery
swarm_handoff.sh ./tmp/handoff.txt

# receiving side, driven by the role's mode in .swarmforge/roles.tsv
ready_for_next.sh     # -> TASK: / BATCH: / NO_TASK, plus the payload
done_with_current.sh  # -> stamps completed_at, then pulls the next item

Les barrières que le hardener doit franchir, dans l'ordre

sh

C'est ce qui fait de l'essaim autre chose qu'un jeu de rôle. La constitution installe ces outils au démarrage, frais depuis les dépôts de l'auteur — crap4go, crap4java et crap4clj pour la complexité, mutate4go, clj-mutate et mutate4java pour la mutation, et la famille dry4* pour la duplication — et le prompt de rôle fixe leur ordre d'exécution.

# hardener: nothing advances until the previous check is clean
mutate4go ./...            # one file at a time, differential, <= 8 workers
gherkin-mutator --level soft   # mutate the acceptance examples too
crap4go ./...              # complexity against coverage
dry4go ./...               # duplication

# then, and only then
swarm_handoff.sh ./tmp/handoff.txt   # to: QA

Pourquoi chaque mécanisme a cette forme

Lues comme de l'ingénierie, la plupart des décisions d'apparence étrange sont des défenses contre des modes de défaillance précis des agents.

Le message est un commit, pas une explication

Une passation git porte un nom de tâche et un commit validé. Elle ne peut pas porter l'argumentaire de l'auteur sur la qualité du code, parce qu'un argumentaire invite l'agent suivant à être d'accord avec lui. Un commit invite plutôt à la vérification. C'est l'idée la plus transposable du projet.

Les réveils sont génériques et peuvent être perdus

La notification tmux du démon dit seulement que du courrier est arrivé et qu'il faut lancer ready_for_next.sh si l'on est inactif. Elle ne nomme jamais de fichier, donc un agent ne peut pas choisir l'élément intéressant et sauter l'ordre de la file, et un agent occupé peut l'ignorer sans risque puisque terminer une tâche prend aussi la suivante.

Les notes sont plafonnées à quatre-vingts caractères et découragées

Un agent ne peut envoyer une note libre que si un humain, le prompt de rôle ou la constitution le demandent explicitement. Face à une ambiguïté ou une contradiction, la consigne est de s'arrêter et de demander à une personne. C'est un refus délibéré de laisser les agents négocier les exigences entre eux, précisément là où les montages multi-agents dérapent en silence.

Chaque rôle a un worktree, pas seulement une branche

L'isolation est au niveau du système de fichiers, donc toute la classe de pannes où deux agents modifient le même fichier au même instant devient impossible. Cela rend aussi chaque rôle inspectable indépendamment pendant son travail, ce qui compte plus qu'il n'y paraît quand on cherche à comprendre ce qu'un essaim a fait.

La seconde moitié de l'anneau consomme des lots

Cleaner, architect, hardener et QA prennent toutes les passations de même priorité comme une seule unité. Les runs de mutation, de couverture et les contrôles d'architecture coûtent cher par invocation et peu par fichier supplémentaire : le lot fait la différence entre une barrière que l'on exécute et une barrière que l'on désactive.

Le standard est un arbre de prompts à préséance explicite

constitution.prompt revendique l'autorité, les articles portent les règles, les articles locaux les surchargent pour le projet, les prompts de rôle se posent par-dessus, et l'agent doit tout relire à chaque tâche. Votre standard de code cesse d'être un document sur le travail pour devenir une entrée du travail.

Le verdict

La moitié précieuse de SwarmForge, c'est la constitution et l'ordre des barrières : des rôles nommés à responsabilité unique, des critères de sortie qui sont des commandes exécutables, et une règle dure voulant que l'auteur d'un changement ne le note jamais. Cette moitié est réellement bonne, elle est indépendante du langage dans son esprit, et vous pouvez l'implémenter ce trimestre dans la CI que vous exploitez déjà — sans tmux. L'autre moitié, le démon et la file de fichiers durable, est magnifiquement construite et résout surtout un problème que vous pouvez éviter : si vos barrières tournent en CI sur une pull request, vous obtenez durabilité, piste d'audit et ordre de priorité gratuitement, avec des outils que votre équipe opère déjà.

Lisez-le comme une implémentation de référence d'un workflow, pas comme une plateforme à adopter. Commencez par le two-pack pour sentir si des rôles séparés aident vraiment votre travail, empruntez la chaîne de barrières dans tous les cas, et ne visez l'anneau à six rôles que lorsque le coût d'un défaut dépasse clairement celui de six runs d'agent par changement.

Ce qu'il réussit

  • + Les barrières qualité sont des commandes avec des seuils — mutation, CRAP, DRY, couverture — au lieu d'adjectifs dans un guide de style
  • + Le relecteur ne voit jamais le raisonnement de l'auteur, seulement un commit, et c'est la seule façon qu'une relecture par agent vaille quelque chose
  • + L'ordre correspond à une véritable séquence d'ingénierie : spécifier, implémenter, nettoyer, restructurer, durcir, vérifier indépendamment
  • + L'isolation par worktree élimine la corruption par édition concurrente par construction plutôt que par verrous
  • + L'état de la file vit sur le disque avec une piste d'audit que les agents sont structurellement incapables de falsifier : un plantage reprend et un run se reconstitue
  • + L'unique barrière d'approbation humaine se situe au moment de la spécification, là où changer d'avis coûte le moins cher
  • + Tout est du texte brut observable — des fenêtres à lire, des prompts à éditer, une file que l'on liste avec ls

Ce qu'il vous coûte

  • La configuration livrée lance chaque agent avec contournement des permissions : tout le design suppose que vous acceptez de laisser six agents exécuter des commandes sans surveillance dans votre dépôt
  • Six runs d'agent par changement sont économiquement absurdes pour du petit travail, et rien dans l'anneau ne décide qu'une tâche mérite moins de processus
  • La chaîne d'outils exécutables, ce sont les projets crap4*, mutate4* et dry4* de l'auteur pour Go, Clojure et Java — hors de ces langages le contrat de démarrage de la constitution ne s'applique pas et vous fournissez vos équivalents
  • Réinstaller ces outils depuis GitHub à chaque démarrage est lent, dépendant du réseau, et constitue une surface d'attaque de chaîne d'approvisionnement dont vous héritez
  • zsh, tmux et Babashka sur macOS est le chemin heureux ; sous Windows cela signifie WSL et une couche d'adaptation du terminal
  • La règle de transmission oblige un rôle à faire suivre en aval qu'il ait changé quelque chose ou non : l'anneau génère du trafic même quand une étape n'a rien fait
  • Les prompts de rôle ne sont pas de l'exécution forcée : rien n'empêche un rôle de sauter sa propre barrière sinon la phrase qui le lui interdit, donc les vraies garanties valent seulement ce que vaut votre copie en CI
  • C'est visiblement en cours — un tableau de bord, un indicateur de chaleur, un chien de garde de fenêtres et des branches pack divergentes, main étant délibérément non exécutable

Ce qu'il faut emprunter même sans jamais le lancer

Ne laissez jamais l'auteur noter son travail

  • - Lancez les outils qualité dans une étape séparée, avec un contexte séparé de celui qui a écrit le code
  • - Donnez à l'étape de relecture le diff et les outils, pas la justification de l'auteur
  • - Pour un workflow d'agents ce n'est pas de l'hygiène de processus, c'est la différence entre une revue et un tampon

Transformez chaque barrière en code de sortie

  • - Complexité, duplication, couverture et mutants survivants disposent tous d'outils qui renvoient non zéro
  • - Fixez leur ordre d'exécution et arrêtez le pipeline au premier échec
  • - Un agent agit correctement sur une commande en échec et vaguement sur un paragraphe de conseils

Des passations étroites, validées et auditables

  • - Une référence de commit plus une ligne courte force l'intention dans le code et le message
  • - Validez à la frontière pour qu'une requête mal formée échoue avant que l'étape suivante y gaspille un run
  • - Gardez les champs de provenance hors de portée de l'émetteur si vous voulez que la piste d'audit signifie quelque chose

Gardez le standard là où le travail se fait

  • - Des règles écrites comme articles de prompt sont lues à chaque tâche, contrairement à une page de wiki que personne n'ouvre
  • - Séparez les règles partagées des surcharges locales pour que l'exception d'une équipe ne devienne pas la règle de tous
  • - Versionnez-les avec le code et relisez leurs modifications comme du code

Le workflow est la contribution

Retirez tmux, Babashka et l'installation par tarball, et il reste une affirmation sur le génie logiciel : les disciplines qui rendent le code habitable sont séparables, chacune mérite son tour avec ses propres instructions, et aucune ne peut être exercée de façon crédible par la partie qui a écrit le code. C'était vrai avant les agents. Ce que les agents changent, c'est l'enjeu : le volume de production a augmenté et l'humain qui relit n'est pas devenu plus rapide.

Prenez donc les parties qui survivent à la traduction. Nommez vos passes et donnez à chacune un seul travail. Faites de chaque critère de sortie une commande. Placez la barrière humaine au moment de la spécification. Refusez à l'auteur d'un changement tout rôle dans son jugement. Que ce pipeline soit six fenêtres tmux, deux ingénieurs, ou un fichier CI avec cinq jobs ordonnés compte bien moins que de savoir si les barrières existent et tournent vraiment.

FAQ

Que faut-il pour faire tourner SwarmForge ?

zsh, git, tmux et Babashka, plus une CLI d'agent configurée comme Claude, Codex, Copilot ou Grok. Aucun service cloud ni couche d'orchestration à monter : l'essaim, ce sont des fenêtres tmux que vous pouvez regarder, un worktree par rôle sur le disque, et une file de fichiers texte.

Par quelle branche une équipe doit-elle commencer ?

two-pack. Deux rôles suffisent à savoir si séparer l'écriture du jugement aide votre travail, et le coût d'un anneau à six rôles est très difficile à justifier avant. main est documentaire et ne lance pas d'essaim.

Est-il prudent de lancer des agents avec contournement des permissions ?

C'est la plus grande question opérationnelle que le design vous laisse. La configuration livrée passe les drapeaux de contournement à chaque rôle, et c'est ce qui rend un anneau non surveillé possible. Si vous essayez, faites-le sur un clone jetable ou dans un conteneur sans identifiants, et gardez les vraies barrières qualité en CI, là où l'essaim ne peut pas les sauter.

Cela ne marche-t-il que pour Go, Clojure et Java ?

L'orchestration est indépendante du langage, les barrières exécutables non. La constitution nomme les outils de mutation, CRAP et DRY de l'auteur pour ces trois langages. Sur d'autres stacks, gardez la structure de rôles et substituez des équivalents, comme Stryker ou PIT pour la mutation et n'importe quel rapport complexité plus couverture pour le calcul CRAP.

Un essaim d'agents supprime-t-il le besoin de QA ?

Non, et ce design ne le prétend pas. Il promeut la QA en rôle nommé avec des scripts exécutables et une règle explicite de s'arrêter pour demander à un humain quand la suite QA contredit la spécification. Quelqu'un doit toujours savoir ce que le produit doit à ses utilisateurs, et quelqu'un signe toujours la release.

Quelle est l'idée la plus digne d'être copiée ?

Que l'agent qui a écrit le code est le pire juge possible de ce code, et que le remède est un contexte séparé tenant un outil doté d'un code de sortie. Tout le reste du dépôt est un détail d'implémentation de cette phrase.

© 2026 - Ryware.