Ik wil een marathon draaien
Laat Claude autonoom door je backlog werken — plannen, bouwen, reviewen, finishen, en door naar het volgende issue. Volgorde komt uit de dependency-graph (is_blocked_by Work Item links), priority en leeftijd. Niet uit grootte.
Steps
Start een marathon:
/spexso-marathonOf start met een specifiek eerste issue:
/spexso-marathon 42Voor één enkel issue autonoom (zonder ketting): gebruik
/spexso-start 42 --yolo.Zelf kiezen wat er gebouwd wordt:
/spexso-marathon --issues 45,47,46 # exact deze issues, in deze volgorde, daarna stop /spexso-marathon --milestone "Escalations" # alleen deze marathon (spexso/Escalations), gewone picker-volgordeBij
--issuesis jouw lijst de volgorde — maar blockers blijven gelden: een issue met een open blocker wacht tot die gesloten is (een blocker verderop in de lijst gaat dus eerst; een blocker buiten de lijst eindigt in de deadlock-melding). Lijst-issues die niet in aanmerking komen (verkeerde stage, toegewezen aan iemand anders, gesloten) zie je onder Not queued met de reden. Onderbroken? Draai hetzelfde commando opnieuw — afgewerkte issues zijn niet meerstage::specen worden overgeslagen. Combineer met--previewom de volgorde eerst te zien, en metparallel.budgetom parallel te bouwen.Eerst kijken wat de marathon zou doen?
/spexso-marathon --previewToont de volledige gepickte volgorde (id, titel, priority, rationale per positie) zonder iets te locken, te branchen of te builden. Handig om vooraf te zien of de dependency-graph je verwacht volgorde geeft. Draai je met
parallel.budget> 1, gebruik dan--preview --deep: die scout het eerste window (kost planner-tokens) en toont de échte wave-cut — welke issues straks tegelijk gebouwd worden. De gescoute plannen blijven staan onder.spexso/plans/en worden door de echte run hergebruikt (staleness-gecheckt), dus dat token-budget is niet weg. Cancel en herstart zonder--previewom écht te beginnen.Claude toont eerst een queue-samenvatting voor de start:
📋 Ready: 8 issues (no open blockers) 🔒 Blocked: 4 issues (waiting on is_blocked_by links) ⏭ Not queued: #16 (type::tracking), #17 (stage::opportunity)Issues in
stage::opportunityof mettype::trackingworden overgeslagen — ze staan niet klaar om te implementeren. Issues met open blockers wachten tot hun blocker gemerged is (stage::ship/operate) of gesloten — met"blockerResolvedAt": "closed"in.spexso/config.jsonwacht de marathon op het sluiten.Claude pakt issues op basis van dependency + priority + leeftijd:
- Eerst: alleen issues zonder blocker die nog open staat (gemerged of gesloten telt als opgelost).
- Dan: priority (critical → high → medium → low).
- Tiebreaker: oudste eerst (
created_atascending). Geen size-sort meer.
Per issue: een wegwerp
spexso-issue-runnersubagent voert plan → build (TDD) → review → MR-creatie (finish --train) uit in een geïsoleerde context; de runner merget zelf níet. De marathon-orchestrator krijgt een korte JSON-samenvatting terug — geen plan-output, geen MR-bodies — en merget daarna zelf via de merge train (finish --train-merge): rebase op de target branch, volledige testsuite op de gerebasede code, dán pas de merge. Is de suite groen, dan wordt de branch gepusht en wacht de train op de MR-pipeline: die draait ook wat de suite niet doet (een schone install,cds build --production,mbt build). Een rode suite of pipeline krijgt eerst herstelrondes: de builder krijgt alle rode CI-jobs met hun log en de jobs die CI erachter oversloeg, zoekt de oorzaak over alle installatiepaden heen, en repareert in de worktree (code, build-script, dependency-range of lockfile, nooit een test). Daarna draait de gate opnieuw. Dat gaat door zolang elke ronde vooruitgang boekt, tot maximaal 5 rondes. Pas als ze dan nog rood is: niet mergen,needs::attention. Volledige details staan in.spexso/marathon-log.jsonl.Tussen elke wave draait
npx spexso train guard. Staat er een issue opstage::reviewmet eenneeds::*-label en een open MR, dan stopt de marathon (stop reasonline_stopped):✗ line stopped: #8 (!21) must land before new work startsAnders zou het volgende issue starten op een main zonder dat werk, en stapelen de conflicten zich op. Land of sluit de MR (of draai
/spexso-finish --train-merge 8 --mr 21opnieuw) en start de marathon dan opnieuw.De marathon stopt automatisch als:
- De ready-set leeg is (en geen blocked issues meer) → backlog op
- De ready-set leeg is, maar er zijn nog blocked issues → deadlock-melding met wie op wie wacht
- Je
/spexso-stopofnpx spexso stopuitvoert --maxlimiet bereikt is- Een MR die de train niet kon landen nog openstaat (
line_stopped, zie stap 5) - 3 issues op rij falen → circuit breaker stopt de marathon (vangt systeemproblemen zoals CI-uitval). Een enkele failure zonder open MR stopt de run niet — die krijgt
needs::attentionen de marathon gaat door. - Een falende static-check (geconfigureerd in
staticChecks) telt als een gewone task-failure — 3-strike-rule binnen de issue. Na 3 strikes pauzeert spexso en escaleert naar jou.
Eindrapport toont: issues voltooid, MRs gemerged, overgeslagen issues, ongeresolvede conflicten, blocked-at-exit, duur.
WARNING
Gebruik --max 5 om het aantal issues te beperken. Zeker bij een eerste run. --max telt pogingen: elke verwerkte uitkomst (completed, conflict, skipped, failed) telt mee — zo blijft het budget van een nachtelijke run voorspelbaar.
Meerdere issues parallel (parallel.budget)
Standaard bouwt de marathon één issue per keer. Zet in .spexso/config.json:
{ "parallel": { "budget": 6 } }en de marathon wordt wave-gebaseerd. Het window vult zich in strikte picker-volgorde tot een size-score-budget (parallel.sizeScores — de default-scores en de hotspot-lijst staan op de config-pagina): met de defaults past budget 6 bijvoorbeeld drie M-issues — of één XL, die het budget alleen vult en daardoor automatisch solo bouwt. Het window sluit bij het eerste issue dat niet past (er wordt nooit voorbij gezocht naar een kleinere "passer" — dat zou grote issues achterstellen); dat issue leidt de volgende wave. Issues zonder size-label tellen als M; een eventueel --size-filter wordt door de picker toegepast vóór het window vult, dus het bepaalt mee de wave-samenstelling. Window-issues zijn onderling verschillend en vooraf gepickt — dát maakt de gelijktijdige /spexso-start-claims race-vrij. Daarna worden de window-issues door read-only planner-scouts gepland (parallel; het plan wordt hergebruikt door de runner, dus dit kost géén dubbel planwerk), waarna een deterministische wave-cut (npx spexso waves) alleen issues zonder overlappende file-footprints samen laat bouwen. Overlappende issues worden gesequenced naar een latere wave — nooit gedropt, nooit tegelijk gebouwd. De runners van één wave worden in één keer gespawnd en bouwen concurrent; de merge train blijft strikt serieel, dus de merge-volgorde blijft deterministisch en conflicten blijven structureel vermeden.
Twee extra hekken bewaken dat "structureel vermeden":
- Hotspots (
parallel.hotspots— default-lijst op de config-pagina) — bestanden waar élke aanraking botst. Twee issues die dezelfde hotspot raken, óók op verschillende paden (root- vs app-package.json), komen nooit samen in een wave. Leeg array = opt-out. - Fence-check in de merge train (
npx spexso fence) — de wave-cut werkte op voorspelde footprints; een builder kan buiten zijn plan zijn gelopen. Vóór elke merge vergelijkt de train de werkelijke diff met wat er in deze train al gemergd is (plus hotspots). Bij overlap wordt het issue één keer naar het einde van de train geschoven en daarna alsnog geprobeerd — de rebase-first testgate blijft het vangnet.
De scouts doen ook een self-assessment vóór ze plannen: testbare acceptatiecriteria aanwezig, scope eenduidig, betrokken bestanden/systemen aanwijsbaar? Een duidelijk onplanbaar issue wordt geweigerd (plannable: false + reden) in plaats van gepland: het krijgt needs::attention plus een note, verdwijnt voor de rest van de run uit de wachtrij en telt niet mee als failure óf poging — het werd nooit een attempt, dus de circuit breaker en --max blijven onaangeroerd. Grensgevallen worden gewoon gepland; weigeren is voor duidelijke gevallen, want een onterechte weigering kost menselijke aandacht. Bij parallel.budget: 1 is er geen scout en dus geen self-assessment — daar vangt de 3-strike-rail een slechte spec later op.
Let op: elk extra parallel issue is een volledige subagent-boom (planner/testers/builders) aan token- en API-verbruik — het budget balanceert die load, maar niet de duurtijd: een gemengde wave wacht bij de merge train op zijn traagste runner (een S-sibling staat even stil terwijl een L afrondt). Picker-volgorde wint bewust van duurtijd-homogene waves. De scores zijn ongekalibreerde schattingen — leg ze naast npx spexso observe report-data en stem ze per project af via parallel.sizeScores (defaults en aanbevolen budget: config-pagina). Faalt een complete wave in één keer, dan stopt de marathon direct (wave_failed — dat is systemisch, geen pech).
Dependency links komen uit /spexso-brainstorm
/spexso-marathon leest blocking links: native blocks-links waar GitLab ze heeft (Premium/Ultimate), en Blocked by #n-regels in de issue-beschrijving waar niet — op GitLab CE (zoals flexso.gitlab.host) zet npx spexso link --type blocks zo'n regel in het afhankelijke issue, plus een relates_to-link zodat je de relatie in de UI ziet. Ze worden geschreven door /spexso-brainstorm tijdens de dependency-check in het interview. Voor handmatig aangemaakte issues zonder links: voeg ze achteraf toe via GitLab's Linked items UI of:
npx spexso link <issue-iid> <blocker-iid> --type is_blocked_by(De adapter stuurt het vereiste target_project_id mee en post blocks vanaf de blocker-kant — een workaround voor GitLab's is_blocked_by 404-bug, gitlab#271168.)
Zonder dependency-links valt de marathon terug op priority + leeftijd. Dat werkt prima — je krijgt alleen geen ordering die werkafhankelijkheid respecteert.
Tips
- Gebruik
/spexso-stopofnpx spexso stopvoor een graceful stop na de huidige wave (bijparallel.budget: 1: na het huidige issue). - Werkt het best wanneer je brainstorm-sessies de blockers expliciet hebben gelinkt.
- Monitor via
npx spexso statusin een tweede terminal. Tijdens een wave toont dat N worktrees en evenveel open MRs die op de merge train wachten — normaal, geen hangende run. - Crashte de run mid-train? De getroffen issues staan op
stage::reviewmet een open MR en een bewaarde worktree — herstel per issue met/spexso-finish --train-merge {id} --mr {mr_id}, en ruim overgebleven worktrees op metnpx spexso worktrees reap. - Harde kostengrens voor nachtelijke runs:
--maxbegrenst pogingen, niet spend — combineer het met Claude Code's--max-budget-usden subagent-spawn-caps. - Issues met
needs::conflict-resolutionna de marathon: open GitLab, resolve manueel, dan re-run/spexso-finish. - Eindigt de samenvatting met
📥 … rulebook lesson(s) ready? Dan hebben de reviews lessen verzameld die minstens twee keer opdoken. Beslis erover met/spexso-rulebook, of in GitLab; zie Rulebook-lessen goedkeuren. - Als Jest test files vindt in
.spexso/worktrees/: run/spexso-setup— het voegt automatisch.spexso/toe aantestPathIgnorePatterns. - 's Ochtends details bekijken?
.spexso/marathon-log.jsonlbevat één JSON-regel per issue met taken, tests, review-bevindingen en diff-stats.cat .spexso/marathon-log.jsonl | jq .voor leesbare output. - Liever een cijfermatig overzicht dan JSONL?
npx spexso observe reportgenereert een deterministisch latency-rapport (wall clock, subagent hops, testruns) uit de gitignored run-logs in.spexso/observability/.
Marathon zonder laptop: auto-pick
Wil je dat kleine, goedgekeurde issues ook 's nachts of tijdens je vergaderingen worden opgepakt, zonder dat er een sessie openstaat? Dan draait een runner in GitLab CI de marathon voor je, met --autopick: alleen issues met het auto-pick-label, sequentieel, en elke MR gaat op GitLab auto-merge in plaats van direct gemerged te worden. Zie Een agent makkelijke issues laten oppakken.
Marathon vs --yolo op start
Twee verschillende dingen — verwarring is begrijpelijk maar belangrijk om uit te lichten:
/spexso-start 42 --yolo | /spexso-marathon | |
|---|---|---|
| Aantal issues | 1 (stopt erna) | meerdere (loop tot leeg/stop) |
| Volgorde | n.v.t. — jij koos #42 | dependency-graph + priority + leeftijd |
| Per-issue stijl | yolo (autonoom) | yolo (autonoom) |
| Wanneer gebruiken | je weet welk issue je wil doen | je wil dat Claude de queue voor je leegtrekt |