Clean
One cleanup pass over the code a branch changed. It keeps behavior and the test
suite exactly as they were, and it ends with a ledger instead of a verdict.
This skill changes code. It is not a reviewer: it never scores, never grades,
and never emits findings for a human to action inside the diff. Anything it
notices outside the diff becomes a follow-up line, never an edit.
One pass. A standalone clean ends after its ledger. A nested clean returns its ledger
to the caller, which continues its next authorized work. Neither case starts a second
sweep.
Fixed point
The pass is scoped to a diff, so it starts by pinning where that diff begins.
Accept an optional ref argument (/clean <ref>). With none, the fixed point is
the merge-base with the default branch. Resolve it by the rules in
code-review's "Pin the fixed point" —
the same SHA, branch, tag, PR, and stale-base handling, cited rather than
restated. Confirm the diff is non-empty before touching anything.
The scope is the files changed since that point. Unchanged files are read
freely for context — that is how you learn the module that already covers a
behavior — but they are not edited.
Preconditions
Discover the repo's test command the way /ticket does: read AGENTS.md or
CLAUDE.md for a test line first, then the CI workflows, then package scripts.
An argument naming the command overrides discovery.
Run it before any edit.
- Green: proceed, and record the command and result for the ledger.
- Red: stop. Report the failing output and make no edits. A branch that is
already broken has no baseline to preserve, and a cleaner cannot tell its own
damage from damage that was already there.
- No runnable suite: proceed, say so in the ledger, and limit the pass to
changes a compiler, type checker, or linter can verify. Behavior preservation
is being asserted rather than demonstrated, and the ledger has to say which.
Generated and vendored code is skipped and named in the ledger.
Before the first edit, capture a pre-pass snapshot or patch for both the index and
working tree, including unrelated staged and unstaged content. It must be sufficient
to undo only the cleaner's edits without replacing the pre-pass state from the index
or HEAD.
Checklist
Load codebase-design for the vocabulary before
starting — module, interface, depth, seam, adapter, deletion test — and use those
words exactly. Load domain-modeling when the repo
has a CONTEXT.md, so renames land on the domain's own terms.
Apply the list once per changed module, in this order. Each item names the
charter rule that grounds it; a change with no rule
behind it is taste, and taste is not in scope.
- Naming and locality. Names say what the thing is in the repo's own idiom;
related code sits together. Rule: match the surrounding code.
- Dead code. Unreferenced functions, unreachable branches, commented-out
blocks, and leftover scaffolding introduced by the diff go. Rule: no dead
code, no speculative abstraction.
- Duplication. Behavior the diff re-implements, where an existing module
already reaches it through its public interface at that call site, collapses
to the existing module. Rule: reuse the module that already covers the
behavior.
- Shallow modules. A module the diff introduced whose interface is about as
complex as its implementation is deepened or inlined. Apply the deletion test:
if removing it only moves complexity around, it should not exist. Rule: deep
modules; the deletion test.
- Unearned guards. A guard for a state that cannot occur is complexity, not
safety. Remove one only when the ledger names the enforced invariant that
makes the state unreachable — code that rejects it, or a pinned test.
Otherwise keep it. Guards at a trust boundary, and guards grounded by
acceptance criteria, security, or observed behavior, always stay. Rule: earn
every guard.
- Speculative seams. A seam with one caller is a hypothetical seam; collapse
it and build it again when the second caller is real. Rule: one adapter is a
hypothetical seam, two is a real one.
Invariants
These bound every edit. A cleanup that cannot be made without breaking one of
them is not made — it becomes a follow-up line.
- No behavior change. Logic branches, error modes, and outputs are what they
were. Renaming a variable is in scope; changing what a condition decides is not.
- Nothing outside the diff. Public interfaces of modules the diff did not
touch stay untouched, however tempting.
- No new dependencies, and no scope expansion.
- Tests are not rewritten to pass. A test that fails after a cleanup is the
cleanup being wrong. Revert the cleanup, keep the test.
Post-check
Re-run the same test command.
- Green: the pass holds; write the ledger.
- Red: restore only the cleaner's own edits from a pre-pass snapshot or patch,
preserving the index and working-tree bytes that existed before the pass, including
unstaged edits. Do not use
git checkout, the index, or HEAD as a whole-file
substitute for that pre-pass state. If concurrent changes make safe reversal
uncertain, preserve them and report the conflict with the failing output.
Then stop.
Ledger
The ledger is the clean helper's final result. A nested clean returns it to the caller,
which continues authorized work; a standalone clean ends its single pass. Nothing is
written to the repo except the cleaned code itself: no plan file, no scratch directory,
no report committed to the branch.
It carries three things:
- Changes made — per change: the file, what moved, and the charter rule that
grounded it. A guard removal names its enforced invariant here or it is not a
legitimate removal.
- Follow-ups — what was noticed outside the diff, or inside it but blocked by
an invariant, listed for a human to route. Not fixed.
- Verification — the test command, its result before, and its result after.
A reduced pass (no runnable suite, skipped generated code) says so here.
Not this skill
- Review verdicts —
review routes those.
This skill edits; it does not grade.
- Writing tests —
tdd.
- Mutation testing, coverage gates, and other deterministic hardening — the
hardening step that runs after this one.
1---2name: clean3description: Clean the current branch's diff without changing behavior — naming, dead code, duplication, and the charter's deep-module rules — in one pass, then stop. Use when the user says "clean this diff", "/clean", "cleanup pass", or wants the branch tidied before review or hardening.4---56# Clean78One cleanup pass over the code a branch changed. It keeps behavior and the test9suite exactly as they were, and it ends with a ledger instead of a verdict.1011This skill **changes code**. It is not a reviewer: it never scores, never grades,12and never emits findings for a human to action inside the diff. Anything it13notices outside the diff becomes a follow-up line, never an edit.1415One pass. A standalone clean ends after its ledger. A nested clean returns its ledger16to the caller, which continues its next authorized work. Neither case starts a second17sweep.1819## Fixed point2021The pass is scoped to a diff, so it starts by pinning where that diff begins.2223Accept an optional ref argument (`/clean <ref>`). With none, the fixed point is24the merge-base with the default branch. Resolve it by the rules in25[`code-review`'s "Pin the fixed point"](../code-review/SKILL.md#1-pin-the-fixed-point) —26the same SHA, branch, tag, PR, and stale-base handling, cited rather than27restated. Confirm the diff is non-empty before touching anything.2829The **scope** is the files changed since that point. Unchanged files are read30freely for context — that is how you learn the module that already covers a31behavior — but they are not edited.3233## Preconditions3435Discover the repo's test command the way `/ticket` does: read `AGENTS.md` or36`CLAUDE.md` for a test line first, then the CI workflows, then package scripts.37An argument naming the command overrides discovery.3839Run it before any edit.4041* **Green:** proceed, and record the command and result for the ledger.42* **Red:** stop. Report the failing output and make no edits. A branch that is43 already broken has no baseline to preserve, and a cleaner cannot tell its own44 damage from damage that was already there.45* **No runnable suite:** proceed, say so in the ledger, and limit the pass to46 changes a compiler, type checker, or linter can verify. Behavior preservation47 is being asserted rather than demonstrated, and the ledger has to say which.4849Generated and vendored code is skipped and named in the ledger.5051Before the first edit, capture a pre-pass snapshot or patch for both the index and52working tree, including unrelated staged and unstaged content. It must be sufficient53to undo only the cleaner's edits without replacing the pre-pass state from the index54or HEAD.5556## Checklist5758Load [`codebase-design`](../codebase-design/SKILL.md) for the vocabulary before59starting — module, interface, depth, seam, adapter, deletion test — and use those60words exactly. Load [`domain-modeling`](../domain-modeling/SKILL.md) when the repo61has a `CONTEXT.md`, so renames land on the domain's own terms.6263Apply the list once per changed module, in this order. Each item names the64[charter](../../../profile/CHARTER.md) rule that grounds it; a change with no rule65behind it is taste, and taste is not in scope.66671. **Naming and locality.** Names say what the thing is in the repo's own idiom;68 related code sits together. *Rule: match the surrounding code.*692. **Dead code.** Unreferenced functions, unreachable branches, commented-out70 blocks, and leftover scaffolding introduced by the diff go. *Rule: no dead71 code, no speculative abstraction.*723. **Duplication.** Behavior the diff re-implements, where an existing module73 already reaches it through its public interface at that call site, collapses74 to the existing module. *Rule: reuse the module that already covers the75 behavior.*764. **Shallow modules.** A module the diff introduced whose interface is about as77 complex as its implementation is deepened or inlined. Apply the deletion test:78 if removing it only moves complexity around, it should not exist. *Rule: deep79 modules; the deletion test.*805. **Unearned guards.** A guard for a state that cannot occur is complexity, not81 safety. Remove one **only** when the ledger names the enforced invariant that82 makes the state unreachable — code that rejects it, or a pinned test.83 Otherwise keep it. Guards at a trust boundary, and guards grounded by84 acceptance criteria, security, or observed behavior, always stay. *Rule: earn85 every guard.*866. **Speculative seams.** A seam with one caller is a hypothetical seam; collapse87 it and build it again when the second caller is real. *Rule: one adapter is a88 hypothetical seam, two is a real one.*8990## Invariants9192These bound every edit. A cleanup that cannot be made without breaking one of93them is not made — it becomes a follow-up line.9495* **No behavior change.** Logic branches, error modes, and outputs are what they96 were. Renaming a variable is in scope; changing what a condition decides is not.97* **Nothing outside the diff.** Public interfaces of modules the diff did not98 touch stay untouched, however tempting.99* **No new dependencies**, and no scope expansion.100* **Tests are not rewritten to pass.** A test that fails after a cleanup is the101 cleanup being wrong. Revert the cleanup, keep the test.102103## Post-check104105Re-run the same test command.106107* **Green:** the pass holds; write the ledger.108* **Red:** restore only the cleaner's own edits from a pre-pass snapshot or patch,109 preserving the index and working-tree bytes that existed before the pass, including110 unstaged edits. Do not use `git checkout`, the index, or HEAD as a whole-file111 substitute for that pre-pass state. If concurrent changes make safe reversal112 uncertain, preserve them and report the conflict with the failing output.113 Then stop.114115## Ledger116117The ledger is the clean helper's final result. A nested clean returns it to the caller,118which continues authorized work; a standalone clean ends its single pass. Nothing is119written to the repo except the cleaned code itself: no plan file, no scratch directory,120no report committed to the branch.121122It carries three things:123124* **Changes made** — per change: the file, what moved, and the charter rule that125 grounded it. A guard removal names its enforced invariant here or it is not a126 legitimate removal.127* **Follow-ups** — what was noticed outside the diff, or inside it but blocked by128 an invariant, listed for a human to route. Not fixed.129* **Verification** — the test command, its result before, and its result after.130 A reduced pass (no runnable suite, skipped generated code) says so here.131132## Not this skill133134* **Review verdicts** — [`review`](../../workflows/review/SKILL.md) routes those.135 This skill edits; it does not grade.136* **Writing tests** — [`tdd`](../tdd/SKILL.md).137* **Mutation testing, coverage gates, and other deterministic hardening** — the138 hardening step that runs after this one.