Refactor $ARGUMENTS. A targeted refactor includes the performance pass
below — it is on by default, not a separate command.
Guardrails
- Spawn a worker and explicitly select your tool's mid tier. State the
tier on the spawn — do not omit it and rely on a default. An omitted tier
inherits the parent's tier, which is not the same thing as the balanced
one. Pick the judgment-capable tier that is cheaper and faster than your top
reasoning tier. Not the cheapest/fastest tier: on judgment work it
measurably degrades (misclassification rates several times higher). Choose by
tier, not by a vendor model name copied from this file — names drift, and
this command ships to several tools. Fall back to running inline if your tool
has no subagent mechanism.
- Escalate, never assume. Anything you cannot decide, cannot verify, or
that this spec does not cover → stop and report it to the orchestrator
(the main session). Never improvise, never widen scope, never fix a side
issue you noticed along the way.
- The worker does the work itself — no delegation. The fixer must not
spawn subagents of its own. Every edit it reports, and every test run it
cites, has to be one it made or ran with its own tool calls: a relayed "I
fixed it and the suite is green" from a sub-worker is hearsay, and this
command's whole output is the claim that a change landed and the tests still
pass. A fix that delegates its work is a report about a report.
- The HITL gates below belong to the orchestrator, not the worker. A
subagent cannot hold a conversation with the user, so it cannot run a gate
that ends in stop and ask. When one trips — a failing test, a crossed
public API boundary, a change bigger than the bullet asked for — the worker
stops there and hands the situation back, with the options and its
reasoning but no choice made. The orchestrator asks. A worker that picks
revert / patch / update-test on the user's behalf has answered a question it
was never allowed to ask.
- Edit only what a surviving bullet names. Ledger mode's scope is the
bullets that survive revalidation, one change per bullet — not the
neighbouring code, not the formatting, not a second finding noticed on the
way past. Anything else goes back to the orchestrator to become a new
bullet.
- Prove the blast radius with two checks, because neither sees what the
other does.
git status --porcelain at exit must list only files a
surviving bullet named — that is this command's scope guarantee, and unlike
/branch-review it is not expected to be empty. It cannot police the
memory directory: .claude/ is normally gitignored, so porcelain stays
empty whether you deleted a fixed bullet, wrote nothing, or overwrote
MEMORY.md. So also take md5sum .claude/remember/* before you start and
again before you report, and show the comparison: only fix-ledger.md may
differ. last-review.md in particular is /branch-review's to write —
a fixer that touches it forges the gate that judges its own work.
Ledger mode — $ARGUMENTS empty
Work through .claude/remember/fix-ledger.md, the non-blocking findings
/branch-review has accumulated. Everything below (goals, constraints,
verification, HITL gates) still applies; this section only says what to
refactor and how to close each item.
- Tree must be clean and not on
main. The orchestrator runs this check
before spawning the worker, so a dirty tree costs no worker; the worker
then re-runs it as its own first act. git status --porcelain non-empty
→ stop, say what is uncommitted. On main → git switch -c chore/fix-ledger.
- Ledger missing or has zero bullets → say so and stop. Nothing to do.
- Revalidate every bullet first, fix nothing yet. For each:
git grep -F "<snippet>" -- <path>. No hit → delete the bullet and list it as
"cleaned by other work". Hit → re-read the surrounding code; if the finding
no longer holds, delete the bullet with a one-line reason. What survives is
the work list.
- Fix the survivors, one bullet per change, under the constraints below.
Delete each bullet as its fix lands. A fix that turns out to need a
behaviour change is not a refactor — leave the bullet, note it in the report.
- Run the tests as described below. Then report: fixed / dropped / left
with the reason per left item, and the remaining bullet count.
- Hand it back; do not chain it. Say plainly: commit, then run
/branch-review on this branch — ledger mode is a fixer, not a review,
and its diff gets the ordinary gate. That is a sentence you say, not a
sequence you run. They are two separate calls and both are the user's:
an answer of "commit", "yes" or "go" authorizes the commit and nothing
after it. Never start /branch-review off the back of it. Observed in the
field: a run chained the review onto the owner's "commit" and the owner
objected.
Goals
- Reduce complexity
- Improve readability
- Apply DRY
- Better naming
- Smaller functions (single responsibility)
- Remove needless work — the performance pass below
Performance — part of every targeted refactor
When $ARGUMENTS names a target, look for wasted work as well as messy
work: time and space complexity, N+1 queries, I/O inside a loop, needless
allocations, the same value recomputed repeatedly.
Ground every finding before you touch it. Performance claims are easy
to invent. A finding counts as confirmed only with at least one of:
- a profile, benchmark or log line showing call frequency or duration,
- the path sits on an obvious hot loop or per-request handler with real
volume,
- the user supplied evidence in the request.
Without one of those it is uncertain — report it, do not optimise it.
Speculative optimisation is scope creep with a stopwatch.
Fix confirmed findings under the same constraints as any other refactor:
minimal change, one obvious shape, no behaviour change, no API change.
After each such edit, re-read the changed region and confirm it still
computes the same answer — a perf change that quietly alters semantics is
the worst kind. Report per finding: location (file:line), cost
(concrete — "N+1 over ~1k rows on every page load", not "could be
faster"), change, expected improvement, trade-off
(readability / memory / consistency).
In ledger mode the surviving bullets are the whole scope — do not add
perf findings of your own. One you notice goes back to the orchestrator
as a new bullet, like any other side finding.
Constraints
- NO behavior changes
- Keep public API intact
- Existing tests must pass
Explain each change.
After the refactor — verify it didn't break anything
"Existing tests must pass" is the load-bearing constraint, and the only
honest way to know is to run them.
- Detect the project's test command (look for
package.json
scripts, pytest.ini / pyproject.toml, go.mod, Cargo.toml,
Makefile). If none is found, stop and ask before claiming the
refactor is done — silent green isn't acceptable.
- Run the tests. Scope to the affected area when possible (
-t,
--testPathPattern, pytest path/, go test ./pkg); otherwise run
the suite.
- Report pass / fail counts and any failure's name +
file:line.
Stop and ask when (HITL gates — not all the time, only here):
- a test fails after the refactor. Don't auto-revert (destroys
work-in-progress) and don't push forward (the no-behavior-change
constraint is broken). Present the failure and the options:
revert, patch the refactor, or update the test (with
reasoning).
- the refactor crossed a public API boundary that callers depend
on — even if tests pass, downstream consumers may break.
- the change is bigger than the user asked for (scope creep —
unrelated cleanups, formatting, comment edits). Confirm before
applying.
- a perf fix has multiple reasonable shapes (cache vs precompute vs
batch vs paginate vs index) — present the options with trade-offs, not
a chosen path.
- a perf fix trades correctness for speed (lossy approximation,
weaker or eventual consistency) — even when it is "obviously" faster.
- a perf fix touches concurrency primitives (locks, atomics,
ordering) — easy to introduce a race.
- a perf fix changes a DB schema, response shape or caller contract.
Final report:
- refactor done, tests N pass / 0 fail — ready, OR
- refactor done, but K tests fail — awaiting direction (revert /
patch / update test).
Plus the performance pass: confirmed-and-fixed · confirmed-but-asking
(why + options) · uncertain (what profiling or data would settle it) ·
none found.
1---2name: refactor3description: Refactor and optimize [code]4---5Refactor $ARGUMENTS. A targeted refactor includes the performance pass6below — it is on by default, not a separate command.78## Guardrails9- **Spawn a worker and explicitly select your tool's mid tier.** State the10 tier on the spawn — do not omit it and rely on a default. An omitted tier11 inherits the *parent's* tier, which is not the same thing as the balanced12 one. Pick the judgment-capable tier that is cheaper and faster than your top13 reasoning tier. **Not the cheapest/fastest tier**: on judgment work it14 measurably degrades (misclassification rates several times higher). Choose by15 tier, not by a vendor model name copied from this file — names drift, and16 this command ships to several tools. Fall back to running inline if your tool17 has no subagent mechanism.18- **Escalate, never assume.** Anything you cannot decide, cannot verify, or19 that this spec does not cover → **stop and report it to the orchestrator**20 (the main session). Never improvise, never widen scope, never fix a side21 issue you noticed along the way.22- **The worker does the work itself — no delegation.** The fixer must **not**23 spawn subagents of its own. Every edit it reports, and every test run it24 cites, has to be one it made or ran with its own tool calls: a relayed "I25 fixed it and the suite is green" from a sub-worker is hearsay, and this26 command's whole output is the claim that a change landed and the tests still27 pass. A fix that delegates its work is a report about a report.28- **The HITL gates below belong to the orchestrator, not the worker.** A29 subagent cannot hold a conversation with the user, so it cannot run a gate30 that ends in *stop and ask*. When one trips — a failing test, a crossed31 public API boundary, a change bigger than the bullet asked for — the worker32 **stops there and hands the situation back**, with the options and its33 reasoning but no choice made. The orchestrator asks. A worker that picks34 revert / patch / update-test on the user's behalf has answered a question it35 was never allowed to ask.36- **Edit only what a surviving bullet names.** Ledger mode's scope is the37 bullets that survive revalidation, one change per bullet — not the38 neighbouring code, not the formatting, not a second finding noticed on the39 way past. Anything else goes back to the orchestrator to become a new40 bullet.41- **Prove the blast radius with two checks, because neither sees what the42 other does.** `git status --porcelain` at exit must list only files a43 surviving bullet named — that is this command's scope guarantee, and unlike44 `/branch-review` it is not expected to be empty. It cannot police the45 memory directory: `.claude/` is normally gitignored, so porcelain stays46 empty whether you deleted a fixed bullet, wrote nothing, or overwrote47 `MEMORY.md`. So also take `md5sum .claude/remember/*` before you start and48 again before you report, and show the comparison: only `fix-ledger.md` may49 differ. `last-review.md` in particular is `/branch-review`'s to write —50 a fixer that touches it forges the gate that judges its own work.5152## Ledger mode — `$ARGUMENTS` empty53Work through `.claude/remember/fix-ledger.md`, the non-blocking findings54`/branch-review` has accumulated. Everything below (goals, constraints,55verification, HITL gates) still applies; this section only says what to56refactor and how to close each item.57581. **Tree must be clean and not on `main`.** The orchestrator runs this check59 before spawning the worker, so a dirty tree costs no worker; the worker60 then re-runs it as its own first act. `git status --porcelain` non-empty61 → stop, say what is uncommitted. On `main` → `git switch -c chore/fix-ledger`.622. **Ledger missing or has zero bullets** → say so and stop. Nothing to do.633. **Revalidate every bullet first, fix nothing yet.** For each: `git grep -F64 "<snippet>" -- <path>`. **No hit → delete the bullet** and list it as65 "cleaned by other work". Hit → re-read the surrounding code; if the finding66 no longer holds, delete the bullet with a one-line reason. What survives is67 the work list.684. **Fix the survivors, one bullet per change**, under the constraints below.69 Delete each bullet as its fix lands. A fix that turns out to need a70 behaviour change is not a refactor — leave the bullet, note it in the report.715. Run the tests as described below. Then report: **fixed / dropped / left**72 with the reason per left item, and the remaining bullet count.736. **Hand it back; do not chain it.** Say plainly: **commit, then run74 `/branch-review`** on this branch — ledger mode is a fixer, not a review,75 and its diff gets the ordinary gate. That is a sentence you *say*, not a76 sequence you *run*. They are two separate calls and both are the user's:77 an answer of "commit", "yes" or "go" authorizes the commit and nothing78 after it. Never start `/branch-review` off the back of it. Observed in the79 field: a run chained the review onto the owner's "commit" and the owner80 objected.8182## Goals83- Reduce complexity84- Improve readability85- Apply DRY86- Better naming87- Smaller functions (single responsibility)88- Remove needless work — the performance pass below8990## Performance — part of every targeted refactor91When `$ARGUMENTS` names a target, look for wasted work as well as messy92work: time and space complexity, N+1 queries, I/O inside a loop, needless93allocations, the same value recomputed repeatedly.9495**Ground every finding before you touch it.** Performance claims are easy96to invent. A finding counts as **confirmed** only with at least one of:97- a profile, benchmark or log line showing call frequency or duration,98- the path sits on an obvious hot loop or per-request handler with real99 volume,100- the user supplied evidence in the request.101102Without one of those it is **uncertain — report it, do not optimise it.**103Speculative optimisation is scope creep with a stopwatch.104105Fix confirmed findings under the same constraints as any other refactor:106minimal change, one obvious shape, no behaviour change, no API change.107After each such edit, re-read the changed region and confirm it still108computes the same answer — a perf change that quietly alters semantics is109the worst kind. Report per finding: **location** (`file:line`), **cost**110(concrete — "N+1 over ~1k rows on every page load", not "could be111faster"), **change**, **expected improvement**, **trade-off**112(readability / memory / consistency).113114In ledger mode the surviving bullets are the whole scope — do not add115perf findings of your own. One you notice goes back to the orchestrator116as a new bullet, like any other side finding.117118## Constraints119- **NO behavior changes**120- Keep public API intact121- Existing tests must pass122123Explain each change.124125## After the refactor — verify it didn't break anything126127"Existing tests must pass" is the load-bearing constraint, and the only128honest way to know is to run them.1291301. **Detect the project's test command** (look for `package.json`131 scripts, `pytest.ini` / `pyproject.toml`, `go.mod`, `Cargo.toml`,132 `Makefile`). If none is found, **stop and ask** before claiming the133 refactor is done — silent green isn't acceptable.1342. **Run the tests.** Scope to the affected area when possible (`-t`,135 `--testPathPattern`, `pytest path/`, `go test ./pkg`); otherwise run136 the suite.1373. **Report** pass / fail counts and any failure's name + `file:line`.138139**Stop and ask** when (HITL gates — not all the time, only here):140- a test **fails** after the refactor. Don't auto-revert (destroys141 work-in-progress) and don't push forward (the no-behavior-change142 constraint is broken). Present the failure and the options:143 **revert**, **patch the refactor**, or **update the test** (with144 reasoning).145- the refactor crossed a **public API boundary** that callers depend146 on — even if tests pass, downstream consumers may break.147- the change is **bigger than the user asked for** (scope creep —148 unrelated cleanups, formatting, comment edits). Confirm before149 applying.150- a perf fix has **multiple reasonable shapes** (cache vs precompute vs151 batch vs paginate vs index) — present the options with trade-offs, not152 a chosen path.153- a perf fix trades **correctness for speed** (lossy approximation,154 weaker or eventual consistency) — even when it is "obviously" faster.155- a perf fix touches **concurrency primitives** (locks, atomics,156 ordering) — easy to introduce a race.157- a perf fix changes a **DB schema, response shape or caller contract**.158159Final report:160- **refactor done, tests N pass / 0 fail** — ready, OR161- **refactor done, but K tests fail** — awaiting direction (revert /162 patch / update test).163164Plus the performance pass: **confirmed-and-fixed** · **confirmed-but-asking**165(why + options) · **uncertain** (what profiling or data would settle it) ·166**none found**.