Solve Issue
Runs the full issue workflow in one command; Flow Overview below is the phase list.
Designed for issues the user already judged simple. When uncertainty appears, pause and
ask — or, under auto, decide through a board (Asking the User).
Mutation class: writes to external services. It edits the working tree, and through
issue-flow it commits, pushes, opens pull requests, files issues, and merges.
This skill owns engineering judgment only. Every git and gh write in the
lifecycle — issue selection, branch, snapshot, commit, squash, push, PR, merge — belongs
to issue-flow, and its rules stay its own: do not restate its commit format or squash
rules here, and do not run a write its loaded instructions did not direct. The one write
it does not own is the pull request's own review threads: pr-review posts and resolves
those in Phase 7.
Read-only git diff / git status / git log, and gh pr view plus gh api GETs,
are yours — for scoping and for reading review state. allowed-tools cannot express a
method restriction, so its gh api grant is wider than that: this sentence is the limit,
not the declaration. A gh api call with -X, -f, or --input is a write — it belongs
to issue-flow.
Conventions
Asking the User
Every question in this skill is written as AskUserQuestion options. Use that tool where
the host offers it, or the host's nearest structured-choice equivalent. Where the host has
neither, ask the same question in normal chat as a numbered list of 2–5 options —
recommended first, one short line of description each — and wait for the user to reply
with a number.
Every gate defaults to proceeding, so a host that cannot prompt still completes the flow;
Flow Overview lists which phases ask. A Stop option exits the run cleanly, leaving
local state as it stands. auto in $ARGUMENTS is an unattended run: take the
(Recommended) option at every gate, the Phase 6 endgame and the Phase 7 seam question
included. A bare auto with no issue number still asks Phase 0.
Unattended, no question is asked. Where a phase would stop for a decision that has no
(Recommended) option — a Phase 2 pause condition, or a Phase 3 blocker of the "decision
required" kind — invoke consilium with the decision and its candidates, take its ranked
recommendation, and record it in the Phase 6 summary as Decided unattended: <choice> — <one-line reason>; without consilium, stop as an attended run would. A blocker no
decision resolves — missing credentials, a service down, an open blocking issue — still
stops the run. Notes are filed only where Phase 7's bar admits them — see Phase 7 →
File the deferrals before merging.
Delegating to Other Skills
This skill is an orchestrator: it invokes issue-flow, issue-analyze, changes-review,
tests-audit, live-probe, code-cleanup, pr-review, and under auto consilium and
doubt, rather than reimplementing them. "Invoke <name>" means hand control to that skill however the host chains skills.
Where chaining means loading its instructions into this context, it means following
them — its commands included. They stay its rules, not yours.
issue-flow and issue-analyze are hard prerequisites: the lifecycle's writes live
in one and the scope analysis in the other, so a host that cannot invoke another skill
cannot run this one. Stop with solve-issue needs to invoke issue-flow and issue-analyze; this host cannot chain skills. rather than reimplementing the lifecycle inline. The rest
are graceful — each call site names its inline fallback in two lines or less.
Editing Files
Apply targeted edits per hunk; never rewrite a whole file to change part of it — in implementation, simplification, advisor fixes, the comment pass, and Phase 7 fixes alike.
Tracking Progress
Where the host has a task list, put one entry per Changes item in it and update entries as you go. Where it does not, keep the printed numbered Changes list as the tracker and state which item you are on before starting it. Either way, progress is visible per item — never a single opaque "implementing" step.
Flow Overview
| Phase | Step | Asks user? |
|---|---|---|
| 0 | Resolve issue number | Only if $ARGUMENTS is empty |
| 1 | Analyze via issue-analyze |
No |
| 2 | Plan + create branch | Only if plan is genuinely uncertain |
| 3 | Implement | Only on hard blockers |
| 4 | Verify (checks + optional probe) | Only to opt into a live observation |
| 4.4 | Subtle simplification pass | No |
| 4.5 | Tests audit (only if tests moved) | No |
| 4.6 | Advisor round(s) + apply fixes | No |
| 5 | Comment cleanup + commit | No |
| 6 | Summary + choose endgame | Always — unless auto (takes Option 1) |
| 7 | Review feedback, then merge | Through pr-review's own gate |
Phase 0: Resolve Issue
If $ARGUMENTS holds an issue number or GitHub issue URL, use it and skip to Phase 1.
If it carries no number, ask, per Asking the User:
question: "No issue number provided. How should I pick one?"
Option 1 — header
Next issue, labelLet issue-flow pick(Recommended)—Rank the backlog and recommend the most relevant open issue.Option 2 — header
Manual, labelStop and ask—Exit so you can re-run with an explicit issue number.Option 1 → invoke
issue-flowwith intent"pick an issue". Its Step 0 ranks the backlog, lets the user choose, and chains intoissue-analyzeon the selection — continue from Phase 2 with the number and the analysis it returns.Nonepicked, or a short-circuit branch carrying no issue number, ends the run — stop and say which, since Phase 5 commits under the issue title.Option 2 → print
Re-run with an issue number, e.g. /solve-issue 42.and stop.
Two preconditions stop the run before anything else: gh unauthenticated, which
issue-flow or issue-analyze reports — relay it — and no git repository, which stops
with Not inside a git repository.
Phase 1: Analyze
Invoke issue-analyze on <N>. Do not duplicate its work inline — capture the Scope
Analysis and Implementation Tasks it emits. It is a prerequisite, not a nice-to-have: it
resolves the issue title this flow commits under, and the blockers Phase 1 stops on.
Stop conditions from the analyzer:
- Issue is closed → print its status line and stop.
- Issue has an open blocker → print the blocker and stop. Do not implement through an open blocker without explicit user approval.
- Issue is assigned to another user (
> Note:line) → continue, but flag the condition in the final summary.
End Phase 1 with one line: Phase 1: #<N> "<title>" — <N> tasks, <N> blockers. Then go to
Phase 2. Nothing is edited before the plan is printed.
Phase 2: Plan
Before drafting, list every file the Changes list will name plus its immediate callers, and open all of them in one batch. A plan naming a file nobody read is a guess. Do not edit anything yet.
Then print the plan inline, in the exact structure references/plan-format.md specifies —
goal, numbered file-level Changes, explicit out-of-scope, risks or decisions. That file
also carries the rules the body has to satisfy. Never write a plan file.
After printing it, set up progress tracking per Conventions → Tracking Progress — one entry per Changes item.
When to pause for approval
Default: proceed to Phase 3 immediately after printing the plan. The printed plan is the
checkpoint, and the user can interrupt if they disagree — do not ask for approval on a
simple issue. references/plan-format.md lists the conditions that override that default
and the shape of the one question to ask when any of them fires.
Create branch
A dirty working tree on the base branch stops the run here: Uncommitted changes on base branch — resolve first.
Otherwise invoke issue-flow with intent "start work on #<N>". That runs its Step 2,
which checks out issue-<N> off the correct base branch and updates the project board to
"In Progress" when available. If issue-<N> already exists, let issue-flow handle the
switch-vs-recreate prompt.
Record the Fork: SHA from its Step 2 report — later phases scope verification by it and
pass it to the reviewers. Use Fork:, not Base:: a branch name that exists only on the
remote fails git diff with unknown revision, a SHA always resolves.
Every phase that scopes by the fork reads the working tree, never <fork>..HEAD. The
form is git diff --name-only <fork> plus git ls-files --others --exclude-standard,
stated once here. Snapshots are optional until Phase 4.6, so without one HEAD still is
the fork and that range is empty while the changes sit unstaged.
Do not detect the base yourself; issue-flow owns it and handles the epic-* cases.
Entered on an existing branch with no Step 2 report, ask issue-flow for the fork point.
End Phase 2 with one line: Phase 2: branch issue-<N> off <base>, fork <sha>, <N> changes planned.
Phase 3: Implement
Work through the tracked Changes items sequentially. Mark each one started when you begin it and done as soon as it is done — no batching.
For a checkpoint mid-implementation, invoke issue-flow with intent "snapshot" — its
Step 3 snapshot mode freezes the tree into a content-free wip: commit. Phase 5 squashes
those away. Do not push between tasks.
If a task hits a hard blocker (missing credentials, external service down, decision
required), stop and ask the user — or, under auto, act per Asking the User.
End Phase 3 with one line: Phase 3: <N>/<N> changes implemented, <N> files touched. Then
go to Phase 4 — do not run the project's checks ad hoc as you go; Phase 4 selects them.
Phase 4: Verify
Detect the verification set from package.json + repo conventions. Do not
skip verification on "simple" changes.
Choosing what to run
references/verification-set.md has the script groups, the runner-from-lockfile rule,
and which groups the changed file set selects. Scope it with the Fork: SHA recorded in
Phase 2, not a branch name.
A repo that declares nothing runnable is not a pass: report verification as unverified
and name what was missing, rather than inventing a command the project never declared.
Observe it running (opt-in)
Checks prove the change compiles and that nothing already covered broke. They do not prove a claim about observable output — layout, rendering, wire format, exit code, timing, log content, a golden result. Where the issue asked for a change of that kind, ask, per Asking the User:
- Option 1 — header
Skip probe, labelSkip observation(Recommended)—Checks cover this scope. - Option 2 — header
Observe, labelRun and observe—Run it the way this project declares and read the result.
The default is to skip: starting things is slow and leaves an artifact to clean up. On
opt-in, invoke live-probe with the behavior the issue asked for; it reads the project's
declared way to run and observe from the instruction layer first (CLAUDE.md, AGENTS.md,
rules files), then the repo's declared commands, and reports unverified rather than
inventing one. Expect one such tool, not a matched pair. Where the host cannot chain
skills, follow the same method inline.
On failure
If any verification step fails:
- Go back to Phase 3, fix the cause, and re-run only the failing check.
- If the same check fails twice after two fix attempts, stop and hand back to the user with the failure output. Do not proceed past Phase 4 with failing verification. Do not rationalize skipping it.
Ending the phase
Phase 4 is over when every check the verification set selected is green. End Phase 4 with
one line naming every group, including the ones that did not run and why: Phase 4: type-check ok, unit tests ok (<N> passed), build ok, lint not configured — observation skipped.
Then stop. Do not re-run the whole suite on top of the selected set, do not add a check the set did not select, and do not re-read the diff for a second opinion. Phase 4.6 is where the change gets attacked, by reviewers who are not you.
Phase 4.4: Simplify
Run this before the advisor round, so the reviewers attack the code that will actually ship. A simplification applied after review ships unreviewed.
Dispatch one subagent over the changed files with a single instruction: apply subtle, behavior-preserving simplifications against the bar below, and nothing else. If the host has no subagent facility, run the same instruction inline.
The simplification bar
Apply only when all hold:
- Behavior is provably unchanged
- The change is contained to a single function or a local symbol
- No public export, API shape, or file layout is touched
- It makes the code shorter and clearer, not merely shorter
Anything heavier — splitting functions, reshaping control flow, extracting utilities, renaming exported symbols — is not applied. Record it for the Phase 6 summary and move on: a refactor that is merely nice is out of scope for an issue the user called simple.
Re-run the Phase 4 checks the simplifications could plausibly break. Revert anything that fails rather than fixing around it — behavior-preserving was the bar, and a failing check is proof it was not met.
End Phase 4.4 with one line: Phase 4.4: <N> simplifications applied, <N> reverted, <N> recorded as out of scope. Then stop — one pass only. A second pass over the result is how
a subtle simplification turns into a refactor nobody reviewed.
Phase 4.5: Tests Audit
Take the changed test files from the working tree, per Phase 2 → Create branch. Skip this phase only when that set carries no test file.
When that set is non-empty, dispatch one general subagent that loads tests-audit over
those files — tests-audit is a skill, not an agent type. Its brief is the changed test
paths and the code under test and nothing else — not the plan, not what you were trying to
do, since your justification is the one thing that would let a weak test through. Where the
host has no subagent facility, run it inline under the same restriction. It runs before
the advisor round for the reason Phase 4.4 does, and it runs the suite — order dependence
and flakiness are invisible in a diff.
tests-audit reports and never edits, so applying its verdicts is this phase's job.
references/tests-audit-pass.md has which verdicts to apply against a test this branch
wrote, one it modified, and one it merely lives beside, and the gate to run inline when
the skill is not installed.
The rule that never bends: a tightened assert that now fails is either the defect the loose one was hiding — fix it, that is the payoff — or a bad tightening, in which case revert that assert. Never loosen it back to make the suite green.
End Phase 4.5 with one line: Phase 4.5: <N> tests audited — <N> tightened, <N> rewritten, <N> deleted, <N> noted. Then stop. Do not widen the audit to tests this branch never
touched — a verdict on one of those is a Note for Phase 6, not work for this issue, with
the single exception the reference's Tighten row names.
Phase 4.6: Advisor Round
Independent reviewers attack the change in parallel; the findings are then triaged and fixed. This always runs once verification is green.
The review itself belongs to changes-review. This phase owns only workflow policy:
freezing the diff, triaging findings, and deciding whether to run a second round. Do not
duplicate the reviewer prompts here, and do not invoke consilium — that board ranks
candidate approaches and has nothing to say about whether a finished diff is correct.
Freeze the diff first
Every reviewer must see the same change set. Before dispatching, delete the cruft listed under Phase 5 → Remove cruft — the snapshot stages everything, and a baked-in scratch file is invisible to Phase 5's untracked check.
Then, if the tree is dirty, take a snapshot per Phase 3 — issue-flow with intent
"snapshot".
Each round freezes again — round 2 must snapshot the round-1 fixes before dispatching, or
the reviewers re-review the diff they already saw. Round 2 and later also pass
--mode simple with the previous round's snapshot as the base, so the reviewers attack
the fix rather than re-reading the whole branch to check a two-line change.
Carry your own list of findings you accepted rather than fixed: the reviewers are blind to previous rounds by design, so recognizing a repeat is your job.
Run the review
Invoke changes-review with --base <fork> and --issue <N>, using the Fork: SHA
recorded in Phase 2 — it resolves as a rev where a branch name may not. It dispatches the
reviewers, re-attacks its own findings — verification is on by default for a --base run
— and returns what survives. It changes nothing.
Pass no other context — not the plan, not the Risks section, not a summary of intent, not the previous round's findings or triage. Its value is reviewers blind to your reasoning.
If changes-review is not installed, note that in the Phase 6 summary, skip this phase,
and go to Phase 5. Do not hand-roll a reviewer round in its place.
Triage and fix
Classify every returned finding:
| Class | Meaning | Action |
|---|---|---|
| Fix | Real defect or a genuine requirement gap | Apply now |
| Note | Valid but out of scope for this issue | Report in Phase 6 |
| Reject | Wrong, or the reviewer lacked context that makes the code correct | Report in Phase 6 |
Rules that keep triage honest — you are judging reviews of your own work, and the pull toward dismissal is real:
- Uncertainty defaults to Fix. If you cannot show a finding is wrong, it is not rejected.
- A Reject must name the specific context the reviewer lacked — the file it could not see, the invariant it did not know. "I don't think that's right" is not a rejection.
- Rejects survive verbatim. Phase 6 carries the reviewer's own wording, not your paraphrase of it. The user grades the rejection, not your summary.
Apply the Fix items, then re-run the Phase 4 checks the fixes could plausibly break. Verification must be green again before continuing. If a check the fixes broke still fails after two attempts, revert those fixes, list them as Notes, and go to Phase 5.
Round 2
Run a second round if any of these hold:
- The fixes touched a file that was not in the round-1 diff
- The fixes changed more than ~30% of the round-1 changed-line count
- You rejected any intent-reviewer finding
- You rejected more than half of all findings
The last two exist because a wrongly rejected bug does not change the diff, so no size-based trigger sees it.
Otherwise stop at one round. Hard cap: two rounds. If round 2 surfaces another large batch, do not run a third — apply the clear fixes, list the rest as Notes, and let the PR review catch them.
End each round with one line: Phase 4.6 round <N>: <N> findings — <N> fixed, <N> noted, <N> rejected. A round ends only in one of three states: no findings, findings triaged
with the Fix items applied and verification green, or the cap reached. A description of
what a further round would attack is not a state — either run it or go to Phase 5.
Phase 5: Cleanup + Commit
Trim comments
Invoke code-cleanup --comments-only, scoped to the change — it removes comments that
restate the code, compacts genuine gotchas to a line or two, and surfaces design rationale
for the commit body. --comments-only is deliberate — no code changes at commit time;
a simplification found here is a Note for Phase 6, not work, because it would ship
unreviewed. Its Suggested for commit message section is an input to the commit body —
pass it along under Commit below.
If code-cleanup is not installed, do the comment pass inline: delete comments that
narrate what the code already says, that repeat what a nearby comment carries, or that
point at an issue or PR instead of stating the fact. Keep non-obvious gotchas at one to
two lines. Leave documentation comments and HACK/FIXME/TODO markers alone.
Remove cruft
Delete anything that should not ship with the commit:
- Plan and scratch files under
.claude/plans/,.claude/plan/, ordocs/superpowers/— gitignored working artifacts. Only files this run created; never a config directory. - Temp files under
tmp/or.tmp/at the repo root created during this run - Captured probe artifacts — screenshots, traces, dumps — wherever the instruction layer puts them. Nothing this run captured ships in the commit, a retained frame included
Use git status --short to sanity-check that no untracked scratch files are about to be
staged, and that every intended deletion shows up.
Commit
Invoke issue-flow with intent "commit #<N>". Its Step 3 squashes the branch to one
commit, writes the subject and body, and reports the result. It owns the subject format,
the body, and the squash rules for every wip: snapshot Phase 4.6 created — do not
restate any of them here, and do not run the git commands yourself.
Pass along, as context for the commit body: the issue title and number, and the design
rationale code-cleanup pulled out of the source — it belongs in the body's why
paragraph, not appended at the end.
Capture the short SHA and subject from Step 3's report for the Phase 6 summary. If Step 3 comes back with a dirty tree or more than one commit, re-invoke it rather than fixing the history here. The endgame pushes the commit, not the working copy.
End Phase 5 with one line: Phase 5: <N> comments trimmed, <N> cruft files removed, committed <short-sha> <subject>. Then stop. Nothing leaves the machine until Phase 6
asks — no push, no pull request.
Phase 6: Summary + Endgame
Print the summary references/report-format.md specifies — what changed, what was
verified, what the tests audit moved, what the advisors found, and the commit. That file
carries the shape and a full example; the fragment that is most often wrong is this one:
**Not applied**
- Note: out of scope — the same clamp exists in `Popover.tsx`, untouched by this issue
> `Popover.tsx:88` repeats the clamped-rect bug this change fixes in `Tooltip`.
- Reject: the reviewer could not see `ResizeObserver` is installed by `useAnchorRect`
> The rect is never recomputed on resize, so the flip is stale after a window resize.
Never omit a Reject: a rejected finding the user never sees is the one failure mode this whole phase is built to prevent, and Phase 4.6 requires the reviewer's own wording.
Then ask, per Asking the User:
- question: "What's next for this commit?"
- Option 1 — header
PR + merge, labelPush, PR, auto-merge(Recommended)—Push, open a PR, answer the automated reviewers, file an issue for anything deferred, merge once no reviewer is left unresolved. - Option 2 — header
PR only, labelPush and open PR—Push, open a PR, answer any review already in, stop before merge. - Option 3 — header
Push only, labelPush the branch—Push the branch. No PR. - Option 4 — header
Nothing, labelLeave it local—Keep the commit local. No push.
Route via issue-flow:
| Choice | issue-flow intent |
Then |
|---|---|---|
| PR + merge | "push and open PR for #<N>" — Steps 4 and 5 |
Phase 7, then Step 6 merge |
| PR only | "push and open PR for #<N>" — Steps 4 and 5 |
Phase 7, then stop |
| Push only | "push #<N>" — Step 4 |
Stop |
| Nothing | Stop — commit stays local | — |
The merge is not part of the endgame invocation. PR + merge opens the pull request,
hands to Phase 7, and merges only after the automated reviewers have had their window; a
single "push, PR, and merge" intent merges past them. issue-flow owns its per-step
questions — squash confirmation, reviewer selection, merge pre-checks — do not repeat them.
Both PR endgames continue into Phase 7 and end with issue-flow Step 5's Mergeable:
line, not a PR URL. CONFLICTING means the flow is not done: rebase, force-push, re-check,
report the resolved state.
End Phase 6 with one line: Phase 6: <endgame chosen> — PR #<M>, Mergeable: <state>.
Phase 7: Review Feedback
Runs on both PR endgames. Skipped for Push only and Nothing.
Detect, then decide whether waiting buys anything. A bot is expected when the pull
request's timeline records a bot review_requested event, and has reported when its
review appears against the current head SHA. A review already in is worked on either
endgame; only PR + merge polls for one that is not. Report what the queries showed, with
the time checked — never No automated reviewers, which no query supports.
references/review-feedback.md has both queries, the decision table, the bot-matching
rule, and the budget.
Then invoke pr-review <N> --fix, which owns the step — standing, verifying each claim,
the six verdicts, the reply, the resolve. Do not re-triage its findings. On PR + merge
add --auto, which posts unattended on bot-rooted threads only and holds human threads as
unsent drafts, plus the instruction to publish nothing until the fixes are pushed — a reply
naming an unpushed fix is false when it posts. The order is fix, check, push, publish.
Code that --fix applied is uncommitted work on the squashed commit. It ran the project's
checks per fix, so re-run the wider Phase 4 set once over the final tree, then invoke
issue-flow with intent "amend and push #<N>", message verbatim. Skip the amend when
nothing changed: force-pushing an identical tree re-triggers CI and the reviewers for nothing.
After the push, run both detection queries again against the new head, per
references/review-feedback.md → Rounds. Run this phase at most twice.
File the deferrals before merging
On PR + merge only. Before the merge intent, invoke issue-flow with intent "create an issue" for each defer in pr-review's report, and put the numbers in the report.
Choosing PR + merge is the approval — this is the one mutation with no gate of its own.
Phase 6 Notes are filed under auto only, and then only where a Note is a confirmed
defect, a regression, or absent test coverage for shipped behaviour — being true is not the
bar. doubt rules on the set first; without doubt, file nothing. An attended run files
no Note at all: they stay in the report for the user. references/review-feedback.md →
Filing the deferrals has what goes in each issue, why filing any earlier is impossible,
how Notes are grouped, and what to do when the host cannot reach issue-flow.
Report and close
Append the Review feedback block references/report-format.md specifies — including
what the fixes changed, because the merge ships code the Phase 6 summary did not describe
— then close the endgame:
- PR + merge — invoke
issue-flowwith intent"merge #<N>", once no reviewer is left unresolved; its Step 6 waits on CI. A bot that timed out counts as unresolved: report it and leave the pull request open. A human thread held for a person does not block the merge — it can never be resolved by this run. - PR only — print the open-thread state and stop.
If pr-review is not installed, list the open threads with their authors and claims and
stop there. Do not hand-roll replies: an unverified rejection posted in public cannot be
taken back.
End Phase 7 with one line: Phase 7: <N> threads — <N> fixed, <N> rejected, <N> discuss, <N> deferred, <N> notes (filed #<...>); merged | left open (<reason>). Then stop. Do not open a
third round, and do not re-review the diff after the merge — the run is over.