auto-dev — une flotte continue qui implémente et fusionne les issues
Ce que ça fait
implement-issue transforme une issue planifiée en une PR prête ; merge-pr fusionne une PR. auto-dev les supervise à grande échelle : N workers en arrière-plan possèdent chacun une issue de bout en bout (implement-issue <N> → merge-pr <PR>) ; dès que la PR d'un worker est fusionnée, il est retiré et un nouveau worker est envoyé sur la prochaine issue en file d'attente — ainsi N issues restent actives sans que vous ayez à surveiller.
La valeur réside dans l'orchestration qu'une simple "boucle" naïve ne peut pas offrir :
- Évitement des conflits — chaque worker concurrent reçoit une issue dans une zone de code différente, donc les branches entrent rarement en collision.
- Ordre de traitement — d'abord les petites issues autoportantes (gains rapides, moins de conflits), puis les moyennes. Les L/XL et les QA manuelles sont exclues par défaut.
- Fusion obligatoire — les workers aiment s'arrêter à "PR prête" (un demi-travail). auto-dev vérifie l'état de fusion réel depuis GitHub à chaque signal et relance tout worker qui a calé.
- Capture hors périmètre — un worker qui trébuche sur un bug non lié le corrige en ligne uniquement dans le cadre de l'exception de
implement-issue(local à un fichier que sa PR modifie déjà et petit, dans son propre commit) et sinon le dépose viacreate-issueplutôt que de l'abandonner, en respectant la barre de dépôt partagée (../_shared/filing-bar.md) afin qu'une flotte de N workers ne dépose pas à N standards différents. Le backlog reste fidèle et vidable (#410). - Hygiène de cycle de vie — les agents terminés sont arrêtés ; un fichier d'état survit aux redémarrages, donc la flotte est reprenable.
Contrat d'autonomie
L'utilisateur démarre ceci et s'en va — il regarde un backlog se vider, il n'approuve pas chaque étape. Exécutez-le sans intervention : choisissez la valeur par défaut raisonnable, énoncez-la, continuez. Arrêtez-vous uniquement pour les blocages réels :
ghn'est pas authentifié, ou vous n'avez pas les droits de push/fusion.- Aucune issue éligible (file d'attente vide après filtrage) — signalez que le backlog est vidé.
- Un blocage dur honnête d'un worker (tests qu'il ne peut pas passer au vert, un conflit où les deux côtés ont réécrit la même logique, une approbation requise qu'il ne peut pas s'auto-attribuer). Signalez-le ; ne forcez pas une fusion.
Ne simulez jamais la progression : une case cochée, un basculement "prêt" ou une fusion prétendent que le travail est terminé — soutenez chacun avec des preuves, comme l'exigent les compétences enfants. La squash-merge est le seul acte irréversible — elle ne se produit que via merge-pr sur une PR verte et fusionnable, jamais via un remplacement --admin ici.
Entrées
- Concurrence
N— workers simultanément. Par défaut 3 (3–4 est le point idéal ; plus = plus de contention et plus de zones à garder disjointes). - Ordre — effort par défaut petit→moyen. Respectez ce que l'utilisateur a dit.
- Ensemble éligible — par défaut : issues ouvertes qui (a) ont un plan d'implémentation, (b) sont des tâches de code (pas "QA" manuelle / "vérifier à la main"), (c) sont dans la limite d'effort (par défaut ≤ moyen). Honorez le rétrécissement ("seulement les issues
studio", "étiquetéespriority: high"). - Battement de cœur — normalement lancé via
loopen mode dynamique, donc le réveil à son propre rythme de la boucle est le battement de cœur. Si invoqué directement, armez votre propre réveil. - Niveau de modèle — par défaut hiérarchisé, pas tout-Opus (voir Économie de tokens) : modèle le moins cher capable pour le mécanique/docs, intermédiaire pour les bugs typiques, haut de gamme réservé pour le travail transversal/difficile + l'escalade d'échecs. Le levier de coût le plus important. Honorez une annulation ("tout sur Opus", "Sonnet pour tout").
Économie de tokens — faites tourner la flotte à moindre coût
Le coût d'une longue exécution est ~83% de lecture de cache de contexte par tour, ~16% de sortie — vous payez pour volume de contexte × tours, pas pour la réflexion. Appliquez ces règles ; la raison complète + les mesures se trouvent dans references/token-economics.md.
Mesuré sur une vraie exécution de 19 fusions (un dépôt .NET/Blazor, N=3, 21 sessions worker, 863M tokens) : 224 tours/session · contexte 30K → 350K · contexte moyen de 181K par tour · 0.55 appels d'outil par tour. La lecture de cache était de 98,3% des tokens. Coût = Σ sur les tours de la taille du contexte, donc les derniers tours coûtent ~10× les premiers et le nombre de tours est superlinéaire — il pilote les deux facteurs à la fois. Classez les leviers par cela, pas par intuition.
Ce titre compte les sessions worker — et l'orchestrateur représentait un tiers de la facture. En intégrant le propre transcript du superviseur dans le même agrégat : une session, 551 messages assistant, ~210K de contexte moyen par message, 33% du coût équivalent à la liste de l'exécution — plus que chaque session worker de premier plan combinée — et il n'a jamais compacté une seule fois sur les 19 fusions. Les dépenses des workers sont biaisées de la même manière : les 3 premières des 37 sessions worker représentaient 32% de tous les coûts worker, et la pire était une issue
effort: mediumsur le niveau intermédiaire, donc ni l'étiquette ni le niveau ne l'ont prédite. Les deux mesures, et les deux budgets comptés qui les délimitent, se trouvent dans references/token-economics.md § Longueur de session.
1. Divisez chaque worker en deux sous-agents : implémentation, puis fusion — le seul levier qui a fonctionné de manière mesurable. Vérifié par A/B, ~11% de tous les tokens des workers. Phase 1 (/auto-dev-worker <N>) s'arrête à une PR prête ; phase 2 (/auto-dev-merge <PR>) la fusionne dans un contexte frais.
| phase de fusion | tours | ctx moyen/tour | cacheRead |
|---|---|---|---|
| avant (18 workers, dans la session d'implémentation) | 27 moy | 247K | 6,6M par worker |
| après (v2 phase 2, session fraîche) | 24 | 71K | 1,7M |
Des nombres de tours presque identiques, donc le contexte par tour est toute la différence : −74% sur la phase de fusion, ≈11% des dépenses totales des workers. Passez le numéro de PR entre les phases via un fichier nommé par l'invite de la phase 1 (repliez-vous sur l'analyse de la ligne de rapport, puis gh pr list --head). Bonus : les deux coins post-achèvement observés dans l'exécution de référence se sont produits dans les derniers tours d'une longue session — des sessions plus courtes coincent moins.
2. Regroupement d'appels d'outil — ESSAYÉ ET N'A PAS FONCTIONNÉ. N'attendez pas de gain ici. Une règle de regroupement stricte avec des exemples a été ajoutée à l'invite du worker et mesurée en A/B : la densité est passée 0,556 → 0,537 appels par tour (phase 1) — c'est-à-dire aucun changement. Gardez la règle (elle ne coûte rien) mais ne budgétisez pas les économies pour elle. Le diagnostic : une densité inférieure à 1,0 ne signifie pas que des appels qui pourraient être regroupés ne le sont pas. ~45% des tours ne font aucun appel d'outil — ce sont des tours de raisonnement/narration — et la plupart des autres sont véritablement séquentiels (éditer → construire → lire l'erreur → corriger). Le gaspillage récupérable est les tours qui ne produisent aucun appel d'outil, ce qui est un problème de verbosité de sortie, pas un problème de regroupement. Si vous attaquez cela, attaquez la verbosité (longueur de réflexion, narration entre les étapes), et mesurez les appels/tour pour vérifier que vous l'avez déplacée.
3. Gardez la sortie des grosses commandes hors du contexte — mesuré 4 262 tokens → ~2 par exécution de test complète. La sortie complète de dotnet test fait ~17K caractères et est relue à chaque tour ultérieur. Ordonnez : journalisez dans un fichier, mettez seulement EXIT + les comptes dans le contexte, grepez le fichier uniquement en cas d'échec. Interdisez explicitement le passage de la commande via tail/head — cela tronque la preuve tout en coûtant des tours.
Périmètre honnête : la réduction par exécution est exacte et vérifiée, mais le gain global dépend de la fréquence à laquelle un worker exécute la suite. Le plus grand résultat Bash unique est passé de 25,2 K à 10,5 K caractères dans l'A/B, tandis que le volume total de résultat d'outil par tour a à peine bougé (722 → 710 caractères) — car l'issue A/B était une tâche de documentation qui exécute rarement des tests. Attendez-vous au gain réel sur les issues lourdes en tests.
4. Hiérarchisez le modèle selon la tâche — réel mais dépendant du niveau, selon token-economics.md : faible entre intermédiaire et petit (0,419 $/Mtok vs 0,168 $/Mtok ≈ 2,5×) ; fort entre haut et intermédiaire (2,376 $/Mtok vs 0,419 $/Mtok ≈ 5,7×). À prioriser pour le travail transversal ; moins impactant pour les bugs de routine. Acheminez par les étiquettes d'issue (adaptez les noms au trio petit/intermédiaire/haut du runtime, par ex. Haiku/Sonnet/Opus) :
| Forme d'issue (par étiquette) | Niveau |
|---|---|
docs/templates/manifest, format & régénération de snapshot, gardes priority:low+effort:S sur une ligne | petit (par ex. Haiku) |
la plupart des bugs : gardes d'émetteur/validateur/analyseur, studio TS, CLI, LSP — effort:S/M ; grandes issues par défaut | intermédiaire (par ex. Sonnet) |
| un niveau inférieur n'a pas réussi à verdir cette issue | haut (par ex. Opus), escalade réactive (une fois) |
| transversal (plusieurs zones/émetteurs), ambigu/conception — un travail qu'un mainteneur sait difficile | haut (par ex. Opus), dernier recours prédictif |
L'orchestrateur (vous) reste sur le modèle haut, mais gardez son contexte par tour petit (levier 2).
5. Réduisez ce qui est relu à chaque tour.
- Taillez le préambule fixe — il est payé à chaque tour de chaque worker.
CLAUDE.mdà 44 Ko (~11 K tok) a coûté 52M tokens en une seule exécution à partir d'un seul fichier ; déplacez le matériel de référence sur le déploiement/secrets/kubectl dans des documents liés et laissez un pointeur. - Pas de TaskList par issue — elle croît sans limite et se réinjecte à chaque tour. Le fichier d'état est votre seule mémoire de travail.
- Compactez délibérément, à un rythme compté — pas sur une sensation. L'entier du rythme a une seule maison, references/token-economics.md § Les deux budgets ; l'étape 4 le déclenche à partir du compteur de fusion du fichier d'état, le même champ compté que le rythme de re-survey utilise déjà. Ne reformulez pas le nombre ici —
tests/auto-dev-cost-budgets/test.shéchoue la construction si vous le faites. Pourquoi compté : le coût est Σ(contexte × tours), donc la queue d'une exécution est superlinéaire, et la règle que ceci remplace — un pourcentage/contextou un rythme suffisamment lâche pour ne jamais se déclencher dans une exécution de 19 fusions — n'a rien borné et a coûté 213 $ en une seule session. Compactez toujours avec une directive de focus, par ex./compact garder la carte slot→issue/PR, compteur de fusion, ordre de file d'attente, suivis déposés. Première action après tout compact //clear/ réémission deloop: relisez le fichier d'état. - Gardez les RAPPORTS FINAUX des workers concis — ils sont relus à chaque tour de réconciliation ultérieur.
- Déléguez les lectures lourdes à des sous-agents
Explorejetables — le vidage de fichier meurt avec le sous-agent au lieu de monter dans votre contexte. - Lancez la session SUPERVISEUR légère — les sous-agents héritent de l'ensemble MCP du superviseur, donc chaque serveur connecté à votre session monte à chaque tour de chaque worker. Le décapage MCP par worker n'est plus disponible (l'outil Agent n'a pas de configuration MCP par spawn) ; taillez-le une fois, là où vous lancez.
6. Prenez moins de tours (chaque aller-retour relit tout le contexte).
- Regroupez les appels d'outil indépendants en un seul tour (lectures/greps/
ghparallèles). - Laissez les scripts réduire requête+classification —
scripts/survey.sh,scripts/reconcile.sh. - Ne sondez pas à un rythme court à moins qu'une fusion ne soit imminente — un réveil inutile relit tout, et passé le TTL de cache d'environ 5 minutes, il paie une écriture de cache complète (1,25×), pas une lecture (0,1×).
- Limitez la session, pas seulement le tour. Le regroupement a été testé en A/B et n'a pas bougé (levier 2), donc l'optimisation par tour est presque épuisée et la longueur de session est la variable qui reste — les 3 premières des 37 sessions worker représentaient 32% de tous les coûts worker, et ni l'étiquette d'effort ni le niveau n'ont prédit lesquelles trois. Les workers de phase 1 portent donc un budget de tours (l'entier vit dans references/token-economics.md § Les deux budgets, pas ici) et passent le relais avec
STATUS: PARTIAL; l'étape 4 les reprend dans un sous-agent frais, ce qui est là où se trouve l'économie — une repriseSendMessagegarde le contexte que le budget est censé jeter. C'est le mécanisme du levier 1, le seul gain vérifié de la section, appliqué à une couture de longueur au lieu d'une couture de phase.
Mesurez-le — ne prétendez jamais qu'un levier fonctionne sans A/B. Trois scripts, prenant tous un répertoire de transcripts de session .jsonl :
scripts/usage_report.py— tokens + équivalent en $ par modèle. Suivez tokens/fusion et $/fusion. ⚠️ Il agrège le RÉPERTOIRE ENTIER du projet, y compris les exécutions passées — liez d'abord une exécution dans un répertoire temporaire, en gardant la disposition : le fichier<sid>.jsonldu superviseur plus son répertoire<sid>/subagents/(<proj>/<sid>/subagents/agent-*.jsonlest l'endroit où vit chaque transcript worker, donc la flotte d'une exécution se trouve sous un seul id — choisissez l'id depuis le fichier d'état ou les horodatagesgh; mtime n'est pas fiable). Un tas plat de liens symboliquesagent-*.jsonlse lit comme0 sous-agentet n'apparie rien.scripts/analyze_cache.py— tours/session, contexte au début vs pic, contexte moyen par tour, et volume de résultat d'outil par outil. C'est là que vous voyez pourquoi une session est coûteuse.scripts/measure_phase2.py— apparie chaque transcript de sous-agent de phase 1 et phase 2 d'une issue (par leISSUE:de leurs lignes de rapport) et divise le coût en phase d'implémentation vs phase de fusion ; sur un transcript pré-2.0, il trouve le tour de transition de fusion dans la session à la place. C'est ce qui a prouvé le levier 1.
Deux métriques portent la plupart du signal : contexte moyen par tour (les derniers tours sont-ils gonflés ?) et appels d'outil par tour (les tours font-ils un travail quelconque ? référence ~0,55 — voir levier 2).
Comment ça fonctionne
┌─────────────────────── auto-dev (vous, le superviseur) ───────────────────────┐
│ fichier d'état : file d'attente (petit→moyen), slots en vol, terminé, déposé │
│ à chaque signal → réconcilier vs GitHub → fin-fusionné + re-remplir → garder N actifs │
└─────────────────────────────────────────────────────────────────────────────────┘
│ répartition (isolée par zone) ▲ rapport structuré / notification d'inactivité
▼ │
Worker A ─ implement-issue → [prêt] ⇢ SOUS-AGENT FRAIS ─ merge-pr → rapport ┐
Worker B ─ implement-issue → merge-pr → rapport ─┤ N agents d'arrière-plan, une issue chacun,
Worker C ─ implement-issue → merge-pr → rapport ─┘ retirés à la fusion, remplacés depuis la file
Les workers sont des sous-agents d'arrière-plan générés avec l'outil Agent. Communiquez via leurs rapports structurés — le message final d'un sous-agent est son rapport, délivré à vous quand il revient — via des notifications d'inactivité, et par SendMessage à un toujours en cours ; ne lisez jamais leurs fichiers de transcript bruts (<proj>/<votre-session>/subagents/agent-*.jsonl) — la sortie d'un worker est un énorme journal qui fera exploser votre contexte. Fiez-vous au rapport...