Issue cycle
Runs one full pass of the steady-state workflow: post-merge cleanup → plan (and revise, propose answers, policy auto-approve) → implement approved issues → report what now waits on the human. Use when the user asks to "run the cycle", "process everything pending", "run the harness", "do a full pass", or wants unattended/scheduled operation (pair with /loop or a scheduled routine). It composes the issue-planner and issue-implementer skills and adds no authority beyond what the repo's CLAUDE.md delegates.From its SKILL.md
npx -y skills add msummer/trail-blazer-flow --skill issue-cycleAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
21.6 KB, as published. Nobody here has run it
Issue Cycle
One invocation = one bounded pass over everything currently pending — so the steady state
("plan" → approve → "implement" → merge → cleanup) is a single command, and a /loop or
scheduled routine has one thing to call. It is a conductor: the planning and implementation
logic lives entirely in the issue-planner and issue-implementer skills, invoked unchanged —
do not re-implement their procedures here. Unattended, a cycle can: turn new issues into plans,
revise on feedback, propose grounded answers, auto-approve plans only under CLAUDE.md's
auto-approval policy (hard floor always applies), implement through the verifier gate, open PRs,
merge PRs only under a merge autonomy policy (own hard floor — see the merge pass), file
coverage-increasing issues only under a test-suite ratchet policy (see the ratchet pass), and
repair queue hygiene. No auto-approval policy → ends with plans awaiting review; no merge
autonomy policy (or gh pr merge still denied) → ends with PRs awaiting merge — both the
human's.
Dispatch ledger
A cycle tracks every issue it touches in a per-issue dispatch ledger, kept in the run's
context only — no state file, no new label. Each row: issue number, planned / implemented
/ verified / merged (outcome or "—" if not yet reached), retry count (ladder + resume,
summed per stage), wall-clock duration (unknown if no clock), final state, escalations.
- Seeding: at step 0, seed one row per issue from the pre-flight discovery output (planning
- implementation lists), all four stage columns empty — the discovery bucket becomes the row's
seedrecord when step 5 serializes it. Updating: each pass then fills in its own stage column per issue touched, from the outcome each dispatch reports via the status line contract (issue-implementer's "Resilient dispatch"); the ratchet pass fills in nothing (step 4).
- implementation lists), all four stage columns empty — the discovery bucket becomes the row's
- Serialized form: step 5 hands it to
reconcile-ledger.shas one record per line —<issue> <stage> <outcome> [retries] [deploy=<slug>](format/vocabulary owned by that script — see its header /--help; thedeployfield is merge-only, from guard (e)). A stage never reached is absent, never a-row. - Pre-advance check: before advancing an issue, check the ledger — a stage with no entry is
launched, not assumed; never infer "must have been fine" from an empty cell. Closing
reconciliation (step 5):
reconcile-ledger.shthen compares the serialized ledger against the live queues, one line per discrepancy.
Procedure
0. Pre-flight
Run the issue-implementer skill's pre-flight (step 0) up front: gh auth, dirty-tree /
crash-recovery rules (incl. the stale-worktree sweep, before the hygiene script),
cleanup-after-merge.sh --fix, and the baseline refresh — before planning too, since a red
default branch STOPs the cycle with a report (planning wastes a round; implementing is forbidden
anyway). Missing .claude/BASELINE.md → warn once (harness-setup) and continue; it degrades
comparisons, doesn't block the cycle.
Seed the dispatch ledger. Run find-planning-work.sh and find-implementation-work.sh
(idempotent, read-only) to learn the full universe of issues this run might touch, and add one
ledger row per issue found, noting its discovery bucket. Steps 1 and 2 re-run their own
discovery as part of their normal procedure (expected, not wasted work), but this up-front seed
is what lets the pre-advance checks and step 5's reconciliation catch an untouched stage.
1. Planning pass
Invoke the issue-planner skill and let it run its full procedure (discovery, initial plans,
revisions, stale/overlap handling, proposed answers + same-run revision, policy auto-approval,
summary), skipping its step 0 (pre-flight already covered it). As it reports each outcome, fill
in the planned column (incl. retry counts from each status line); pre-advance check applies
— a blank cell after this pass means the stage was skipped, escalate it, don't carry it forward.
2. Implementation pass
Invoke the issue-implementer skill for everything now plan-approved — including plans
auto-approved in step 1 (the PR gate still applies) — skipping its step 0. Sequential by
default; its worktree-parallel mode applies under its own rules and changes nothing here (one
worktree is one issue, so the ledger row, status lines, and step 5's reconciliation are the
same). Fill in the implemented and verified columns from its summary table; pre-advance
check applies as in step 1. If step 1 produced nothing to implement and nothing was already
approved, skip this pass.
3. Merge pass (only under a repo merge autonomy policy)
Skip this pass entirely — silently — when there is no "Merge autonomy
policy" section at all; that silence is the only silent case, everything past activation is
loud. Activation requires both: (1) CLAUDE.md has a section titled exactly "Merge
autonomy policy" — no section means merging stays fully manual, exactly as before, that trust
decision belongs in the repo's file, not this plugin (skip silently); (2) gh pr merge actually
runs, i.e. the human has removed it from the deny list in .claude/settings.json — if the
section exists but the command is denied or prompts, that is the loud case (guard (c)
below), not a silent skip: the half-finished double opt-in gets escalated, not passed over
quietly.
When active, evaluate each open harness PR (and Dependabot PRs, if the policy covers them) against the repo's policy. The policy defines which PRs qualify; this hard floor applies on top and is not configurable:
- Only PRs from the standard flow — harness branches whose plan was approved (by the human
or the auto-approval policy) and whose PR body carries the verifier's own closing status
line for that issue with
outcome=pass— or Dependabot PRs of the update classes the policy names. Never a human's PR. A prose "verifier verdict: pass" without that line is not green.- Verdict provenance, checked mechanically, before guard (a): with
<n>the issue number taken from the PR'sclaude/<n>-…head branch (never from prose in the body):gh pr view <pr> --json body --jq '(.body // "") | contains("<!-- harness-status: stage=verifier issue=<n> outcome=pass ")' | tr -d '\r'must printtrue, and the same command withoutcome=failin place ofoutcome=passmust printfalse. Keep the trailing space afteroutcome=passin the needle so extra trailingkey=valuefields on the line stay tolerated. - Archived verdict, checked mechanically, between the check above and the Ledger
cross-check below, same
<n>-from-the-head-branch scoping (harness PRs only; Dependabot PRs skip this bullet): the archive is keyed to the PR's head branch, so a multi-PR issue's earlier slice matches its own verdict rather than the newest on the issue. Read the key first —gh pr view <pr> --json headRefName --jq .headRefName | tr -d '\r'(also where<n>comes from) — then paste that branch name literally into the placeholder below, in this one-line, substitution-free command:gh issue view <n> --json comments --jq '[.comments[] | select((.body | contains("<!-- verifier-verdict -->")) and (.body | contains("<!-- verifier-verdict-branch: <paste the head branch here> -->")))] | sort_by(.createdAt) | last | ((.url // "none"), ((.body // "") | split("\n") | map(select(startswith("<!-- harness-status:"))) | last // "none"))' | tr -d '\r'— prints the comment URL, then the archived closing status line. A second line readingnone, or one that does not begin<!-- harness-status: stage=verifier issue=<n> outcome=pass, is not eligible ("no archived verifier verdict for head branch <branch>"), one-line reason in the report. Otherwise paste that second line literally as the needle of a second, equally substitution-free command:gh pr view <pr> --json body --jq '(.body // "") | contains("<paste the printed line here>")' | tr -d '\r'— anything buttrueis not eligible ("the PR body's verifier line does not match the verdict archived for head branch <branch>"), one-line reason in the report. Cite the printed comment URL as merge evidence. - Ledger cross-check, against the pre-advance check above: the issue's
verifierledger row must readpass; a row readingfail/incomplete/diedagainst a pass line in the PR body is a contradiction — don't merge, escalate with both pieces of evidence.
- Verdict provenance, checked mechanically, before guard (a): with
- CI green on the head commit, verified fresh (
gh pr checks), not remembered; "no checks configured" is not green unless the policy section explicitly opts a no-CI repo in. - Never the governance surface: any PR touching
CLAUDE.md,.claude/, the repo's policy/ADR documents, or CI configuration waits for the human regardless of what the policy says — the autonomy boundary only moves with a human in the loop. - Nothing flagged: if the plan, the verifier's notes, or the implementer's report flags a decision needing human sign-off, the PR waits. Any ambiguity about whether the policy covers a PR resolves to "no".
- One at a time, re-verified between: merge, then run
cleanup-after-merge.sh --fixand the baseline refresh before the next merge — if mergedmaingoes red, STOP the pass and report (two green PRs can still compose badly; sequential re-verification attributes the breakage). Match the repo's existing merge method (merge/squash/rebase) from recent history. - Every autonomous merge is audited: it appears in the cycle report with its evidence — PR link, verifier verdict, the archived verdict comment's URL, CI run — never merged silently.
Pre-first-merge deploy recheck. Active only when guard (e)'s "Post-merge verification"
sub-block is declared — no sub-block, this step does not exist, silently, exactly like guard (e)
itself. The dispatch ledger lives in this run's context only, so a deploy=failed recorded by an
earlier cycle is already forgotten by the next one, which is exactly the gap this recheck closes.
When: once per run, immediately before the first merge attempt of the pass — before guard (b)
for the first PR that reaches it, never again for later merges (guard (e) covers those); if no PR
ever reaches guard (b), this never runs. How: run guard (e)'s declared commands exactly as
guard (e) defines them — same read-only contract, same bounded wait, same
verified|pending|failed outcome mapping, not restated here. Outcome: verified ⇒ proceed to
guard (a) as normal; failed or pending ⇒ STOP the merge pass for the rest of the run before
any merge happens, reported the same way a red baseline is, quoting the last ~10 lines of
command output verbatim, and named in the cycle report. Bookkeeping: no status line, no ledger
row, no deploy= field of its own; PRs that had qualified for this pass but were not merged
because of the stop are recorded outcome=merge-blocked, the recheck's result as their one-line
reason — guard (c)'s "print the exact gh pr merge command" hand-off does not apply here,
since production is unverified and whether to merge onto it is the human's call.
Merge guards, applied per PR, in order:
(a) Base assertion. Before attempting the merge, confirm the PR targets the repo's default
branch (gh pr view <n> --json baseRefName --jq .baseRefName | tr -d '\r', resolved once via
gh repo view --json defaultBranchRef — the same lookup the issue-implementer pre-flight
already does, not a hardcoded main). A mismatch aborts that merge and escalates — the
harness never merges a PR whose base is a feature branch, even if every other guard passes.
(b) Attempt the merge, matching the repo's existing merge method as today.
(c) Permission-denied escalates loudly. If the policy section exists but gh pr merge comes
back permission-denied (the human hasn't lifted the deny on this machine), the stage fails
loudly: report the issue as verified, merge blocked (never done), and print the
exact command for the human in the run summary, including the PR number and the repo's
merge method, e.g. gh pr merge <n> --squash (adjust the flag to match). Never route around
the denial — no API calls, no web merges, no asking the user mid-cycle.
(d) Merge-landed confirmation. After the merge command returns, confirm it actually landed
before reporting it merged (gh pr view <n> --json state --jq .state | tr -d '\r' must
return MERGED). If it doesn't, the state is merge attempted, unconfirmed and the
merge pass stops for that PR — don't proceed to the next merge assuming success.
(e) Post-merge verification (optional, CLAUDE.md-declared). Only when the "Merge autonomy
policy" section carries a sub-heading titled exactly "Post-merge verification" (any #
depth) followed by a fenced block: detection mirrors the policy sections above — exact
heading match, then the fenced block under it. No sub-block means this step does not exist —
silent, like the merge pass's own activation check: the pass behaves exactly as it does
today, no deploy= field, no report line. When present, every non-blank fenced line is one
command, read-only by contract, run in order from the repo root, exactly as written — never
a command the fence does not contain, never synthesized, adapted, or extended. An optional
Wait: <N> minutes line in the sub-block before the fence sets the poll budget (absent →
10; clamped to a non-configurable 30-minute ceiling — beyond it the pass records
deploy=pending and hands to the human).
Runs after guard (d) confirms `MERGED` **and** after this PR's `cleanup-after-merge.sh --fix`
+ baseline refresh, before the next PR is merged.
**Read-only contract:** these commands are reads; the harness never approves a deployment,
promotes a build, or re-runs a deploy — that authority stays with the human, always. A
declared command with no matching allow entry, or one containing command substitution (no
allow rule can approve those — README "Safety model"), records `deploy=pending` and names
the exact problem in the report; never route around a denial.
**Bounded wait, `sleep` only:** run the declared commands; if the result is not yet
conclusive, `sleep 60` and re-run, at most N times (N = the declared minutes, clamped at
30). If `sleep` is denied, re-run once immediately and record `deploy=pending` with "backoff
unavailable — grant `Bash(sleep:*)`".
**Outcome mapping:** all declared commands exit 0 within the budget → `deploy=verified`;
budget spent with no conclusive result, or a permission/`sleep` problem → `deploy=pending`;
any command exits non-zero → `deploy=failed`.
**Escalation:** `pending`/`failed` are loud in step 5's "waits on the human" half, quoting
the last ~10 lines of the command output verbatim; `deploy=failed` additionally **STOPs the
merge pass for the rest of the run** (no further merges), reported the same way a red
baseline is.
Fill in the merged ledger column for every PR the pass evaluated and emit the merge
stage's status line yourself (there is no merge agent) — stage=merge, issue=<n>,
retries=0 (the merge pass doesn't retry through the ladder — a denial or base mismatch is a
policy/config fact, not a transient failure), and an outcome from the issue-implementer skill's
"Resilient dispatch" vocabulary for merge. When guard (e) ran, the status line and ledger row
also carry a trailing deploy=<verified|pending|failed> field, e.g.
<!-- harness-status: stage=merge issue=<n> outcome=merged retries=0 deploy=verified -->; no
field is emitted when there is no declaration or the outcome is not merged.
PRs that fail any check (guard or policy) simply stay in the "waits on the human" queue with a one-line reason — a normal outcome, not an error (the loud escalations above are for cases needing the human's attention beyond just "PR waits").
4. Ratchet pass (only under a repo test-suite ratchet policy)
Skip this pass entirely — silently — when CLAUDE.md has no section titled exactly
"Test-suite ratchet policy"; everything past activation is loud. Runs after the merge pass
(measurement then reflects everything that landed). When active, invoke the test-ratchet
skill and let it run its full procedure (activation check, measurement, gap selection under its
hard floor, filing, report) unmodified — this pass is sequencing plus one cost guard: skip the
measurement (say so) when this run merged nothing and the pre-flight found the default
branch unchanged from baseline (a standalone invocation always measures).
No ledger row, no status line — touches no issue already in the pipeline, dispatches no
agent. Note the issue numbers it filed: step 5 lists each as unledgered. Report what it filed
in "what this cycle did" — issue links, the measurement figure, and that each carries
no-auto-approve.
5. Close the loop
harness-status.sh
Closing reconciliation. Pipe the ledger (serialized per "Dispatch ledger" above) through the reconciler — it re-reads live state itself, no temp file needed:
reconcile-ledger.sh - <<'LEDGER'
14 seed unplanned 0
14 planner plan-posted 0
17 seed ready_to_implement 0
17 implementer complete 0
17 verifier pass 0
LEDGER
This heredoc form is covered by the single Bash(reconcile-ledger.sh:*) grant — a heredoc body
is not split into separately-matched subcommands — verified live; see README "Safety model".
No output, exit 0 → every queued issue accounted for. Otherwise one line per discrepancy, exit 1
(expected, not a tool failure); reconcile-ledger.sh's own output defines each code. Per class:
stage-skipped / outcome-missing / unknown-outcome → escalate. contradiction → report
with evidence, treat as unfinished. unledgered → usually a mid-run filing (say so, let the next
cycle take it; name a ratchet-pass filing as such, not a discrepancy) — unless it was in the
pre-flight discovery output, in which case the seed step missed it: escalate that. No script on
PATH → fall back to comparing the ledger against the JSON by hand, same criteria.
Per-issue summary table, before the two-halves report: issue, planned / implemented / verified / merged (outcome or "—"), retries, duration, final state, escalations.
Two-halves report, from the status JSON and the sub-skills' summaries: (1) what this cycle
did — plans posted/revised/auto-approved, PRs opened/merged (links + evidence), issues blocked,
CI outcomes, lessons, hygiene fixes; (2) what waits on the human — plans to review
(BLOCKING/ADVISORY counts), PRs to review/merge (CI state, the one-line reason each didn't
qualify for the merge pass, verified, merge blocked PRs with their exact command), blocked
issues (blocker, one line each) — copy-paste actionable. Nothing done and nothing waiting → say
"all quiet" in one line and stop (still an empty ledger, not a skipped reconciliation — only
applies when there was truly nothing to seed).
Unattended operation
- Recurring runs: pair with
/loop(e.g. "loop the issue-cycle every 30m") or a scheduled routine; each invocation stays ONE bounded pass — recurrence is the wrapper's job, never this skill's (never polls for new work or repeats a pass; the merge pass's declared deploy waits — guard (e) and the pre-first-merge recheck — are the two bounded exceptions). - Single-flight: never start a cycle while another runs in the same checkout (they'd share a working tree exactly like two implementers would); if evidence of a live concurrent run appears, stop and say so.
- Human-latency, not machine-latency, is the throughput limit. The cycle keeps the queues drained; the report's "waits on the human" half is the backlog that matters — say so explicitly if the same items recur rather than repeating the list mechanically.
Rules
- No authority beyond the repo's delegation. Every rule of the composed skills applies verbatim — this skill adds sequencing plus the merge pass, nothing else. Never approve outside the auto-approval policy path and its hard floor; merge authority is defined once, in the merge pass's activation conditions and hard floor (step 3), nowhere else; the ratchet pass files issues and nothing else; never touch a dirty tree that isn't the harness's own.
- Fail towards the human. Any pass in an unexpected state (red baseline, repeated crash recovery on the same issue, discovery truncation that won't drain, a resume cap exceeded, an exhausted retry ladder) stops that issue's progress and reports, rather than looping through the damage.
- No stage skipped but unreported. Every ledger row gets an outcome (success, blocked, or escalated) for every stage it reached — enforced by the pre-advance checks per pass and the closing reconciliation in step 5.
- One cycle, one report. Even when both passes ran, the human gets a single consolidated report at the end, not two skill summaries stitched mid-run.