rig-epic — workflow de branche d'intégration
Pour les arcs multi-éléments où atterrir chaque élément directement sur le tronc casserait temporairement le contrat d'exécution, empilez les PR enfants sur une branche d'intégration partagée et rebasez cette branche sur le tronc en une seule PR à la fin. Chaque PR enfant est revue comme l'étape qu'elle est réellement ; la livraison vers le tronc est un seul rebasage compressé.
Configuration
Lit .rig/config.json (valeurs par défaut entre parenthèses) :
tracker.provider—linear|github|none(none). Comment les éléments parents/enfants sont stockés.none→ les éléments vivent uniquement dans le fichier d'état de l'epic (ci-dessous) ; aucun appel de tracker.tracker.team/tracker.project/tracker.ticketPrefix/tracker.githubIntegration.vcs.baseRef(origin/main),vcs.defaultBranch(main),vcs.protectedBranchMergeQueue(false).sourceScope[0]— où explorer pendantplan.agents.architect/agents.reviewer(par défautrig-<role>) — pour le panneaureviewen contexte frais.
Délègue à /rig-task (par enfant), /rig-worktree (clonages), /rig-review
/rig-review fix(la revue de diff combinée),/rig-tidy(optionnel).
Fichier d'état de l'epic (remplace toute mémoire externe)
Chaque epic actif est suivi dans un fichier JSON local au dépôt à
.rig/epics/<branche-integration>.json :
{
"parent": "ABC-42 ou un slug dans tracker=none",
"parentTitle": "…",
"integrationBranch": "abc-42-<slug>",
"whyEpic": "quels enfants s'entrelacent et pourquoi",
"children": [
{ "id": "ABC-43", "title": "…", "blockedBy": [], "branch": null, "status": "todo|merged" }
]
}
Ceci est la source unique de vérité que next/run/review/finish/prune
lisent. Ajoutez .rig/epics/ à .gitignore (c'est un état de coordination
transitoire). Inférence du parent (quand <PARENT> est omis) : si exactement un
.rig/epics/*.json existe, utilisez-le ; si zéro ou plusieurs, demandez.
Bannière d'intention : chaque invocation DOIT imprimer une ligne en premier — mode, quelle branche les PR ciblent, ce qu'elle ne fera pas :
rig-epic: <sous-commande> — <action>. Les PR ciblent <branche>. Ne fera pas <chose>.
status (par défaut, lecture seule)
Lit le(s) fichier(s) d'état de l'epic. Rapport : branche d'intégration + commits en
avance sur vcs.baseRef ; PR enfants ouvertes (gh pr list --base <branche-integration>)
et leur état ; statut du tracker de chaque enfant (si un tracker est configuré) ;
worktrees fusionnés/supprimés restants (suggérez /rig-epic prune) ; et une
recommandation en une ligne (ouvrir la PR enfant X, prêt pour /rig-epic next,
ou prêt pour /rig-epic finish). Ne modifie rien ; ne lance rien.
plan <FONCTIONNALITÉ>
Décompose une fonctionnalité en un parent + 3 à 8 enfants, écrit le fichier
d'état, puis enchaîne vers start.
Utilisez ceci uniquement lorsque le travail a vraiment une forme d'epic (les
enfants s'entrelacent — au moins un contrat d'exécution d'un enfant dépend d'un
autre partiellement terminé). Si les éléments sont indépendants et que chacun
peut atterrir seul sur le tronc, arrêtez-vous et dites à l'utilisateur
d'exécuter /rig-sprint plan à la place — même décomposition, pas de branche
d'intégration.
Procédure
- Lire le contexte. Documents produit/spec si le projet en a (demandez si
incertain) ; explorez le codebase (
sourceScope[0]) pour voir ce qui existe. Si un tracker est configuré, recherchez d'abord les éléments quasi dupliqués. - Vérifier que c'est un epic (selon le test d'entrelacement ci-dessus).
Si non → envoyer vers
/rig-sprint plan. - Créer le parent.
tracker: linear/github→ créez l'élément parent (équipe/projet depuis la config) ; la description couvre l'Aperçu, pourquoi-c'est-un-epic et les enfants prévus.tracker: none→ le parent est un slug + titre enregistré uniquement dans le fichier d'état.
- Créer chaque enfant avec ses arêtes de dépendance.
- Assez petit pour une session d'agent (1 à 3 fichiers) ; critères d'acceptation concrets et testables ; travail fondamental d'abord.
- Enregistrez
blockedBypour chaque dépendance réelle — c'est ce quenextlit pour choisir le prochain enfant non bloqué. Sans cela, le choix retombe sur l'ordre de déclaration et obtient des epics entrelacés incorrects. - Mode tracker : définissez les relations parent/bloqué-par natives du tracker
et reflétez-les dans le fichier d'état.
none: fichier d'état uniquement.
- Afficher un tableau récapitulatif (ID · Titre · Dépend de).
- Enchaîner vers
start <PARENT>—planest planifier-et-démarrer ; ne vous arrêtez pas pour demander. - Arrêter après
start. Rapportez la branche d'intégration, les enfants et la prochaine étape (/rig-epic nextpour un seul,/rig-epic runpour la boucle). Ne démarrez jamaisrunautomatiquement — l'exécution est un opt-in explicite.
start <PARENT>
Pré-vol : git fetch origin ; confirmez que le parent et au moins un enfant
existent (dans le tracker, ou comme arguments pour none).
- Nom de la branche d'intégration :
<slug-parent>-<slug-titre>(kebab, ex.abc-42-agent-comme-definition). - Couper la branche d'intégration depuis
vcs.baseRefsans checkout local :
Non destructif. Si la branche existe déjà, laissez-la (ne jamais écraser — pourrait détruire un travail en cours).git fetch origin git push origin <vcs.baseRef>:refs/heads/<branche-integration> - Écrire
.rig/epics/<branche-integration>.json(schéma ci-dessus) avec le parent, pourquoi-cet-epic et chaque enfant +blockedBy. C'est ce qui fait que chaque/rig-task <enfant>cible la branche d'intégration au lieu du tronc. - Si un tracker est configuré, ajoutez une note "Branche d'intégration :
cible
<branche-integration>, pas le tronc" à chaque enfant pour que le prochain agent ne relise pas cette compétence, et assurez-vous que le parent est En Cours (adaptatif : déplacez-le seulement s'il n'a pas déjà commencé ; différer si une intégration en direct l'a fait). Les enfants obtiennent leur propre En Cours depuis leur/rig-taskÉtape 1. - Nommer la session
"EPIC: <titre parent> (<parent>)"viascripts/set-session-name.sh(Claude-Code uniquement ; sans effet ailleurs) pour que la liste des tâches d'arrière-plan lise l'epic. Les enfants définissent leurs propres nomsFEAT:/CHORE:avec--skip-if-prefix "EPIC:", donc cette étiquette d'epic reste en haut. - Rapporter la branche, les enfants et la prochaine étape.
next (enfant unique)
- Résoudre la branche d'intégration active (une attendue ; demandez si
plusieurs). Si la session n'est pas déjà nommée
EPIC:(c'est-à-direnextinvoqué directement, pas viastart), nommez-la"EPIC: <titre parent> (<parent>)"(Claude-Code uniquement). - Choisir le prochain enfant non bloqué : le premier enfant non terminé
dont tous les
blockedBysont fusionnés dans la branche d'intégration. Énoncez le choix + le raisonnement dans la bannière. - S'assurer que l'enfant précédent a atterri. Avec
--auto-merge(Étape 4) chaque PR enfant est fusionnée dans la branche d'intégration automatiquement une fois les CI passées, donc la pointe d'intégration avance automatiquement — faites simplementgit fetch originet confirmez. (Fallback pour un enfant exécuté sans--auto-merge: avance rapide de la branche sur sa pointe —git push origin origin/<branche-enfant-precedent>:refs/heads/<branche-integration>, ce qui ferme automatiquement cette PR comme MERGED. Sûr à réexécuter.) - Exécuter
/rig-task <ENFANT> --base <branche-integration> --auto-merge(ajoutez--spec-clearedlorsque la révision des spécifications préchargée deruna déjà effacé les specs) —--basefait que la worktree de l'enfant provient de, et sa PR cible, la branche d'intégration ;--auto-mergefait que l'enfant activegh pr merge --squash --autosur sa propre PR une fois sa revue propre, donc la CI la fait atterrir dans la branche d'intégration (toujours squash — ne pas faire de merge rebasé ; de nombreux dépôts l'interdisent. Si la branche d'intégration n'a pas de vérifications obligatoires, l'enfant fusionne directement). Exécutez en un seul coup (début→fin) ; il retourne une seule chaîne de résultat pour la porte de fusion. - Porte de fusion — seul
cleanest vert pour fusion :clean→ l'enfant a activé l'auto-merge, donc sa PR atterrit quand CI passe. Attendez : interrogezgh pr view <N> --json state(~60s, jusqu'à ~30min) jusqu'àMERGED, puisgit fetch originet confirmez que la pointe a avancé. Enregistrez l'enfantmerged+ sa branche dans le fichier d'état, et assurez-vous que le ticket de l'enfant est Terminé (adaptatif — déplacez uniquement s'il n'est pas déjà Terminé ; différer si une intégration en direct l'a fermé). Si CI échoue / ne fusionne jamais → traiter comme non-clean.- autre chose (
actionable/timeout, ou un état mis en pause par le tracker) → l'enfant n'a pas activé l'auto-merge ; arrêtez. Affichez le résultat, l'URL de la PR et tout résumé du relecteur. Attendez l'utilisateur ; ne réessayez pas une revue en pause.
next fait exactement un enfant. Utilisez run pour la boucle.
run [--advisor]
Révision des spécifications préchargée — une fois, avant la boucle. Examinez tous les specs des enfants ensemble, en amont, au lieu de découvrir les bloqueurs un enfant à la fois en cours d'exécution. Un enfant qui marque une pause sur une question de spec bloque tout l'epic (et sous exécution parallèle ou durable, un enfant en pause peut faire échouer tout le lot), donc résolvez les specs avant qu'un enfant ne commence à coder :
- Distribuez
agents.architect+agents.qasur les specs de chaque enfant, lus par rapport à la branche d'intégration ; chacun retourne ses bloqueurs. - Consolidez en une liste de bloqueurs et résolvez-la une fois — clarifiez dans le tracker, ou décidez avec l'utilisateur. C'est le point de décision unique des specs de l'epic.
- Ensuite, exécutez chaque enfant avec sa porte de spec pré-effacée :
/rig-task <ENFANT> --base <branche-integration> --auto-merge --spec-cleared, afin qu'aucun enfant ne fasse une nouvelle pause sur une question déjà répondue.
Ce passage de spec pré-codage ; la review de diff combinée (ci-dessous)
est le passage de code post-fusion — des portes différentes.
--advisor (sans surveillance). Décidez de cette porte préchargée avec un
passage conseiller au lieu d'un humain : un agents.architect délégué lit
les specs de l'architecte + QA et soit procède avec une direction synthétisée
par enfant (transmise textuellement au codeur de chaque enfant), soit s'arrête
avec un rapport bloqué nommant ce qu'un humain doit décider. Aucun humain
n'attend, donc l'epic fonctionne sans intervention jusqu'aux PR enfants ; un
véritable bloqueur l'arrête quand même plutôt que de se disperser sur une mauvaise
spec. (Le workflow durable Smithers associé implémente cela avec un modèle bon
marché — le "conseiller Fable" — donc les epics lancés ne restent jamais bloqués
à la porte.)
Ensuite, bouclez next jusqu'à ce qu'il ne reste aucun enfant non bloqué :
tant qu'un enfant non bloqué existe :
exécutez /rig-epic next # les enfants s'exécutent avec --spec-cleared (spec préchargée)
s'il s'est arrêté sans fusionner (résultat ≠ clean) → arrêtez, rendez la main
sinon → réévaluez les enfants non bloqués
Quand la file est vide, rapportez "epic prêt pour /rig-epic finish."
review [<PARENT>]
Exécutez après la fusion du dernier enfant dans la branche d'intégration, avant
finish. La revue par PR (/rig-review dans chaque /rig-task) voit chaque
enfant isolément ; celle-ci voit la forme combinée et la simplification
visible seulement une fois que tout est en place. Les sous-agents en contexte
frais (entrée = le diff compressé + titres des PR enfants) ne peuvent pas
hériter des rationalisations mémorisées de l'implémenteur.
Exécutez avant prune — les sous-agents de revue ont besoin d'un checkout
fonctionnel ; réutilisez une worktree d'enfant si elle existe encore (évite une
nouvelle installation + resymlink d'env).
- Résolvez la branche d'intégration ;
git fetch origin. - Assurez une worktree de branche d'intégration (
$WT). Réutilisez une worktree d'enfant fusionné avancée rapidement à la pointe d'intégration, sinon créez-en une avec/rig-worktree(--base <branche-integration> --reuse). - Distribuez trois sous-agents en parallèle (un message, trois appels
Agent), chacuncddans$WTavec la pointe d'intégration extraite :- Lentille 1 — Simplification (
agents.architect): diffgit diff <vcs.baseRef>...HEAD; liste des PR enfants viagh pr list --base <BR> --state merged. Mandat : trouver les abstractions à réduire, les helpers ajoutés par une PR que la forme finale d'une autre PR a rendus redondants, les boutons de configuration que personne ne définit, les chemins de code que le diff combiné a rendus morts, les types à un seul appelant. Suppressions/fusions concrètes, fichier:ligne, impact le plus élevé d'abord. Ignorez la correction. - Lentille 2 — Correction cross-PR (
agents.reviewer): parcourez le catalogue de motifs de revue du projet (review.patternsFile) par rapport au diff combiné. La revue par PR a déjà été exécutée ; attrapez les interactions visibles seulement à la forme fusionnée (helper de PR-A vs appelant obsolète de PR-D ; PR-B a supprimé un bouton que PR-F lit encore). P0/P1/P2 avec fichier:ligne + catégorie. - Lentille 3 — Code mort et références obsolètes (
agents.reviewer): pour chaque symbole que le diff a ajouté, est-il appelé ailleurs ? Pour chaque symbole supprimé, grep l'arborescence (workflows, manifests, IaC, scripts, docs) pour des références résiduelles. Rapportez avec fichier:ligne.
- Lentille 1 — Simplification (
- Consolidez — dédupliquez, produisez une liste P0/P1/P2 groupée par lentille, imprimez les comptes.
- Triage :
- 0 éléments →
clean — prêt pour /rig-epic finish, arrêtez. - des constats → demandez via
AskUserQuestion:appliquer maintenant/ignorer et terminer quand même(rétrograder en suivi) /pause. Surappliquer maintenant, exécutez/rig-review fix --source localdans$WT(lanceagents.coder, re-revoit jusqu'à propre), commitez +git push origin <branche-integration>, réexécutezreviewune fois pour confirmer la convergence.
- 0 éléments →
- Chaîne de résultat (pour
finish) :clean — …/appliqué — …/en pause — ….
finish [<PARENT>] [--merge]
Compresse toute la branche d'intégration en une seule PR vers le tronc. Défaut : ouvrez la PR et arrêtez — c'est la PR à examiner.
review est une porte dure. finish exécute toujours review en premier
; la PR compressée s'ouvre uniquement sur clean ou appliqué. Sur en pause,
arrêtez et attendez.
- Exécutez
review(porte) en ligne ; branchez sur son résultat (clean/appliqué→ procédez ;en pause→ arrêtez et imprimez les constats en attente). - Rafraîchissez et rebasez si nécessaire.
git fetch origin; listezgit log <vcs.baseRef>..origin/<branche-integration> --oneline. Si le tronc a bougé, rebasez d'abord la branche d'intégration dessus (git rebase <vcs.baseRef>sur une copie locale, puisgit push --force-with-lease origin <local>:<branche-integration>). - Ouvrez la PR finale vers
vcs.defaultBranchavec un titre référençant le parent et un corps résumant tous les enfants. Dans un tracker avec un verbe de fermeture (Fixes <PARENT>/Closes #<n>), incluez-le pour que le parent se ferme automatiquement