Feature Loop
skill_version : 8.15.5 (historique : CHANGELOG.md). Implémentation itérative auto-notée d'une feature jusqu'à convergence sur un radar de qualité.
Fichiers du skill (progressive disclosure) : scoring-rubric.md (chargé par le reviewer), lessons.md (instantané publié, promu à la main — la mémoire de travail est hors dépôt dans ~/.claude/skill-memory/feature-loop-lessons.md, chargée par la mère à l'init), reference/subcommands.md (lu au dispatch status/learn), reference/report-template.md (lu au §5.4), reference/git-recipes.md (recettes shell snapshot/restore/conflicts, lues aux §4.2/5.0/5.1bis), reference/log-example.md (trace de run illustrative), reference/limitations.md (lu si contexte concerné), reference/references.md (sources académiques, à la demande), reference/stack-*.md (packs spécialistes — symfony, golang, htmx, javascript, cqrs-es — chargés à l'Étape 2bis selon la stack détectée, combinables).
Architecture (patterns officiels Anthropic, Building Effective Agents) :
- Orchestrator-workers : une mère (Opus, haute réflexion) estime, décompose, délègue à des sous-agents spécialisés, puis synthétise. Elle reste le cerveau ; les workers sont les bras.
- Evaluator-optimizer : boucle générer → évaluer → raffiner, avec un évaluateur distinct du générateur. Valide quand les critères sont clairs et mesurables (notre radar).
- Séparation stricte des rôles : écrivain-code ≠ écrivain-tests ≠ relecteur. Le self-preference bias est prouvé (un modèle qui se juge se surnote). La mère orchestre, ne s'auto-juge jamais.
- Effort proportionné à la difficulté : multi-agents ≈ 15× les tokens d'un chat (Anthropic). On dimensionne modèle + profondeur à l'enjeu → rapide sur le facile, lourd sur le critique.
Sources détaillées (patterns Anthropic, LLM-as-judge, raffinement itératif, tests LLM) : reference/references.md.
PRE-FLIGHT (baseline projet : git clean, deps, build pass)
↓
INIT (clarifier + détecter scope/keywords-sensibles + extraire conventions + lint plugins
+ ESTIMER LA DIFFICULTÉ → tier + modèles (Étape 2bis)
+ charger insights projet + lessons cross-projet + branche in-place [ou worktree si --worktree])
↓
LOOP × max 3 (default, --max-iter ; --fast = chemin court si tier TRIVIAL) :
PLAN (Sonnet) → MINI-REVIEW PLAN (Haiku)
↓
IMPLEMENT CODE (agent A — Sonnet/Opus selon tier) ⟍ agents
ÉCRIRE TESTS depuis la SPEC (agent B ≠ A, dès STANDARD) ⟍ DISTINCTS
↓
GATE OBJECTIF : build/lint/typecheck/tests + RED-CHECK (test critique doit pouvoir rougir)
(lint plugins spécialisés + retry flaky 1×) — PAS de juge LLM si le gate casse
↓
REVIEW BLIND (agent C ≠ A,B — Sonnet défaut / Opus si complexe-sensible)
+ écrit un test adversarial par finding [+ DEVIL'S ADVOCATE si paranoid/auto]
↓
ESCALADE SUR DOUTE (score borderline / désaccord juges / confiance basse / scope sensible
→ 2e juge, puis panel de 3, puis arbitre Opus)
↓
VALIDATION DES PREUVES (anti-hallucination, file:line vérifiés)
↓
DÉTECTION RÉGRESSION / PERSISTANCE / STAGNATION → garder la MEILLEURE version (pas la dernière)
↓
Convergence ? → SUCCESS Régression ? → ROLLBACK + contrainte
↓
next iter (force notes_acknowledged)
↓
SMOKE TEST FINAL (offline build/tests) → SMOKE TEST LIVE (run réel + exercer le chemin) → CONFLICTS CHECK vs main → RAPPORT MARKDOWN → insights + lessons + runs-log + skill_version → user décide
Principes non négociables
Fondements académiques de ces règles : reference/references.md.
- Travail à deux, pas tête baissée : ambiguïté → demander avant de coder. Stopper la boucle pour toute décision produit ou trade-off non technique.
- Honnêteté > faux confort : une solution simple aux limites documentées bat une solution complexe qui se prétend parfaite. Sur-ingénierie constatée à l'usage → reculer proprement (rollback simplificateur, 4.8), pas persister.
- Solution minimale viable avant infrastructure : JAMAIS de parser custom / framework / abstraction avant d'avoir essayé la solution simple. Si elle ne suffit pas, justifier par les cas concrets qu'elle rate.
- Logs temps réel : 1 ligne par sous-étape clé. Pas de silence > 3 min.
- Review en aveugle : le reviewer ne voit JAMAIS le prompt d'implémentation.
- Séparation des rôles writer ≠ tester ≠ reviewer (non négociable) : l'auteur du code ne l'évalue ni ne le teste JAMAIS (self-preference bias prouvé, refs). Donc (a) review = sous-agent au contexte vierge ; (b) tests = sous-agent dédié ≠ auteur dès STANDARD, écrits depuis la SPEC (pas en lisant l'impl) ; (c) sur TRIVIAL/express la mère peut coder ET tester, mais la review reste déléguée (auto-review interdite, toujours).
- Pas de validation sans signal externe : l'auto-correction LLM sans oracle externe dégrade (refs). Aucune itération SUCCESS sur la seule auto-critique : il faut le gate objectif vert (build/lint/tests) ET un juge séparé.
- Le run réel est le signal ultime : pour toute app runnable, gate offline + intg sur DB de test = nécessaires mais PAS suffisants (ils ne voient pas un serveur resté sur l'ancien binaire, une migration non rejouée sur la DB runtime, une erreur de câblage, une intégration que les mocks simulaient). Exécuter l'app réelle et exercer le chemin de bout en bout (smoke LIVE, §5.1b) avant tout SUCCESS « testé ». Live bloqué (auth/creds) → maximum faisable + dire explicitement ce qui reste à confirmer ; jamais « testé » sur la seule foi des mocks.
- Tout test critique doit pouvoir rougir (red-check) : 76 % des tests LLM ratent le fail-to-pass (refs). Avant de faire confiance à un test critique : muter sa ligne cible, vérifier qu'il ÉCHOUE, restaurer. Resté vert = vacant → réécrire. Périmètre : tests critiques seulement (§4.5b).
- Effort proportionné à la difficulté : multi-agents ≈ 15× les tokens d'un chat. Panel, devil's advocate, review Opus, itérations multiples seulement si l'enjeu le justifie. Trivial → mode express (2bis).
- Doute → escalade (panel avant gros modèle) : jugement incertain (score borderline près du seuil, désaccord juges ≥ 2 pts, confiance basse, scope sensible, preuves invalides) jamais accepté tel quel → 2ᵉ juge → panel mixte de 3 → arbitre Opus (§4.6c).
- Garder la meilleure version, pas la dernière : les gains plafonnent après 2-3 itérations et une itération peut régresser → snapshot du meilleur radar (
best_iter_sha), restauré si la dernière est moins bonne. - Preuves obligatoires et vérifiées : tout score < 10 cite
file:line; le skill VÉRIFIE que ces refs existent. - Build/lint/typecheck/tests doivent passer : sinon score robustesse = 0.
- Isolation par branche : in-place sur branche dédiée par défaut (courante si feature branch, sinon
feature-loop/<slug>créée depuis la courante si protégée — develop/main/master). Worktree UNIQUEMENT sur--worktree.run_base_sha+ snapshots → rollback sûr. L'in-place rend les edits visibles live dans l'éditeur de l'user. - Pas de commit/push/merge automatique sur la branche principale, ni sur la branche user en in-place au-delà des snapshots de mécanisme.
- Prompt caching : parties stables (rubrique, conventions, insights) en tête des prompts ; partie variable (diff, findings) en fin.
- Discipline tokens/latence — à qualité égale, le run le moins cher gagne : (a) le reviewer TIRE ses inputs (COMMANDES exactes
git diff <pre_impl_sha>..HEAD -- <scope>+ liste fermée de fichiers), la mère ne colle pas le contenu ; jamais les deux ; re-lecture limitée au scope ; (b) itération corrective → continuer le même juge (SendMessage), pas d'agent frais (§4.6) ; (c) Playwright sobre — snapshots ciblés,curlpour le non-visuel ; clic réel OBLIGATOIRE pour les contrôles UI nouveaux (§5.1b) ; (d) sorties shell tronquées (tail/--filter; suite complète aux seuls gates) ; (e) validation de preuves = grep par la mère, jamais un agent ; (f) paralléliser l'indépendant (A∥B, tools groupés, panel parallèle). - Axes standards + extension : les axes de base (lisibilité, robustesse, modularité, simplicité, YAGNI, tests + scope-specifics) sont obligatoires. +1-3 axes domain-specific possibles, jamais en substitution. Renommer/supprimer un axe standard = interdit.
- Skip Sonnet refusé si paranoid actif : mode paranoid actif → délégation de l'impl à Sonnet non négociable. Sécurité > overhead.
- Mode spécialiste selon l'archi (auto, annoncé) : l'Étape 2bis nomme la combinaison stack+archi et confère à l'impl, au test-writer ET au reviewer une persona d'expert senior + les invariants/pièges d'archi à respecter/vérifier. Écrire idiomatique = moins de bugs à la source (d'où l'application à l'impl, pas au seul reviewer). Auto-détecté, jamais une question de plus.
- Recherche externe permise en cas de doute : un agent qui doute d'une API/version/framework PEUT consulter le web (doc officielle d'abord) plutôt qu'halluciner une signature — mais l'oracle reste le gate objectif + red-check + smoke live, jamais la réponse web. En cas de doute seulement, pas par défaut.
- Pas de "mergeable proprement" sans commit : §5.2 refuse de logger
mergeablesi 0 commit applicatif ; le rapport force un commit final (5.1bis) avant le conflicts check.
Parsing des arguments
Sous-commandes (premier token, pas de boucle d'implémentation) :
status— affiche le tableau de bord des runs passés sur ce repo (lit le runs-log persistant). Voir Étape 6.learn— analyse les runs passés + complètelessons.md, et propose (sans appliquer en silence) des évolutions du SKILL.md. Voir Étape 7.
Mode feature (défaut) :
<description>— description libre de la feature--worktree— force l'isolation worktree git au lieu de l'in-place. Cas d'usage : faire tourner deux runs en parallèle sur le même repo sans collision de branche. Sinon, défaut = in-place sur branche dédiée (voir Étape 3).--paranoid— force le 2e reviewer Opus en devil's advocate (sinon auto-activé sur keywords sensibles)--no-paranoid— désactive le devil's advocate même si keywords sensibles détectés--max-iter=N— override la limite par défaut (3). Augmenter au-delà de 5 nécessite justification : les iter 4-5 apportent peu en pratique (observé sur runs réels : converge en 2-3, ou MAX_ITERATIONS valide avec limites documentées).--threshold=N— override le seuil de SUCCESS par axe (8)--fast— force l'évaluation en mode express (Étape 2bis) et supprime les confirmations d'avant-boucle. Le mode express s'active DÉJÀ tout seul sur une tâche TRIVIALE sans keyword sensible (cf. 2bis) ;--fastne fait que sauter la confirmation et l'imposer si l'estimation hésite. Refusé dès qu'un keyword sensible apparaît.--judge=sonnet|opus— override le modèle du reviewer par défaut (défaut : Sonnet, escalade auto sur doute).--judge=opusforce Opus à chaque review (plus lent/cher, qualité de jugement max).--no-redcheck— désactive le red-check (4.5b) sur les tests critiques. Déconseillé : c'est le garde-fou anti tests vacants. Utile seulement sur un projet où la mutation est impraticable (build trop lent, pas d'exécution ciblée possible).--issue=N— charge l'issue GitLab/GitHub #N comme SPEC (glab issue view N, ough issue view Nsi le remote est GitHub : titre + description deviennent la description de la feature). Si une branche liéeN-*existe (créée parglab mr create --related-issue, ex. via le skill projetissue-mr), elle devient la branche de travail (Étape 3). Voir Étape 1 pour le pont issue-mr quand la spec est vague.
Logs utilisateur (principe)
Préfixes : [preflight], [scan], [init], [tier], [iter N/max], [plan], [impl], [tests], [gate], [redcheck], [review], [devil], [escalade], [evidence], [converge], [best], [smoke], [smoke-live], [commit], [conflicts], [report], [insights], [lessons], [runs], [done]. Sous-commandes : [status], [learn]. Pas d'emojis. Style factuel.
Exemple complet d'une trace de run de bout en bout : reference/log-example.md.
Étape 0 — Pre-flight check (baseline projet)
Avant tout vérifier que le projet est dans un état exploitable. Si non, le skill ne peut pas mesurer ses propres changements.
Log : [preflight] vérification baseline...
Checks dans le repo principal (avant tout choix de branche / worktree) :
- Git clean :
git status --porcelain. Si modifs non commitées →AskUserQuestion: "Le repo a des modifications non commitées. Options : 1) commit avant de continuer / 2) stash temporaire (récupéré à la fin) / 3) annuler". - Deps installées : présence de
node_modules/(Node),vendor/(PHP), équivalent selon stack. Si pas installé → proposernpm install(ou équivalent) puis continuer. - Baseline build pass : lancer build + lint + typecheck + tests sur HEAD actuel — la MÊME suite que le gate 4.5 exécutera (tags d'intégration inclus, ex.
go test -tags intg, si le gate les lancera). Une baseline partielle fait découvrir les échecs préexistants en pleine boucle → diagnostic stash coûteux (et ungit stashsans-ulaisse les fichiers untracked qui cassent la compile — toujours-u). Si ÉCHEC →AskUserQuestion: "Le projet ne passe pas son propre build/lint/tests sur HEAD. Options : 1) corriger d'abord (skill ne peut pas comparer un avant/après sur base cassée) / 2) continuer quand même — si l'échec est PRÉEXISTANT et hors de la zone touchée, le documenter et l'exclure du verdict de gate / 3) annuler".
Check piège vendor/node_modules symlink : UNIQUEMENT en mode --worktree. APRÈS création du worktree (étape 3), vérifier :
for dep in vendor node_modules; do
if [ -L "$WORKTREE/$dep" ]; then
REAL=$(realpath "$WORKTREE/$dep")
MAIN=$(realpath "$REPO_MAIN/$dep")
[ "$REAL" = "$MAIN" ] && echo "WARN: $WORKTREE/$dep symlinked to main → autoloader/require résoudra vers /main/src, runtime test des modifs entités IMPOSSIBLE"
fi
done
Si symlink détecté → logger [preflight] WARN: <dep> symlinked to main — limitation runtime test (voir Limitations connues). Ne pas BLOQUER (juste avertir l'agent + reviewer pour qu'ils en tiennent compte).
En mode in-place (défaut) : ce piège n'existe pas — le repo principal utilise son vrai vendor//node_modules, les tests runtime des modifs sont fiables. C'est un avantage concret de l'in-place sur les monorepos go.work + vendor.
Détecter règle CLAUDE.md user "no auto-commit" : lire ~/.claude/CLAUDE.md (global user) ET <repo>/CLAUDE.md (projet) si présents. Chercher des patterns comme :
INTERDIT git add/interdit git commitsans permission explicitel'utilisateur valide/l'user décidene commit pas/pas d'auto-commit
Si détecté → flag no_auto_commit: true dans le journal. Conséquence : l'étape 5.1bis ne force pas le commit, elle propose le message à exécuter manuellement. Voir 5.1bis pour le détail. Logger [preflight] règle user "no auto-commit" détectée → mode proposition manuelle pour le commit final.
Loguer le résultat de chaque check. Si tout ok : [preflight] baseline OK.
Étape 1 — Clarifier la feature + détection sensibilité
Récupérer la description (args du skill ou demander).
Spec depuis une issue (--issue=N) : glab issue view N (GitLab) ou gh issue view N (GitHub, selon le remote) → le titre + la description de l'issue DEVIENNENT la description de la feature (une issue au format analyse — constat/pourquoi/périmètre/plan — passe le test de clarté d'office). Logger [init] spec chargée depuis issue #N (<titre>). Échec glab/gh (issue inexistante, pas de remote) → le dire et retomber sur la description libre.
Test de clarté — la description doit répondre à :
- Quoi : ce qui doit exister à la fin
- Qui : utilisateur cible
- Pourquoi / contraintes : exigences non triviales
- Périmètre : ce qui est EXCLU
Si une réponse manque → AskUserQuestion.
Pont issue-mr (spec vague) : si le test de clarté échoue sur ≥ 2 points ET qu'un skill issue-mr est disponible (global depuis sa v2.0.0 — mode ANALYSE) → proposer via AskUserQuestion de l'invoquer MAINTENANT, avant la boucle : l'analyse explore le code, tranche la conception avec l'user et produit une issue structurée qui devient la SPEC ; la branche <issue>-<slug> créée devient la branche de travail (Étape 3). Bénéfice : le plan 4.3 converge plus vite et l'agent B (tests-depuis-la-spec) teste un vrai contrat. Contraintes : invocation par la mère en conversation principale UNIQUEMENT (un sous-agent ne peut pas invoquer de skill), et UNIQUEMENT ici — jamais au milieu de la boucle (l'interactivité d'issue-mr casserait l'autonomie). Refus user → clarifier par AskUserQuestion classiques.
Détection de keywords sensibles : la description et le scope contiennent-ils un de :
auth, password, payment, payer, paiement, stripe, token, permission, role, crypto, hash, secret, pii, gdpr, rgpd, migration, sql, admin, audit, acl, oauth, jwt, session, csrf, xss ?
Si oui ET pas de --no-paranoid → activer automatiquement le devil's advocate (paranoid: true dans le journal). Logger [scan] keywords sensibles détectés (<liste>) → --paranoid auto-activé.
Calibrage migration/sql : ces deux keywords sur-déclenchent — une migration purement additive (ADD COLUMN ... DEFAULT, index) est à bas risque et ne justifie pas SENSIBLE (review Opus + DA + panel ≈ 3-4× le coût). Si migration/sql sont les SEULS keywords détectés → ne pas forcer : qualifier le risque réel (additive vs ALTER destructif / UPDATE-DELETE de données / changement de type) et proposer le choix paranoid on/off via l'AskUserQuestion de l'Étape 2, avec cette qualification et une recommandation. Les autres keywords (auth, payment, secret, pii…) continuent de forcer l'auto-activation.
Étape 2 — Auto-détection scope + axes + conventions + lint plugins
Log : [scan] détection stack en cours...
Scanner en parallèle :
- Stack :
package.json,Cargo.toml,pyproject.toml,go.mod, etc. - Front / Back / Tests / E2E / Conventions (voir liste détaillée plus bas)
Framework de tests : détection sur vitest.config*, jest.config*, pytest.ini, playwright.config*, etc.
Si AUCUN framework de tests détecté avec confiance → AskUserQuestion :
"Aucun framework de tests détecté. Options : 1) initialiser Vitest (ou équivalent cohérent avec la stack) / 2) framework personnalisé (à préciser) / 3) désactiver l'axe tests pour ce run".
Ne JAMAIS installer un framework non confirmé par l'user — éviter le mismatch (Vitest installé sur projet Jest, etc.).
Lint plugins disponibles : parser package.json (devDependencies + dependencies) à la recherche de :
eslint-plugin-jsx-a11y→ a11y métriqueseslint-plugin-security→ security métriqueseslint-plugin-react-hooks→ robustesse hookseslint-plugin-import→ cycles / imports@typescript-eslint/eslint-plugin→ règles TS strictes- équivalents Python (
bandit,pylint-security) ou Go (gosec)
Lister ceux dispos. Ils seront lancés à l'étape 4.5 et nourriront la review. Pas d'install automatique — si manquant, l'axe correspondant reste 100% qualitatif.
Log : [init] N conventions extraites, M lint plugins dispos (<liste>).
Déduire :
- Scope : backend / frontend / fullstack
- Axes activés : voir
scoring-rubric.mdpour les barèmes à ancres concrètes.- Standards (toujours présents) : lisibilité, robustesse, modularité, simplicité, YAGNI, tests.
- Packs conditionnels (activer seulement les pertinents) :
- Front : UX/UI, contraste, aéré, responsive, doc-utilisateur, a11y (sur screenshots multi-viewport).
- Sécurité/OWASP : si keywords sensibles OU sortie consommée par un tiers (rubrique = checklist OWASP).
- Performance, observabilité : selon scope.
- Pack user-facing (repris d'outil-factory, si la feature produit une UI/contenu vu par un utilisateur final, typiquement un produit public) : i18n (si multilingue), copywriting (si texte user), SEO (si page publique), CTA/conversion (si page à objectif de conversion — rare en interne). Une route API n'active AUCUN de ces axes.
- Axes domain-specific (optionnel) : l'agent peut proposer 1-3 axes complémentaires si la feature a une dimension propre (ex: "résilience anti-bot/WAF" pour scraping, "Compat couche pure" pour refacto avec API publique stable). Chaque axe additionnel doit avoir une rubrique 0-10 explicite définie AVANT l'impl et stockée dans
.feature-loop.jsonau champaxes_custom. Substitution interdite : jamais retirer/renommer un axe standard. L'axe "valeur vs concurrence" (outil-factory) n'est disponible que sur demande explicite (produit public comparable), jamais d'office. - Conventions : extraire 3-5 patterns concrets du codebase (composant, test, error handling, validation, styling)
Présenter via AskUserQuestion :
Scope détecté : <fullstack>
Stack : <...>
Axes activés (N) : <liste>
Conventions extraites : <paths>
Lint plugins dispos : <liste>
Mode paranoid : <on/off> (auto si keywords sensibles)
→ Confirmer / Ajuster ?
Mode express (2bis) : sauter cette confirmation — logger le récap (scope/stack/tier) et continuer directement. L'user interrompt s'il veut ajuster.
Étape 2bis — Estimation de difficulté + dimensionnement des modèles
But : proportionner l'effort à l'enjeu (multi-agents ≈ 15× les tokens d'un chat — Anthropic). La mère estime AVANT d'agir, puis fixe le tier, les modèles et la profondeur. Règle : estimer → dimensionner → déléguer → vérifier → réajuster.
Estimer sur 4 dimensions (basse/moyenne/haute)
- Complexité de raisonnement : logique subtile, algo, archi vs CRUD/copie mécanique.
- Volume / contexte : nombre de fichiers, lignes, surfaces touchées.
- Risque si erreur : sécurité, données, paiement, migration, prod-facing vs cosmétique réversible.
- Parallélisable : sous-tâches indépendantes (→ fan-out workers) vs séquentiel.
Tier résultant (inscrit au journal : difficulty_tier)
| Tier | Signature | Profondeur boucle |
|---|---|---|
| TRIVIAL | mécanique, < 50 LOC, ≤ 2 fichiers, risque nul, 0 keyword sensible | mode express d'office (cf. ci-dessous) |
| STANDARD | feature normale, logique modérée, risque limité | boucle 1–2 itérations, 1 reviewer Sonnet |
| COMPLEXE | raisonnement lourd OU large surface OU archi transverse | boucle complète, reviewer Opus, escalade possible |
| SENSIBLE | keyword sensible (auth/paiement/crypto/migration/données…) OU risque élevé | boucle complète + devil's advocate + panel d'office ; jamais de chemin court |
paranoid (Étape 1) force SENSIBLE. Présenter le tier à l'user en Étape 2.
Dimensionnement des modèles (rôle × tier)
La mère tourne toujours sur le meilleur modèle disponible (= le modèle de la session — Opus, Fable…, haute réflexion) — orchestration, arbitrages, synthèse, décision finale. Elle délègue les bras :
| Rôle (sous-agent) | TRIVIAL | STANDARD | COMPLEXE | SENSIBLE |
|---|---|---|---|---|
| Plan | (mère) | Sonnet | Sonnet | Sonnet |
| Mini-review plan | — | Haiku | Haiku | Haiku |
| Impl code (agent A) | mère* | Sonnet | Sonnet/Opus | Sonnet/Opus |
| Tests (agent B ≠ A) | mère* | Sonnet | Sonnet | Sonnet |
| Review (agent C ≠ A,B) | Sonnet** | Sonnet | Opus | Opus |
| Devil's advocate / panel | — | si doute | si doute | d'office |
* TRIVIAL : la mère peut coder ET écrire les tests, MAIS la review est obligatoirement déléguée (agent ≠ mère). Dès STANDARD, l'agent tests (B) est distinct de l'agent code (A). ** même TRIVIAL passe par un reviewer distinct : on n'économise jamais la séparation des rôles, on économise sur le MODÈLE et la PROFONDEUR.
Tiers sémantiques (robustesse aux générations de modèles) : les noms de la table = mapping par défaut au moment d'écrire — lire Haiku = tier rapide/mécanique, Sonnet = tier standard, Opus = tier raisonnement max. Si la session tourne sur un modèle plus récent/capable (ex. Fable 5), la mère = le modèle de la session, et chaque rôle prend le meilleur modèle disponible de son tier (paramètre model du tool Agent).
--judge=opus force la review en Opus quel que soit le tier. Inversement le reviewer Sonnet reste le défaut (rapide), l'escalade (§4.6c) monte en puissance seulement sur doute.
Reconnaissance d'archi → persona spécialiste
Le tier choisit quel modèle ; la persona choisit quelle expertise. À partir du [scan] (Étape 2), nommer la combinaison stack + archi dominante (CQRS/ES, hexagonal, event-driven, Shopify/Stripe, Next/tRPC…) et la consigner au journal (specialist_stack). Quand elle porte des invariants propres :
- Auto-activé et annoncé, sans question supplémentaire (l'Étape 2 a déjà son AskUserQuestion ; on n'en rajoute pas). Logger
[tier] mode spécialiste: <stack> → personas expertes (impl/tests/review). - Persona experte par rôle : les briefs de l'implémenteur (4.4), du test-writer (4.4b) et du reviewer (4.6) reçoivent « expert senior 10+ ans de » + une courte liste d'invariants/pièges de l'archi à respecter/vérifier en priorité. Exemples : CQRS/ES → idempotence des commandes, immutabilité/rejouabilité des events, cohérence projection↔agrégat, sagas/effets rétroactifs ; Shopify → pagination/éviction, normalisation E.164, scopes, throttling, champs version-dépendants de l'Admin API ; front → hydratation, a11y, états de chargement. La mère établit cette liste (elle PEUT s'appuyer sur une recherche web ciblée si la stack lui est peu familière, cf. principe « recherche externe »).
- Généraliste si aucune archi marquante (CRUD simple) : on ne force pas une persona artificielle.
- Packs spécialistes fournis : quand un pack
reference/stack-<nom>.mdexiste pour la stack détectée, la mère le LIT à ce moment et en injecte les sections par rôle dans les briefs (impl → invariants impl, tests → invariants tests, review → checklist, gate → commandes). Disponibles :stack-symfony.md(Symfony/Doctrine/Twig),stack-golang.md(Go 1.21+, erreurs silencieuses qui compilent),stack-htmx.md(API basse fréquence = hallucinations max),stack-javascript.md(vanilla front, erreurs silencieuses async/Unicode),stack-cqrs-es.md(pack d'ARCHITECTURE, se combine avec un pack langage — ex. Go+CQRS sur un même projet : charger les deux). Un pack prime sur la liste d'invariants improvisée par la mère ; il s'y AJOUTE des invariants projet (CLAUDE.md) sans les remplacer.
Mode express (auto sur TRIVIAL, ou forcé par --fast)
But : ne pas sortir l'artillerie sur un ticket simpliste. Déclenché d'office quand le tier est TRIVIAL ET 0 keyword sensible — pas besoin de --fast (qui ne fait que sauter les confirmations et l'imposer si l'estimation hésite).
Chemin court : pas de confirmation Étape 2 (logger le scope+tier détectés et continuer ; axes = standards seuls) → pas de dimensionnement élaboré → pas de phase PLAN ni mini-review Haiku (surdimensionné pour < 50 LOC) → impl + tests par la mère si les critères d'auto-impl (4.4a) sont réunis, sinon agent A (code) + agent B (tests) → gate objectif (build/lint/tests + red-check sur LE test du comportement principal) → UNE review déléguée en aveugle → si gate+review verts : SUCCESS en 1 itération, pas de devil's advocate ni panel. Smoke offline obligatoire ; live seulement si runnable trivialement. Rapport court (statut + radar + fichiers + commit proposé), pas le template complet.
Garde-fous JAMAIS sacrifiés en express : séparation reviewer ≠ writer (auto-review interdite, même quand la mère code), gate objectif avant la review, preuves file:line, respect de no_auto_commit. Bascule hors express dès qu'un keyword sensible OU un overflow (loc_real > loc_planned*1.5) apparaît en cours → reprise en boucle standard. Logger [tier] mode express (TRIVIAL) → review déléguée maintenue, reste allégé.
Escalade de modèle en cours de route (la mère peut changer d'avis)
Si un agent Sonnet rend un travail superficiel/faux, ou si une review est incertaine, relancer avec Opus ou un panel. L'estimation initiale n'est pas un contrat figé (cf. §4.6c et boucle adaptative). Logger [iter N/max] escalade modèle : <rôle> Sonnet→Opus (raison).
Étape 3 — Charger insights + lessons + espace de travail + journal
Mémoire cross-runs (par projet) : chercher ~/.claude/projects/<encoded-cwd>/memory/project_feature_loop_insights.md (encoded-cwd = path absolu avec / → -).
Si existe : Read, parser, passer comme contexte aux prompts impl/review. Logger [init] insights projet chargés (N patterns).
Meta-leçons cross-projet : lire ~/.claude/skill-memory/feature-loop-lessons.md (hors dépôt) (créer avec un header minimal s'il n'existe pas). Ces leçons portent sur comment piloter la boucle (indépendant du projet) — les passer en tête des prompts impl/review (zone stable, cache-friendly). Logger [init] lessons cross-projet chargées (N leçons).
Espace de travail : in-place (défaut) ou worktree (--worktree)
Enregistrer run_base_sha = $(git rev-parse HEAD) AVANT toute modification (permet un reset propre au "jeter").
Mode in-place (défaut) — le repo principal EST l'espace de travail, les edits sont visibles live dans l'éditeur de l'user :
- Déterminer la branche de travail :
- Si la spec vient d'une issue GitLab (
--issueou pont issue-mr, Étape 1) et qu'une branche liée<issue>-*existe (locale ouorigin/) →git fetch originpuis checkout de cette branche : la convention projet (<issue>-<slug>, MR liée) prime surfeature-loop/<slug>. Logger[init] in-place : branche issue <branch> checkout (base <sha-court>).- Garde repo sale : si le repo principal porte des modifs non commitées ÉTRANGÈRES à cette feature (WIP d'une autre session/branche), un checkout les embarque (ou échoue) et le diff/commit final mélangerait les deux travaux → proposer d'office le mode worktree. Worktree sur une branche EXISTANTE :
git worktree add .claude/worktrees/<slug> <branche-issue>puisEnterWorktreeavecpath:(EnterWorktree seul crée une branche NEUVE depuis la base par défaut — il ne sait pas checkout une branche existante). Si la branche issue est déjà checkoutée dans le repo principal, l'y libérer d'abord en parquant le WIP sur une branche locale au même commit (git switch -c wip-parking, zéro modif du working tree) — jamais de stash du travail d'une autre session.
- Garde repo sale : si le repo principal porte des modifs non commitées ÉTRANGÈRES à cette feature (WIP d'une autre session/branche), un checkout les embarque (ou échoue) et le diff/commit final mélangerait les deux travaux → proposer d'office le mode worktree. Worktree sur une branche EXISTANTE :
- Si la branche courante est protégée (
develop,main,master, ou la "Main branch" déclarée dans<repo>/CLAUDE.md) →git checkout -b feature-loop/<slug>depuis la courante. Logger[init] in-place : branche <base> protégée → feature-loop/<slug> créée+checkout (base <sha-court>). - Sinon (déjà sur une feature branch) → rester dessus. Logger
[init] in-place sur branche courante <branch> (snapshots de mécanisme créés ici, squashables en fin de run).
- Si la spec vient d'une issue GitLab (
$WORK= racine du repo. Pas decd.- Rollback (4.8) = reset/revert vers le
pre_impl_shade l'iter, dans l'arbre vivant.
Mode worktree (--worktree) :
EnterWorktree(name: "feature-loop-<slug>").$WORK= path du worktree. Lancer ensuite le check symlink vendor/node_modules (Étape 0).- Cas d'usage : deux runs en parallèle sur le même repo sans collision.
Artefacts de run (les deux modes) : .feature-loop.json (journal) et feature-loop-report.md (rapport) vivent sous $WORK/.feature-loop/. En in-place, s'assurer que .feature-loop/ est ignoré par git (l'ajouter à <repo>/.gitignore s'il n'y est pas) pour ne PAS polluer les commits applicatifs. Le runs-log persistant, lui, vit hors arbre (Étape 6).
Créer $WORK/.feature-loop/.feature-loop.json :
{
"feature": "...",
"started_at": "<ISO>",
"scope": "...",
"stack": { "lang": "...", "framework": "...", "tests": "...", "e2e": "...", "lint_plugins": ["..."] },
"axes": ["..."],
"threshold": 8,
"max_iterations": 3,
"difficulty_tier": "standard",
"specialist_stack": "<ex: Shopify + CQRS/ES en Go | null si généraliste>",
"judge_model": "sonnet",
"paranoid": true,
"paranoid_auto_triggered_by": ["auth", "token"],
"best_iter_sha": null,
"best_radar": null,
"escalations": [],
"work_mode": "in_place",
"work_path": "<repo root ou worktree path>",
"branch": "feature-loop/<slug> ou branche courante",
"branch_created": true,
"run_base_sha": "<sha HEAD avant toute modif>",
"conventions": [{ "path": "...", "purpose": "..." }],
"project_insights": "<contenu ou null>",
"lessons_loaded": 5,
"baseline": { "build": "pass", "lint_errors": 0, "tests_passed": 47 },
"iterations": [],
"rollback_counts": {},
"persistent_critics": {},
"final_status": "in_progress"
}
Étape 4 — Boucle d'itération (max 3 par défaut, configurable via --max-iter)
4.1 Construire le prompt d'implémentation
Structure cache-friendly — placer en tête (stable) :
- Description courte de la feature
- Conventions extraites (paths + extraits)
- Project insights (cross-runs)
- Rubrique des axes (résumée)
- Contraintes (CLAUDE.md)
- Charte du code (bloc ci-dessous, verbatim)
Charte du code (les conventions du projet priment en cas de conflit) :
- Le nom EST l'explication : teste-le sur 3 questions (pourquoi il existe / ce qu'il fait / comment l'utiliser) — si un commentaire décrit le quoi, renommer au lieu de commenter. Après une fusion/délégation qui fait gagner un nouvel appelant à une fonction existante, re-tester son nom contre TOUS ses appelants (pas seulement le premier) : un nom fidèle à un seul usage devient trompeur une fois partagé.
- Fonction profonde : petite surface (un appel), beaucoup de travail caché. Découper sans exposer — le sur-découpage (helpers que l'appelant doit enchaîner, méthodes siamoises) est un défaut au même titre que la fonction-fleuve.
- Commentaires, 3 genres seulement : le pourquoi (décision non évidente), l'avertissement (piège, ordre à ne pas casser), le contrat (ce que la fonction promet). Jamais de paraphrase ; 1 ligne par défaut ; dans le doute, ne pas commenter. Un commentaire long et pénible à écrire signale une abstraction ratée : reconcevoir plutôt que documenter.
- Erreurs : quand la sémantique le permet, faire disparaître le cas d'erreur (borner, valeur par défaut, null object) au lieu d'imposer des checks à chaque appelant — tirer la complexité vers le bas, dans le module.
- DRY = savoir, pas code : deux fragments identiques qui évolueront pour des raisons différentes ne sont PAS une duplication — ne pas les fusionner. Boussole ETC : « est-ce plus facile à changer après ? »
- Boy-scout borné au périmètre : dans les zones touchées, supprimer les commentaires morts/paraphrases existants ; ne rien nettoyer hors scope.
Puis en queue (volatile) : 7. État spécifique à l'itération (critiques précédentes, notes_for_implementer, scores cibles)
Cette structure permet à Anthropic prompt cache de réutiliser le préambule sur toutes les itérations.
Itération 1 : prompt = préambule + exigences de base (tests, build pass, front → Playwright).
Itération N>1 : prompt = préambule + critiques classifiées du tour précédent + notes_for_implementer du tour précédent + contraintes anti-régression (axes ≥ N à préserver) + résumé des tentatives précédentes.
Forçage notes_acknowledged au tour N>1 : ajouter explicitement au prompt :
"Tu DOIS retourner un champ
notes_acknowledgedqui liste, pour CHAQUE note du tour précédent, comment tu l'as appliquée dans cette implémentation. Format :[ { note: '...', applied_at: 'file:line', explanation: '...' } ]. Si tu ne peux pas appliquer une note, dis-le explicitement avec la raison."
Si retour vide ou évasif (toutes explanation génériques) → re-prompt avec emphase. Si toujours évasif → flag dans le journal notes_ignored: true, à mentionner au reviewer.
Calculer prompt_hash. Si déjà vu → reformuler avec variation.
4.2 Snapshot pré-implem
Le snapshot permet le rollback/restore. Sa forme dépend de no_auto_commit (détecté au pre-flight) :
Mode 1 — no_auto_commit: false (défaut) : commit de mécanisme.
git add -A && git commit --allow-empty -m "feature-loop iter-N pre-impl" --no-verify
--no-verify est volontaire : un snapshot de mécanisme ne doit pas être bloqué par un pre-commit hook applicatif. Noter le SHA dans pre_impl_sha.
Mode 2 — no_auto_commit: true (règle user « pas d'auto-commit ») : ne pas polluer l'historique de la branche de l'user, mais le snapshot doit rester sûr (anti perte de données : capturer aussi l'untracked, survivre au git gc, marcher même sur arbre propre). On crée donc un commit-objet sur une ref technique dédiée hors-branche (jamais sur HEAD, jamais dans git log de la branche) — commandes exactes : reference/git-recipes.md §4.2 Mode 2 (capture tracked+untracked via index temporaire → commit-tree → update-ref refs/feature-loop/snap-iter-N). Préféré à git stash create (non-ancré donc gc-able, rate l'untracked, chaîne vide sur arbre propre). La branche de l'user n'est PAS modifiée (HEAD, index réel, git log intacts).
Rollback (4.8) et restore best (5.0) sur ce snapshot = restaurer le tree de pre_impl_sha/best_iter_sha dans le working tree après sauvegarde de l'état courant (jamais de checkout -- . aveugle, cf. 5.0). Nettoyage en fin de run : git for-each-ref refs/feature-loop/ | … git update-ref -d (supprimer les refs techniques). Logger [iter N/max] snapshot ref-technique (no_auto_commit) <sha-court>.
4.3 Phase PLAN (Sonnet) + MINI-REVIEW (Haiku)
Mode express (2bis) : sauter 4.3 entièrement — pas de plan formel ni de mini-review Haiku (la mère implémente directement, 4.4a). Reprendre à 4.4.
Log : [iter N/max] plan Sonnet...
Sonnet retourne { plan, files, tests, risks, confidence }.
Sanity check basique : paths cohérents, confidence ≥ 6.
Puis mini-review Haiku :
Agent(
subagent_type: "general-purpose",
model: "haiku",
description: "feature-loop plan check iter N",
prompt: <prompt court>
)
Le prompt :
- "Voici la feature demandée : <description en 1-2 phrases>"
- "Voici le plan proposé par un autre agent : "
- "Voici 3 conventions du projet (extraits) : "
- "Vérifie 3 points : (a) le plan adresse-t-il la feature complètement ? (b) les fichiers cités sont-ils les bons (pas de fichier random, paths cohérents) ? (c) le scope est-il minimal (pas de refacto opportuniste) ?"
- "Réponse JSON :
{ verdict: 'ok'|'concerns'|'reject', concerns: [...], blocking: boolean }"
Si verdict: 'reject' ou blocking: true → renvoyer le plan à Sonnet avec les concerns Haiku, demander un plan révisé. Max 2 révisions de plan, après quoi escalation user.
Log : [iter N/max] mini-review Haiku : <verdict>.
Si OK → continuer.
4.4 Phase IMPLEMENT — agent A (code)
Log : [iter N/max] impl code (agent <modèle>)...
Modèle selon le tier (Étape 2bis) : Sonnet (STANDARD), Sonnet/Opus (COMPLEXE/SENSIBLE), mère (TRIVIAL seulement). Mêmes obligations qu'avant (build pass, conventions, scope minimal, STOP_NEED_CLARIFICATION possible).
Persona + recherche : si specialist_stack est défini (2bis), briefer l'agent A en « expert senior 10+ ans de » et lui passer la liste d'invariants/pièges d'archi à respecter (écrire idiomatique = moins de bugs à la source). En cas de doute sur une API/un flag/une version, une recherche web ciblée est permise (doc officielle d'abord) plutôt que deviner une signature — mais le gate objectif + les tests de B restent l'or
…(truncated)