Aller au contenu principal
Accueil : Florian Bruniaux Engineering & AI

Florian Bruniaux / Explore

Rechercher sur le site

Recherchez en français ou en anglais, ou accédez à une rubrique.

↑ ↓ pour naviguerEntrée pour ouvrirÉchap pour fermer

FR
Thème
Contact

Plan-execute : exécuter plus de 20 agents sur une migration

Une migration illustrative de 243 fichiers répartie entre agents aux missions bornées, avec brief partagé, contrôles locaux et validation séquentielle des merges.

90 min de lecture Mis à jour le
Aller au résumé ↓

Ce que vous en retirez

  • ✓ Le modèle en deux phases configuré et prêt à fonctionner
  • ✓ Une checklist de décomposition pour savoir si une tâche peut être parallélisée
  • ✓ La commande /batch avec des contrôles qualité pour votre stack
  • ✓ Un workflow de review pour les exceptions qui exigent un jugement humain

Prérequis

  • → Claude Code installé et configuré
  • → Worktrees Git disponibles (git 2.5+)
  • → Une tâche de migration portant sur au moins 20 fichiers

TL;DR

Je recommande plan-execute pour une migration seulement quand vous pouvez écrire un contrôle qualité qui renvoie réussite ou échec sans interprétation humaine. Si les fichiers ne sont pas indépendants, ne parallélisez pas ; si vous ne pouvez pas encore écrire ce contrôle, écrivez-le d’abord. Le schéma est un planificateur en lecture seule qui rédige un brief, des agents aux missions bornées dans des worktrees séparés et un merge séquentiel qui relance le contrôle après chaque merge. Je m’attends à ce que la review se déplace vers le plan et le contrôle plutôt que les diffs individuels. L’exemple de 243 fichiers ci-dessous est illustratif, et rien dans ce résumé n’en dépend.

Une migration JSX vers TSX peut toucher davantage de fichiers qu’une session ne peut en traiter confortablement. Interruptions, dépendances partagées et contrôles incomplets peuvent laisser des branches partiellement converties. Le modèle plan-execute donne à chaque unité une mission bornée et fait de l’intégration une étape séparée.

Dans l’exemple illustratif, un agent Opus planifie une migration de 243 fichiers, puis environ 24 agents Sonnet exécutent des missions bornées sur des branches séparées. Trois fichiers demandent une review humaine tandis que 240 passent leurs contrôles locaux. C’est un exemple illustratif, pas une exécution que je peux documenter : je n’ai ni log, ni taux d’exception mesuré, ni durée calibrée derrière ces chiffres, et les règles du guide n’en dépendent pas.

Ce guide couvre la mise en place, les raisons de l’échec quand la décomposition est sautée et le traitement des exceptions.

Pourquoi le séquentiel se dégrade à l’échelle

Une longue session séquentielle accumule sorties d’outils et décisions. La disponibilité des conventions antérieures dépend du modèle, de la gestion du contexte et de ce qui est conservé pendant la compaction. Le nombre de fichiers seul ne dit pas quand une convention disparaîtra ou cessera d’être suivie.

Chaque unité exige encore inspection des dépendances, transformation et validation. Une convention erronée dans un brief partagé peut affecter beaucoup de fichiers, que l’exécution soit séquentielle ou parallèle. Détectez-la avec des contrôles explicites et une review avant d’étendre l’exécution.

Les missions bornées réduisent le périmètre de chaque agent, et les branches séparées tiennent à part les modifications ordinaires de checkout. Ni les unes ni les autres n’empêchent une erreur partagée ou un échec d’intégration. Les contrôles locaux détectent les propriétés qu’ils testent ; le coordinateur doit relancer les contrôles d’intégration après chaque merge.

Le modèle en deux phases

La phase 1 fait tourner un agent Opus unique en lecture seule. Il lit la codebase entière, identifie les schémas, trouve les cas limites et signale les fichiers qui demanderont un traitement particulier. Il ne touche aucun fichier. Sa seule sortie est un brief.md qui couvre les conventions cibles, les exceptions par répertoire, les cas limites connus du code réel et la commande exacte de contrôle qualité que chaque agent doit réussir avant que sa branche soit considérée prête. Ce brief est l’artefact central. Tout ce qui suit dépend de sa qualité. C’est du context engineering appliqué à une tâche ponctuelle ; la version durable et toujours active de la même discipline est couverte par le guide de context engineering.

La phase 2 confie le brief et des sous-ensembles distincts de fichiers à N workers Sonnet. Chaque worker utilise son propre worktree (une copie de travail distincte avec sa branche), applique la migration et lance le contrôle qualité. Si le contrôle réussit, le worker marque sa branche comme prête. Sinon, il écrit un rapport d’exception et s’arrête. Un coordinateur collecte les branches prêtes, les merge séquentiellement et relance le contrôle qualité après chaque merge. Les exceptions parviennent à un reviewer humain avec le contexte exact de chaque blocage.

Choisissez la concurrence séparément du nombre de missions. Les 24 missions de l’exemple peuvent tourner par lots, en fonction de la capacité du compte, de la mémoire et des outils. Pour comparer deux campagnes, consignez les identifiants réellement utilisés par le planificateur et les workers, ainsi que leur effort.

Phase 1 (Opus)
  Read codebase → identify patterns → identify edge cases
  Output: brief.md
         ↓
Phase 2 (Sonnet × N)
  Agent 01: files 1-10   → quality gate → branch ready ──┐
  Agent 02: files 11-20  → quality gate → branch ready ──┤
  Agent 03: files 21-30  → quality gate ✗ → exception   ─┤
  ...                                                      ↓
  Agent 24: files 231-243 → quality gate → branch ready  Coordinator merges
                                                          ready branches
                                                          Exception queue → human
Un planificateur rédige un brief, des worktrees bornés exécutent des contrôles locaux, les échecs s'arrêtent avec des rapports d'exception et les branches prêtes sont mergées séquentiellement avec un nouveau contrôle après chaque merge.
Le coordinateur vérifie l’intégration après chaque merge. Des branches qui passent seules peuvent encore échouer ensemble. Voir la figure en taille réelle.

La contrainte clé de la phase 1 : Opus n’écrit pas de code. S’il touche aux fichiers, deux choses se passent mal. L’invariant de lecture seule est rompu : les agents de phase 2 peuvent rencontrer des fichiers modifiés différents de ce que décrit le brief. Plus subtilement, Opus commence à prendre des microdécisions qui devraient être des conventions explicites du brief, et les agents de phase 2 reçoivent une spécification incomplète. Le brief doit être assez complet pour que tout agent Sonnet puisse exécuter correctement sa mission sans voir ce que font les autres.

La décomposition, l’étape que tout le monde saute

Une mauvaise décomposition peut laisser des agents avec des responsabilités qui se recoupent et des sorties incompatibles. Réglez cette séparation avant de les lancer ; ce guide ne donne pas de taux d’échec mesuré pour cette étape.

La règle est la suivante : si vous ne pouvez pas écrire un contrôle qualité automatisable, une commande qui renvoie réussite ou échec sans interprétation humaine, vous ne pouvez pas paralléliser en toute sécurité. Des instructions de migration vagues multipliées sur 24 agents produisent 24 implémentations différentes de la partie vague. Et comme chaque agent ne voit pas ce que font les autres, vous ne le découvrez qu’au merge.

C’est la règle que je recommande, et elle ne vient pas de moi seul. Quatre praticiens à Dev With AI, Sciara, Grégoire, Negouai et Drode, Laforge, plus une voix indépendante sur le podcast IFTTD (épisode 311), décrivant des projets complètement différents, sont arrivés sans se citer à la même règle pour automatiser toute forme de review : des critères binaires et déterministes seulement, code typé, fonction de moins de 30 lignes, configuration présente. Utilisez des contrôles réussite/échec pour les critères exprimables sous forme binaire et gardez les jugements subjectifs en review humaine. Si la justesse de votre migration ne peut pas être réduite à un contrôle binaire, vous n’êtes pas prêt à la paralléliser, vous êtes prêt à écrire le contrôle.

Avant tout lancement, examinez cette checklist sur votre migration précise :

Les fichiers sont-ils indépendants dans le périmètre de la migration ? Une migration JSX vers TSX convient généralement ici, parce que chaque fichier se convertit isolément. Une migration renommant un type partagé utilisé dans 50 fichiers ne convient pas, parce que le changement de définition du type doit arriver avant la conversion des 50 fichiers. Lorsque l’indépendance n’est pas évidente, dep-scope cartographie les dépendances TS/JS au niveau symbole pour voir quels fichiers partagent réellement un type avant de répartir le travail.

Le contrôle qualité est-il une commande, pas un jugement ? tsc --noEmit renvoyant zéro est un contrôle qualité. « Looks correct » (traduction : « semble correct ») n’en est pas un. Si vous ne pouvez pas encoder le critère en commande shell, revenez au brief et précisez les conventions jusqu’à y parvenir.

Le brief couvre-t-il les cas limites trouvés en phase 1 ? Si la phase 1 a découvert que les fichiers dans src/legacy/ utilisent un autre schéma d’import, le brief doit dire quoi faire. Un agent devant un cas limite non documenté prendra soit une mauvaise décision, soit lèvera une exception. La première option est pire.

Avez-vous des tests de caractérisation pour le comportement que cette migration pourrait changer ? Cela compte davantage pour une migration comportementale que mécanique. Pour une passe mécanique JSX vers TSX, tsc vérifie la compatibilité des types ; il ne prouve pas le comportement à l’exécution. Pour une migration qui y touche, il faut une référence à laquelle comparer.

Quatre contrôles de décomposition couvrent les unités indépendantes, les commandes automatisées, les cas limites documentés et une référence comportementale si nécessaire, avec un arrêt pour résoudre tout manque.
Aucun pourcentage d’échec ni durée d’écriture de tests n’est supposé. La checklist détermine si la répartition choisie est prête. Voir la figure en taille réelle.

L’isolation par worktree

Sans worktrees, des agents parallèles sur le même système de fichiers entrent en collision. Conflits de git stash, écritures concurrentes dans le même fichier et état incohérent de l’index sont de vrais modes d’échec lorsque deux agents touchent des chemins qui se recoupent.

Les worktrees donnent à chaque agent une copie de travail complètement séparée du repository, dans son répertoire, avec sa branche. L’agent 01 travaille dans ../migration-agent-01 sur la branche feat/migration-jsx-01. L’agent 02 travaille dans ../migration-agent-02 sur feat/migration-jsx-02. Ils partagent le même historique Git et évitent par défaut de modifier le même checkout. Les permissions des processus peuvent encore autoriser l’accès aux autres worktrees.

Un arbre Git se divise en deux répertoires et branches distincts. Une colonne indépendante liste les contrôles du système de fichiers, du réseau et des identifiants nécessaires au-delà de la séparation par worktree.
Un worktree empêche le recoupement ordinaire des checkouts. Ce n’est pas une frontière de permissions, et les erreurs d’intégration restent possibles. Voir la figure en taille réelle.

Vous pouvez les créer manuellement :

git worktree add ../migration-agent-01 -b feat/migration-jsx-01
git worktree add ../migration-agent-02 -b feat/migration-jsx-02
# ... repeat for each agent

Ou laisser Claude Code le gérer automatiquement avec isolation: worktree dans le frontmatter de l’agent :

---
name: migration-agent
description: Migrate an assigned set of JSX files to TSX.
model: sonnet
isolation: worktree
tools:
  - Read
  - Edit
  - Write
  - Bash
---

You will receive: brief.md (conventions), a list of files, and a quality gate command.
Apply the migration to your file list following brief.md exactly.
Run the quality gate command. If it passes, exit cleanly.
If it fails, write exception-report.md explaining what blocked you and exit.
Do not touch files outside your assigned list.

L’option isolation: worktree donne au sous-agent une copie de travail séparée. L’alias sonnet suit le modèle que le client et le fournisseur rendent disponible. Pour comparer deux campagnes, consignez l’identifiant effectivement utilisé ou épinglez la version dans la configuration. Consultez la référence des sous-agents pour les champs disponibles.

Les worktrees séparent les opérations ordinaires de checkout. Ils laissent accessibles les appels réseau, les identifiants présents dans le périmètre et les fichiers hors de la cible de migration depuis le worktree. Pour une passe JSX vers TSX sur du code déjà versionné, cela convient généralement. Pour une migration plus proche de secrets, de scripts de déploiement ou d’appels externes, ajoutez la couche d’isolation qui revient indépendamment dans trois communautés de praticiens : conteneur éphémère, montage en lecture seule hors des fichiers cibles, liste d’autorisations réseau et quota de temps strict. Les worktrees gardent Git propre. La couche supplémentaire réduit le rayon d’impact.

La commande /batch

Claude Code fournit /batch comme skill intégré. Donnez-lui une instruction en langage naturel. Il propose de répartir le travail en 5 à 30 unités indépendantes et attend votre validation avant de lancer un sous-agent par unité dans un worktree. Le skill peut ouvrir des PR : précisez la règle de publication dans votre demande. Dans l’exemple ci-dessous, le travail reste local.

Le parallélisme voulu. Pour une migration de 243 fichiers, environ 24 agents de 10 fichiers chacun sont une répartition raisonnable. Le bon nombre dépend de l’indépendance des fichiers et du temps pris par chaque agent : si le contrôle qualité est rapide (moins de 30 secondes), vous pouvez tendre vers 30 agents ; s’il est lent (tsc sur un grand projet peut prendre 2 à 3 minutes), moins d’agents signifie moins de temps perdu lorsqu’un échoue tôt.

Le contrôle qualité, sous forme de commande exacte que chaque unité doit réussir. Pour la migration JSX vers TSX : tsc --noEmit --project tsconfig.json.

Et le brief de phase 1, pour que chaque agent lise les conventions avant de toucher aux fichiers assignés.

Une invocation complète pour le cas JSX vers TSX :

/batch migrate every *.jsx file under src/ to TSX, following the conventions
in .claude/migration/brief.md. Split the work across roughly 24 parallel
agents. Each unit must pass "tsc --noEmit --project tsconfig.json" before
it counts as done. Keep changes on local branches. Do not push or open PRs.

Ce que /batch ne gère pas automatiquement : détecter les dépendances entre fichiers qui auraient dû bloquer la décomposition, résoudre les conflits entre branches prêtes qui ont touché le même fichier partagé et revoir les exceptions. Ces trois points restent humains. Les branches prêtes se mergent proprement précisément parce que la décomposition a assuré leur indépendance. Si un problème passe et que deux branches entrent en conflit, cela signale un manque dans la décomposition.

Le merge lui-même doit rester banal : merger séquentiellement les branches prêtes dans la branche d’intégration et relancer le contrôle qualité après chaque merge, en s’arrêtant au premier échec. Une branche qui a passé son contrôle isolément peut casser le build une fois les voisines intégrées ; la relance sérialisée détecte ces interactions. Résistez à l’envie de faire un merge octopus de 24 branches d’un coup : quand ce build échoue, vous revenez à une bissection manuelle.

Tests de caractérisation

Pour les migrations comportementales, les tests de caractérisation sécurisent la phase 2. Ils comparent la sortie après migration à celle d’avant, plutôt que de vérifier la justesse. Si les workflows test-first avec Claude sont nouveaux pour vous, le guide TDD couvre la discipline sous-jacente.

Le prompt pour les générer :

For [filename], capture its current output for [these inputs] as tests.
Do not assess whether the output is correct. Do not optimize anything.
Capture only what the function currently returns for the given inputs,
so we can verify the migration produces the same results.

Pour les migrations numériques Python (Pandas, NumPy), pd.testing.assert_frame_equal avec rtol=1e-5 gère la tolérance des flottants sans faux négatifs. Pour les migrations de vues Django, assertContains sur le corps de la réponse détecte la dérive comportementale sans parser le HTML.

Les exceptions de l’exemple illustratif

Dans l’exemple illustratif de 243 fichiers, trois déclenchent des rapports d’exception. Ce sont des résultats illustratifs, pas un taux d’exception observé. Ce qui les distingue des 240 réussites n’a pas d’intérêt général, mais le schéma revient dans les migrations : les exceptions sont des fichiers ayant des dépendances hors du périmètre de l’agent, des schémas absents du brief ou des imports circulaires que le contrôle qualité ne peut pas résoudre isolément.

L’agent coordinateur produit une file d’exceptions : une liste de noms de branches avec leur contenu exception-report.md. Chaque rapport contient le fichier en échec, la sortie exacte du contrôle qualité et une courte description de ce que l’agent n’a pas pu résoudre. Un reviewer humain prend la file et traite chaque cas avec ce contexte déjà chargé.

Les trois exceptions illustratives JSX vers TSX ont des blocages différents. L’une avait un import circulaire signalé par tsc seulement en combinaison avec sa dépendance. Une autre utilisait un type tiers non mis à jour pour prendre correctement en charge les transformations JSX. La dernière dépendait d’un utilitaire dans src/legacy/ absent du brief parce que la phase 1 n’avait pas indexé ce répertoire.

Résoudre chaque exception exige d’examiner sa cause précise ; aucune durée mesurée de résolution n’est attachée à cet exemple. L’alternative était de laisser les trois problèmes dispersés invisiblement dans une session séquentielle, découverts en code review ou après merge.

Ce qui justifie le temps consacré à la phase 1

La planification est utile lorsqu’elle expose dépendances et exceptions avant le début de l’exécution. Sa durée dépend du périmètre du repository, des outils et des contrôles requis ; ce guide ne fournit aucune estimation calibrée.

La phase 1 doit inspecter des répertoires comme src/legacy/, documenter les schémas d’import et signaler les dépendances qui rendent la répartition dangereuse. Revoyez le brief pour les cas manqués ; choisir un modèle de planification ne garantit pas qu’il trouve chaque exception.

Le brief est la spécification des missions bornées. Vérifiez sa couverture de fichiers, ses conventions et ses commandes de contrôle avant lancement, puis utilisez le coordinateur pour l’intégration et les exceptions.

Mesurez entrée, sortie, usage du cache et nouvelles tentatives sur une unité représentative avant de fixer un budget d’exécution. Ne multipliez qu’avec des hypothèses explicites sur les unités restantes et vérifiez les tarifs actuels des fournisseurs. Cet exemple illustratif ne fournit ni télémétrie de tokens ni estimation en dollars.

Le schéma se généralise au-delà des migrations. L’équipe de Stefan Negouai et Sébastien Drode, à Dev With AI, a remonté sa discipline de review d’un niveau pour la même raison : revoir le plan, pas les vingt-quatre diffs qu’il produit. À l’autre extrémité, l’orchestrateur Gastown de Jean-Louis Rigau et Emmanuel Sciara et l’Agentic Factory d’Hubert Grégoire sont la même idée en deux phases avec une infrastructure permanente autour : un registre de travail durable fondé sur Git, des agents spécialisés et un juge LLM au contrôle de merge. Le workflow d’équipes d’agents du guide couvre les schémas d’orchestration plus larges dont ce modèle en deux phases est une application.

Écrivez le brief avant de toucher aux fichiers. Lorsqu’il ne peut pas piloter un contrôle qualité automatique, terminez le brief avant de paralléliser la migration.


YSNK

(Vous devriez maintenant savoir)

  • Le planificateur Opus de phase 1 doit rester strictement en lecture seule. Dès qu’il touche aux fichiers, il commence à prendre des microdécisions qui devraient être des conventions explicites du brief, et les agents de phase 2 héritent d’une spécification incomplète
  • isolation: worktree dans le frontmatter de l’agent crée un worktree neuf par invocation et le nettoie automatiquement si l’agent n’a rien modifié. Sinon, le chemin et le nom de branche reviennent dans le résultat
  • Les worktrees séparent les modifications ordinaires de checkout ; ils n’isolent pas ce qu’un agent peut atteindre une fois lancé : réseau, identifiants dans le périmètre, fichiers hors cible. Les migrations touchant secrets ou scripts de déploiement exigent une couche supplémentaire : conteneur éphémère, montage en lecture seule, liste d’autorisations réseau, quota de temps
  • Mergez les branches prêtes séquentiellement et relancez le contrôle qualité après chacune, pas dans un seul merge octopus. Une branche qui passait isolément peut encore casser le build après l’arrivée des voisines
  • Un test de caractérisation compare certains comportements avant et après migration. Il ne prouve pas l’équivalence du programme entier et ne dispense pas de vérifier l’intégration