agentleFS
kenmulfordkenmulford/milestone-driver/skills/solve-milestone/SKILL.md

solve-milestone

Skill2 starsChanged 16 days agoMITView on GitHub

This skill should be used when the user invokes "/milestone-driver:solve-milestone <name>", or asks to "solve a milestone", "drive a milestone", or "work the milestone autonomously". Iterates every issue in a GitHub milestone in dependency order via /milestone-driver:solve-issue, integrating per the resolved integrationGranularity. Runs unattended: parks blocked or gapped issues and continues; only a systemic failure ends a run early. Builds mutually-independent issues within a Wave concurrently in git worktrees by default; a run-start barrier check drops to sequential only when a barrier is present.

  • Commits and pushes

The file

Show its rules and text

We split this skill into the rules it gives an agent

19 rules. About 0 are common, 3 are distinctive, and 16 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 16

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If ${CLAUDE_PLUGIN_ROOT} appears unexpanded, it is the parent of the skills/ directory that holds this file.

    line 7
  2. Distinctive:

    Execution mode: parallel by default: No flag, no opt-in. Resolved once at run start by the barrier cascade in the last Before-starting step …

    line 15
  3. Very specific:

    Auth preflight: Run gh auth status. Non-zero exit, or output containing "not logged in" / "authentication failed" → print Error: gh auth …

    line 23
  4. Very specific:

    Read the profile (docs/profile-schema.md).

    line 24
  5. Very specific:

    All downstream steps use the resolved {number, title}.

    line 59
  6. Very specific:

    Read versioning. versioning: false → skip this step.

    line 103
  7. Very specific:

    Create one TodoWrite item per issue (Codex: skills/runtime-codex.md).

    line 138
  8. Very specific:

    (a): every issue in dependencyGraph.edges["<n>"] (those this issue directly DEPENDS_ON) is already merged to integrationBranch, or, under …

    line 140
  9. Very specific:

    Before (b): where (a) holds and edges["<n>"] is non-empty, read ${CLAUDE_PLUGIN_ROOT}/skills/solve-milestone/blocked-label-clear.md and run …

    line 141
  10. Very specific:

    If buildable: read ${CLAUDE_PLUGIN_ROOT}/skills/solve-milestone/sequential-loop.md and run its per-issue build steps 1–4 (re-sync the build …

    line 145
  11. Very specific:

    Never escalate scope to protectedBranch: No PR, push, or merge targets protectedBranch.

    line 196
  12. Very specific:

    After this update every input the next wave needs is on disk (.milestone-config/.runtime/wave-state.json, …

    line 252
  13. Very specific:

    Read ${CLAUDE_PLUGIN_ROOT}/skills/citation-format.md - the one format every citation in those slots takes.

    line 283
  14. Distinctive:

    Use Template 3 as the layout.

    line 291
  15. Distinctive:

    The run ended because: no buildable issues remain - not because it is waiting on a human.

    line 299
  16. Very specific:

    Output ordering (clean-completion path only): do not emit Template 3 until ### Simplify pass and step 6 have both completed or skipped …

    line 302
  17. Very specific:

    Runs on the clean completion path only: When the systemic-halt path reaches the Final summary, skip this step and go straight to ## …

    line 306
  18. Very specific:

    After Template 3, emit a PushNotification:

    line 321
  19. Very specific:

    Skip cleanly: No usage file for this milestone (zero dispatches) → --finalize fails open on its own, one log line, no zero-value record.

    line 329

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

If ${CLAUDE_PLUGIN_ROOT} appears unexpanded, it is the parent of the skills/ directory that holds this file.

solve-milestone - autonomous driver

Order a milestone's issues, run /milestone-driver:solve-issue on each, integrate per the resolved integrationGranularity. Owns ordering, the loop, branch re-sync, parking, the final summary; solve-issue owns the per-issue pipeline. Coherence pass (coherenceReviewAgent, read-only, never gates). Runs per-issue in solve-issue section 6, before that issue's /code-review, under issue and wave granularity. Under wave granularity in parallel mode it also runs at the Phase-2 merge-tail re-verify point (skills/solve-milestone/parallel-waves.md § Parallel mode - Phase 2: serial verified merge tail), against the integrated wave. Under milestone granularity it runs once, never per issue, at skills/solve-milestone/milestone-end-gates.md § The ordered sequence step 3, against the whole branch. Absent → skip silently.

Blast radius. Merge only to integrationBranch, never protectedBranch. Release, closing the milestone object, and deploy are human-only. This skill closes the milestone's issues and authors the CHANGELOG; never the milestone.

Execution mode: parallel by default. No flag, no opt-in. Resolved once at run start by the barrier cascade in the last Before-starting step (Resolve execution mode), then held all run. A typed --parallel in $ARGUMENTS is stripped and ignored by step 3's --<token> strip.

Contents

Before starting · The procedure - 1. List the milestone's open issues · 2. Determine the order · 3. Determine the target version · Phase 0 - Triage · 4. Loop over issues in dependency-graph order · Permission pre-flight gate · Simplify pass · 5. Finish · Autonomy · Output spec - Template 1 - Run start / plan board · Template 2 - Status update at each wave boundary · Template 3 - Final results · Output style - Main-thread context · Final summary - 6. Author the CHANGELOG entry · Run-complete notification

Before starting

  1. Auth preflight. Run gh auth status. Non-zero exit, or output containing "not logged in" / "authentication failed" → print Error: gh auth status failed - authenticate with 'gh auth login' before running solve-milestone. and halt.
  2. Read the profile (docs/profile-schema.md).

    Decision pointBehavior
    Resolution order (READ only; no migration here)<repo>/.milestone-config/driver.json, else legacy root <repo>/milestone-driver.json. Both present → .milestone-config/driver.json wins; no move, no overwrite, no deletion of the leftover.
    Migration (git mv) of a legacy layoutNever on this orchestrator's own working tree. The first dispatched solve-issue performs it on its feature branch at step 3.5. An all-parked milestone defers it to the next building run; the transitional READ covers the gap.
    Neither file exists, or integrationBranch / protectedBranch / sourceGlobs missingInvoke milestone-driver:setup, then continue. Do not fail.
    implementerAgentDefaults to milestone-driver:implementer.
    Optional keys - unitTestCmd, e2eTestCmd, e2eEnv, domainSkills, nonNegotiablesTheir steps skip cleanly when absent.
    integrationGranularity (resolve here, once, hold all run)Absent → "milestone". Fail-open, never a hard error: an out-of-enum value degrades to "milestone", logging integrationGranularity "<value>" is not one of "issue", "wave", "milestone", degraded to "milestone". A valid value logs nothing; every later read uses it.

    2.0.5. Self-heal the scratch-ignore, always, before any .milestone-config/ scratch write. That directory also holds tracked config (driver.json, feeder.json): never add a bare * or / rule, which swallows both. The suffix-scoped *-notice does not. Ensure a committed .milestone-config/.gitignore carrying the block below: absent → mkdir -p .milestone-config and write it; present → do nothing. The first dispatched solve-issue commits it alongside the migration.

    <!-- KEEP THIS BLOCK IN SYNC with the committed .milestone-config/.gitignore in this repo and with solve-issue / scripts/triage-cache.{sh,ps1} / hooks/tests-green.{sh,ps1}, feeder setup / plan. -->
    # milestone-driver / milestone-feeder per-clone scratch - git-invisible by default.
    # Committed so per-run scratch stays out of `git status` with zero user setup.
    # Patterns are relative to this .milestone-config/ directory. Tracked config
    # (driver.json, feeder.json) is intentionally NOT listed, so it stays tracked.
    *-notice
    triage-cache.json
    tests-stamp
    .runtime/
    worktrees/

    2.0.6. Assemble common.md once; hold its path all run: mkdir -p <repo-root>/.milestone-config/.runtime/plans, then ${CLAUDE_PLUGIN_ROOT}/scripts/assemble-common.{sh,ps1} <repo-root> <repo-root>/.milestone-config/.runtime/plans/common.md [<anchor> ...], one <anchor> per standingDocs entry, prefixed with the resolved projectDocs. A nonzero exit logs its stderr and re-runs with no anchors (fail-open); a second one holds no path. The main thread never reads common.md.

    2.1. One-time notices. Immediately after the profile read: read ${CLAUDE_PLUGIN_ROOT}/skills/notices.md and, in file order (= print order), evaluate each section whose Skills field includes solve-milestone, applying its Trigger → Text → Marker → Legacy fallback mechanics exactly as stated there.

  3. Resolve the milestone argument. Strip flags from $ARGUMENTS: a flag is a token starting with --. Remove each --<token>, plus the following token when it does not start with -- and the flag is value-bearing (--parallel and --driven are boolean - strip the flag alone; any other --<token> followed by a non-flag token counts as value-bearing, strip both). Then:

    • Purely numeric (digits only): gh api repos/{owner}/{repo}/milestones/<milestone-number> --jq '{number, title}'. Found → record the canonical {number, title}, state "Resolved milestone #<milestone-number> → '<title>'". Not found → print the available-milestones table and stop.
    • Otherwise (title): gh api "repos/{owner}/{repo}/milestones?state=all&per_page=100" --paginate --jq '.[] | select(.title=="<name>") | {number, title}'. Found → record it, state "Resolved milestone '<title>'". Not found → stop the same way.
    • Numeric-title halt. Resolved title purely numeric → halt and prompt the human; do not proceed to Phase 0. Triage reads a bare number as single-issue mode, so a purely-numeric milestone title must be renamed to a non-numeric one before this skill can drive it unattended.
    • Available-milestones table (error path): gh api "repos/{owner}/{repo}/milestones?state=all&per_page=100" --paginate --jq '.[] | [.number, .title] | @tsv' as a Markdown table with columns # and Title.

    All downstream steps use the resolved {number, title}; do not re-read $ARGUMENTS. 3.5 integrations.trello present → read ${CLAUDE_PLUGIN_ROOT}/skills/solve-milestone/trello-sync.md and run its run-start card resolution (best-effort; a Trello failure never blocks the run). 3.6 Cherry-pick check for a milestone under a parent group. Fires only when --driven (step 5) is absent; when present, none of it runs - not the first-issue query, not the parent lookup. When absent:

    a. Find the milestone's first issue - lowest issue number, --state all so a fully-built milestone stays inspectable: gh issue list --milestone "<resolved-title>" --state all --json number --jq 'sort_by(.number) | .[0].number'. Nothing returned → fall through to step 4. b. Read that issue's parent, checking md-epic in the same call: gh api repos/{owner}/{repo}/issues/<first-issue>/parent. 404 → no parent. Any other successful response already includes .labels - check those for an exact md-epic match, no second call. A non-404 failure (auth, 5xx, network) is systemic, not "no parent" - surface it and halt per ## Autonomy. c. No parent, or a parent without md-epic → fall through to step 4, no prompt. d. A parent carrying md-epic → read ${CLAUDE_PLUGIN_ROOT}/skills/solve-milestone/md-epic-parent-check.md and run it: the three-option prompt (build just this milestone · hand off to /milestone-driver:solve-issue <parent-number> · pause), each option's branch, and the reactive-only out-of-order note. Reached on no other path.

  4. Confirm the working tree is clean and the local integrationBranch is current (git fetch, fast-forward). Record its tip (git rev-parse <integrationBranch>) as milestoneBaseCommit, held all run for ### Simplify pass.
  5. Resolve execution mode (the last Before-starting step). Resolve once, here; hold all run. Evaluate the cascade top-down; first match wins:

    The --driven token. An interpreted token, not a parsed CLI flag - recognized by string presence in the invocation text, never argument parsing. Only an internal caller dispatching this skill supplies it. It gates only row 4 (the DB-hazard interview): a driven run takes row 4′ instead of prompting. Every other Before-starting prompt is unaffected - step 3's numeric-title halt still halts and prompts on a driven run.

    #ConditionResolved modeDispatchSurfacing
    1profile parallel: falsesequentialbackground leaf dispatch ok if the gate passes, else synchronousquiet - standing opt-out
    2permission-allowlist gap (### Permission pre-flight gate)sequentialsynchronous🔴 gap table + recommend /fewer-permission-prompts
    3profile parallel: trueparallelbackgroundquiet - asserted safe
    4unitTestCmd set and parallel absent and interactiveinterview → user's choice, persisted to parallelper choice🔴 up-front prompt (below)
    4′same as row 4 but (MILESTONE_DRIVER_NONINTERACTIVE=1 OR --driven present)sequentialbackground leaf dispatch ok if the gate passes, else synchronousloud ⚠ note + how to set parallel: true; no persist
    5otherwiseparallelbackgroundquiet - default

    The permission pre-flight gate runs here, once (### Permission pre-flight gate): a gap → synchronous dispatch + sequential mode (row 2); no gap → background dispatch is available and the cascade continues. The in-loop references (sequential-loop.md step 2, parallel-waves.md Phase 1 step 3) read this decision; the gate never re-fires mid-loop.

    DB-hazard interview (row 4). Trigger: unitTestCmd set and parallel absent - the only trigger. Fire once, before Phase 0: read ${CLAUDE_PLUGIN_ROOT}/skills/solve-milestone/db-hazard-interview.md and run it - the prompt, the Yes/No branches writing parallel: true/false to .milestone-config/driver.json, the persistence rule, and the row-4′ path (MILESTONE_DRIVER_NONINTERACTIVE=1 OR --driven), which skips the prompt, falls to sequential with a loud note, and persists nothing.

    Nothing to decide: parallel absent and unitTestCmd absent → row 5 → parallel, quiet; no interview, no persisted value.

    Surface the resolved mode and its reason; it drives Template 1's mode line.

    5.1 Remediate handoff - the run-start question. Is /milestone-feeder:remediate resolvable in this session? Not resolvable → no question, one log line, silent degrade; file never read. Resolvable → read ${CLAUDE_PLUGIN_ROOT}/skills/remediate-handoff.md and run ## The run-start question verbatim - asked once, held all run, never re-asked per issue. MILESTONE_DRIVER_NONINTERACTIVE=1 → do not ask: take that file's non-interactive default with a loud ⚠ note (--driven doesn't gate this). Never copy its procedure here.

The procedure

1. List the milestone's open issues

gh issue list --milestone "<resolved-title>" --state open, using the title resolved in Before-starting step 3.

2. Determine the order

The milestone description is the ordering source of truth. Read it (gh api "repos/{owner}/{repo}/milestones/<resolved-number>" --jq '.description', else gh api "repos/{owner}/{repo}/milestones?state=all" --jq '.[] | select(.title=="<resolved-title>") | .description') and follow the Wave / dependency sequence it records. No explicit order → fall back to ascending issue number and state that in the run output.

3. Determine the target version

Read versioning. versioning: false → skip this step; record "version-free run - no version determined or bumped" and proceed to Phase 0.

Otherwise (true or absent) → read ${CLAUDE_PLUGIN_ROOT}/skills/solve-milestone/version-target.md and run it: the deterministic extractor ${CLAUDE_PLUGIN_ROOT}/scripts/extract-version.{sh,ps1} (never parse by judgment), its branch table, fail-open behavior, and non-interactive degradation. Hold that target for the loop.

Phase 0 - Triage

Invoke triage across the milestone before the build loop:

/milestone-driver:triage <resolved-title>

(Pass the resolved title - triage's bare-number path means single-issue mode.)

  1. Present triage output. Surface the all-clear or gap table; triage's output carries the Wave-ordered dependency graph either way.
  2. Apply triage-recommended park labels. Triage posts the 🔴 Triage comment but applies no labels; that is this skill's job. For every issue where issueStates[n].blockers == true, apply its issueStates[n].label ("needs design" or "needs decision") with the apply-time label helper from ${CLAUDE_PLUGIN_ROOT}/skills/setup/SKILL.md Phase 4, using that taxonomy table's hex color and description. Where issueStates[n].clearLabel == true instead, remove the one park label the issue live-carries and add none (skills/triage/blocker-resolver-dispatch.md (Unparking)):

    gh label create "<name>" --color <hex> --description "<desc>" --force
    gh issue edit <n> --add-label "<name>"
    gh issue edit <n> --remove-label "<name>"     # clearLabel == true

    Under a held Auto answer, every issue parked here enters the ## The Auto loop in ${CLAUDE_PLUGIN_ROOT}/skills/remediate-handoff.md before step 3 - same gated read-direct, on this main line, cap 1 per issue per run; a NEEDS_HUMAN return or a still-dirty re-triage parks for good (skills/remediate-handoff.md (Park for good)).

2.5. integrations.trello configured → run trello-sync.md ## Phase 0 hooks (best-effort).

  1. Seed the build queue. Carry triage's full dependencyGraph and issueStates into the loop; the loop drives from the validated graph, not the raw declared order.

4. Loop over issues in dependency-graph order

Mode branch point. In parallel mode: read ${CLAUDE_PLUGIN_ROOT}/skills/solve-milestone/parallel-waves.md and run its Wave loop - parallel-waves.md § Parallelizable-set selection (parallel mode), then § Parallel mode - Phase 1: concurrent stage dispatch, § Parallel mode - Phase 2: serial verified merge tail, § Integration granularity (issue vs wave) - instead of the sequential build steps below. Never silently degrade to sequential. In sequential mode it is never read.

  • Granularity branch point (orthogonal to the mode branch). Under integrationGranularity: "milestone", read ${CLAUDE_PLUGIN_ROOT}/skills/solve-milestone/milestone-granularity.md: § Branch model and § Folding an issue into the milestone branch own condition (a) and every re-sync below; § Creating the milestone branch cuts milestone-<number>-<slug> from integrationBranch here, before any issue branch. Every issue branch this run is cut from it; nothing reaches origin until milestone end. Under "issue" never read; under "wave" only where cited.

Create one TodoWrite item per issue (Codex: skills/runtime-codex.md). Process issues Wave by Wave; within a Wave, mutually independent issues may be taken in any order. For each issue, determine whether it is buildable this pass - iff all three hold:

  • (a) every issue in dependencyGraph.edges["<n>"] (those this issue directly DEPENDS_ON) is already merged to integrationBranch, or, under integrationGranularity: "milestone", carries its Issue: #<n> trailer on the milestone branch (milestone-granularity.md § Resume and buildability from the trailer); and
    • Before (b): where (a) holds and edges["<n>"] is non-empty, read ${CLAUDE_PLUGIN_ROOT}/skills/solve-milestone/blocked-label-clear.md and run it.
  • (b) the issue currently carries no blocker label - check live: gh issue view <n> --json labels --jq '[.labels[].name]', confirming none of needs design, needs decision, blocked is present. This live check is the authoritative park-state. A labeled issue must not be rebuilt until a human (or Phase 0's Auto remediate loop) clears the label; and
  • (c) issueStates[n].blockers == false.

If buildable: read ${CLAUDE_PLUGIN_ROOT}/skills/solve-milestone/sequential-loop.md and run its per-issue build steps 1–4 (re-sync the build target → run solve-issue <n> in-thread with the held values restated → park-and-continue on STOP/PAUSE → on-success terminal states, trello tick, milestone-granularity fold). In parallel mode it is never read.

If not buildable (triage-parked, live-label park, or dependency not yet merged): read ${CLAUDE_PLUGIN_ROOT}/skills/solve-milestone/not-buildable.md and run it: the park-label back-fill for a triage/prior-run park, and the blocked label, 🔴 Blocked comment, and transitive holds for a dependency hold. Both modes read it when an issue is not buildable.

The loop never waits on a human. Every issue ends merged or parked (label, open branch if applicable, comment), UI included. Park comments: triage parks carry Phase 0's 🔴 Triage comment; build-time parks, the reason posted at sequential-loop.md step 3c; dependency holds, 🔴 Blocked (not-buildable.md).

In versioned mode the first issue's commit sets plugin.json to the target version; every later PR is idempotent.

Permission pre-flight gate

Runs once per run, at run-start mode resolution (row 2 above), before any dispatch - whenever background dispatch is about to be used. The mode cascade and the loop read its result.

Allowlist source. Union permissions.allow from these three settings layers, which the autocompact notice (${CLAUDE_PLUGIN_ROOT}/skills/notices.md) also reads autoCompactWindow from; absent or unreadable layers are skipped in the union, not counted as gaps:

PriorityFile
1~/.claude/settings.json (user global)
2.claude/settings.json (project)
3.claude/settings.local.json (project local)
<!-- KEEP THIS BLOCK IN SYNC with skills/solve-issue/permission-preflight.md § Tool surface and response, its second copy. -->

Pipeline tool surface. The union must cover at minimum:

Tool categoryRequired grants
Read-only gh opsgh pr list, gh issue view, gh issue list
Gitgit commit, git push
PR / issue writesgh pr create, gh pr merge, gh pr edit, gh pr comment
Issue managementgh issue edit, gh issue comment, gh issue close
Label managementgh label create
Planner leafWrite to .milestone-config/.runtime/plans/issue-<n>.md, git rev-parse, Skill
Profile-defined commandsEach command in unitTestCmd, preflightCmd, e2eTestCmd (skip if absent)

Gap detection and response. No gaps → proceed with background dispatch. Gap detected (missing surface coverage, or no readable layer) → do not dispatch in the background: (1) surface a 🔴 gap table naming each missing grant and which layer(s) could supply it; (2) fall back to synchronous dispatch for this run; (3) recommend the consumer run /fewer-permission-prompts (see docs/consumer-setup.md). That result holds for the run; do not re-read settings per issue.

Auto-deny handling. A background leaf reporting an auto-deny it could not work around is a park: post a blocked comment naming the denied tool, apply blocked (+ in progress if the branch has commits), preserve the branch, continue.

Simplify pass

Runs once, after step 4's loop exhausts, on the clean-completion path only; a systemic halt skips it. Read ${CLAUDE_PLUGIN_ROOT}/skills/solve-milestone/simplify-pass.md and run it.

5. Finish

The run ends when no buildable issues remain. integrations.trello present → apply ## Finish hooks from ${CLAUDE_PLUGIN_ROOT}/skills/solve-milestone/trello-sync.md (best-effort; skipped updates surface in the final summary).

Autonomy

  • Unattended between systemic failures. Operate autonomously within an explicit /milestone-driver:solve-milestone run. A solve-issue STOP or PAUSE parks that issue (label + open branch + comment) and the loop continues.
  • Systemic failures that halt the run (examples): gh auth failure, a broken or inaccessible integrationBranch, missing required tooling (gh, git), and any reference file this skill read-directs being missing or unreadable once its condition has fired - parallel-waves.md, milestone-granularity.md, blocked-label-clear.md, sequential-loop.md, not-buildable.md, md-epic-parent-check.md, version-target.md, db-hazard-interview.md, changelog-authoring.md, milestone-end-gates.md. Best-effort integrations (trello-sync.md, simplify-pass.md, coherenceReviewAgent) degrade silently instead. These are conditions where no further issue can make progress: surface the failure, leave the tree clean, all in-flight issues parked, present the summary, and stop - ## Run-complete notification emits 🚨 Run halted - <reason>.
  • Architecture is locked per issue at its plan-approval time. A plan proven wrong is a park (STOP → park + continue), not a silent redesign.
  • Never escalate scope to protectedBranch. No PR, push, or merge targets protectedBranch.

Output spec

<!-- KEEP THIS ICON LEGEND BYTE-IDENTICAL across solve-issue and solve-milestone. -->

Icon legend: ✅ merged · 🔨 building · ⏭️ queued · ⏸️ parked · 👁️ UI surface / visual evidence · ⚖️ judgment call · 🔴 Your move

Template 1 - Run start / plan board

Show after Phase 0 triage completes.

🚀 Milestone v[version] - [N] issues · [W] waves · [resolved mode: parallel | sequential (<reason>)] · ~[T]–[T2] min
   develop ← integration PRs · profile: <H> heavy / <L> light

| Wave | Issue | Title                    | Risk  | UI | Status      |
|------|-------|--------------------------|-------|----|-------------|
| 1    | #201  | Background wave dispatch | heavy | -  | 🔨 building |
| 2    | #203  | Status board templates   | light | 👁️  | ⏭️ queued   |

⏸️ Parked at triage: #202 - needs design (contradictory grouping spec)
▶ Wave 1 dispatched - the floor is yours.

Mode cell: parallel, or sequential (<reason>) where <reason> ∈ { profile parallel:false, permission gap - see 🔴, test-isolation not confirmed }.

Template 2 - Status update at each wave boundary

Show after each Wave completes.

<!-- Structural mirror of solve-issue Template 2; keep column schema (Issue/Result/Gates/PR/Note) in sync. -->
🌊 Wave [N] done · [T] min · milestone [done]/[total] ✅

| Issue | Result    | Gates            | PR   | Note                    |
|-------|-----------|------------------|------|-------------------------|
| #201  | ✅ merged | 🧪✓ 🔍✓(2 fixed) | #301        | ⚖️ quarantined flaky E2E |
| #202  | ⏸️ parked | -                | [#pr | -]   | needs decision: new dep  |

▶ Next: Wave 2 (#203 👁️, #204) - redirect or reprioritize before it lands.

PR cell: the PR number if the issue has one, else -. Note cell: an issue sent through the Auto loop shows remediated, cleared (clean re-triage, label cleared), remediated, still parked (cap spent or still dirty), or NEEDS_HUMAN, parked (skills/remediate-handoff.md (Park for good)). No Auto loop → cell unchanged. A slow first build adds its note per skills/solve-issue/SKILL.md (Slow first build:).

Milestone end row (integrationGranularity: "milestone" only). Once skills/solve-milestone/milestone-end-gates.md's sequence finishes, print one Template-2-shaped table before Template 3:

🏁 Milestone end · [T] min

| Issue         | Result  | Gates       | PR | Note              |
|---------------|---------|-------------|----|--------------------|
| milestone end | ✅ done | 🧪✓ 🔍✓ 🌐✓ | -  | 2 fix dispatches  |

Note cell: <F> fix dispatches (0-3); a cap-spent revert appends ; reverted #<n>. No commits on the milestone branch → no row; any other resolved integrationGranularity never prints it. ## The run-scoped handler path prints ⏸️ needs review instead of ✅ done, the Note cell naming the reason (an open finding, or an unattributed red gate).

Gates legend: 🧪 = unit suite · 🔍 = code review · 🌐 = E2E. Milestone end row: 🧪✓ 🔍✓, plus 🌐✓ only with a ui-labeled issue and e2eTestCmd defined; coherence review and preflight get no symbol, as in the per-issue Gates cell.

After this update every input the next wave needs is on disk (.milestone-config/.runtime/wave-state.json, .milestone-config/triage-cache.json, the milestone branch), so compaction here loses nothing; session-resume re-injects the checkpoint.

Template 3 - Final results

The layout for ## Final summary below; fill the metadata lines from that section's requirements.

🏁 v[version] complete · [T] min · ✅ [M] merged · ⏸️ [P] parked

| Issue | Outcome   | PR          | Follow-up                                  |
|-------|-----------|-------------|--------------------------------------------|
| #201  | ✅ merged | #301        | -                                          |
| #203  | ✅ merged | #303        | 👁️ visual evidence attached                |
| #202  | ⏸️ parked | [#pr | -]   | clear `needs decision` (new dep)           |

Judgment-call PRs: [list or "none"]
PRs missing Code Review section: [list or "none"]
Auto-resolved conflicts: [list or "none"]
Per-wave sizes: Wave 1 · [N] issues · [T] min | Wave 2 · …

🔴 Your move:
1. Sanity-check the ⚖️ judgment-call PRs and any PR listed as missing a Code Review section
2. Clear park labels → re-run
3. All merged → merge `integrationBranch` → `protectedBranch` with `--merge` (not squash), merging the release PR *before* tagging, then **back-merge `protectedBranch` → `integrationBranch`** (history-only, conflict-free) so `integrationBranch` stays tag-current and topologically even, close the milestone (`gh api -X PATCH repos/{owner}/{repo}/milestones/<number> -f state=closed`), deploy - full ordered runbook in `docs/consumer-setup.md` § "Releasing to your protected branch"

PR cell: the PR number if the issue has one, else -. Follow-up cell: the same auto-remediate outcome Template 2's Note cell records.

Output style

Read ${CLAUDE_PLUGIN_ROOT}/skills/output-style.md - this plugin's output contract. ## Terminal output governs what this skill prints (including the ## Output spec template rule); ## GitHub-facing prose, ## When prose is the correct form, and ## Evidence slots govern every issue comment, PR body, and CHANGELOG entry it writes. Plain English. Write every response, document, and GitHub issue, milestone, comment, and PR body in plain, concise English. Never include hypothesis, conjecture, or defensive text.

Read ${CLAUDE_PLUGIN_ROOT}/skills/citation-format.md - the one format every citation in those slots takes.

Main-thread context

The orchestrator never Reads a persisted tool-result file (~/.claude/projects/<session>/tool-results/*.txt) whole, never cats a .project/ doc, the consumer brief, or a plugin reference file - it takes a section with ${CLAUDE_PLUGIN_ROOT}/scripts/read-doc-section.{sh,ps1} or sed -n. A truncated tool result is re-run with a narrower command, never re-read. Everything an agent needs travels as a path in its brief, never pasted inline.

Final summary

Use Template 3 as the layout. On completion or systemic-failure halt, report:

  • Issues built and merged to integrationBranch, with PR links.
  • Issues parked - per issue: number, title, park label, blocker reason, the Auto-loop outcome if attempted, and the open feature branch if applicable. Take the reason from tracked context (triage gap, STOP/PAUSE reason, or unmerged upstream). Not in active context → read gh issue view <n> --json comments and use the most recent matching comment: opening 🔴 Triage (triage-park), 🔴 Blocked (dependency-hold), or 🔴 Parked (build-park). gh returns comments oldest-first, so take the LAST match. No anchored match → report "park reason not recorded (pre-1.7.0 park format)". Never invent a reason.
  • PRs carrying a judgment call label, flagged for post-run review.
  • PRs missing a ## Code Review section, flagged the same way, for review before the integrationBranch → protectedBranch merge.
  • Auto-resolved-conflict issues (parallel mode) - those whose merge conflict the serial verified merge tail auto-resolved, for a human to sanity-check.
  • Per-Wave parallel-set sizes (parallel mode).
  • The run ended because no buildable issues remain - not because it is waiting on a human.
  • The next human step: review parked issues; clear park labels once their blockers are resolved and re-run for the rest; all work merged → run Template 3's 🔴 Your move: item 3 verbatim, then deploy manually.

Output ordering (clean-completion path only): do not emit Template 3 until ### Simplify pass and step 6 have both completed or skipped cleanly (skills/solve-milestone/changelog-authoring.md § 6.9 Surface in the final summary "Your move" section). On the systemic-halt path both are skipped - emit Template 3 immediately.

6. Author the CHANGELOG entry

Runs on the clean completion path only. When the systemic-halt path reaches the Final summary, skip this step and go straight to ## Run-complete notification.

Guard - skip this step entirely if either holds:

  • The parked count for this run is greater than zero, OR
  • The run ended via a systemic halt

The parked count comes from this run's in-context tracking - every issue that did not reach "merged": parked at build time, skipped on triage blockers, or excluded by a live blocker label (e.g. blocked from a prior run). It is Template 3's ⏸️ P count. Do not re-derive via a live gh issue list query: it may find labels unrelated to this run.

Either condition holding → post "Skipping CHANGELOG authoring - run did not fully complete (N parked)." and go straight to ## Run-complete notification - except under integrationGranularity: "milestone", where it skips only changelog-authoring.md steps 6.1-6.5: milestone-granularity.md § Milestone end still runs gates, push, and PR for whatever merged (skills/solve-milestone/milestone-granularity.md (Steps 2 to 6 run for whatever did merge.)).

Guard passes → read ${CLAUDE_PLUGIN_ROOT}/skills/solve-milestone/changelog-authoring.md and run its steps 6.1–6.9 (idempotency check → PR summaries → categorize → theme → author the entry → branch name → doc-only PR → CI result → surface in the final summary).

Run-complete notification

After Template 3, emit a PushNotification:

  • Clean completion: 🏁 <milestone-title> · ✅ M merged · ⏸️ P parked, the counts from Template 3.
  • Systemic halt: 🚨 Run halted - <reason>, where <reason> is the systemic-failure description, e.g. "gh auth failure".

Run-end cost record (additive, never-gating), survives context compaction. No in-context aggregation: each dispatch appends its usage to disk as it returns; the run-end record reads back from that file alone, the last step here on both the clean-completion and systemic-halt paths.

  1. Append, per dispatch, as it returns. Every Agent-dispatch this run - Phase 0 triage's own dispatches and each per-issue / per-wave Agent(run_in_background: ...) dispatch - pipes {"agent":"<dispatch label>","tier":"<opus|sonnet>","totalTokens":<subagent_tokens>,"durationMs":<duration_ms>} to ${CLAUDE_PLUGIN_ROOT}/scripts/write-cost-record.{sh,ps1} --append <milestone id> as its last step, milestone-wide: one usage file spans every Wave, so Phase 1 needs none of its own (skills/solve-milestone/parallel-waves.md (Hand the green set to Phase 2)). An implementer or planner return carrying output_file: merges its measurement per skills/solve-issue/SKILL.md (merges the object); that merge never gates (.project/design-philosophy.md#Error & failure philosophy).
  2. Finalize. ${CLAUDE_PLUGIN_ROOT}/scripts/write-cost-record.{sh,ps1} --finalize <milestone id> sums totalTokens per tier into inputTokens (outputTokens/cacheReadTokens/cacheWriteTokens at the 0 sentinel, provenanceNote: "unsplit-total-as-input" marking it a lower-bound), sums durationMs into wallClockSeconds, and writes the record to .milestone-config/.runtime/cost-records/ with one more field, agents: the raw per-dispatch entries.
  3. Skip cleanly. No usage file for this milestone (zero dispatches) → --finalize fails open on its own, one log line, no zero-value record. Writer script absent → silent no-op, one log line. Never fails the run.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.