| name | my-tidy |
| description | Use when the user says '/my-tidy' or 'tidy [path]' or asks for a cleanup of dead code, unused imports, dead branches, or stale comments — without changing logic. Scoped to a single file or directory only. Always shows the diff and waits for approval before applying. |
| trigger | /my-tidy |
/my-tidy
Scoped, no-logic cleanup. Strips obvious slop — unused imports, unreferenced functions, dead branches, comments-that-narrate-the-code, commented-out blocks. Never touches logic. Never widens scope on its own.
Trigger
/my-tidy (current dir), /my-tidy <path> (file or directory). The path is the scope — you may not touch anything outside it.
If no path is given, default to the current working directory but cap at top-level files only — do not recurse into subdirectories without an explicit path.
What "tidy" means (whitelist — do only these)
- Remove unused imports that the language's own tooling agrees are unused.
- Remove unreferenced top-level symbols (functions, classes, constants) that have zero callers in the repo.
- Delete dead branches:
if False:, if (true) {} else { ... }, code after unconditional return / throw / panic.
- Delete commented-out code blocks older than the current change (i.e. already in git history). One-liner comments explaining why stay.
- Delete narration comments — comments that paraphrase the next line of code (
# loop over users, // increment counter). Comments explaining why stay.
- Delete
TODO/FIXME comments the user authored that are stale (older than 90 days per git blame) — but only after listing them first and getting approval.
- Collapse trivial duplication only when the same expression appears 3+ times in the same file with identical operands. (Three duplications, not two — per
~/.claude/CLAUDE.md.)
What tidy must NOT do
- No renames. (That's
my-refactor-surgeon.)
- No reformatting (
post-edit-format hook handles that on save).
- No "improvements" — extracting helpers, simplifying conditionals, replacing loops with comprehensions, modernizing syntax. Logic-preserving ≠ logic-touching.
- No edits across files (other than removing imports of a deleted symbol).
- No deletes if the symbol is exported from a public API surface (
__all__, package.json:exports, etc.).
- No edits to test files, generated files, or vendor directories.
Workflow
1. Bound the scope
List the files in scope. If > 30 files, refuse and ask for a tighter path.
2. Detect language tooling
For removing unused imports / unreferenced symbols, prefer the language's own tooling:
| Language | Tooling |
|---|
| Python | ruff check --select F401,F811,F841 --fix (only these rules), or pyflakes if no ruff |
| JS/TS | eslint --rule 'no-unused-vars: error' --fix if eslint is configured, else read imports manually |
| Go | goimports -w for imports; for symbols, grep |
| Rust | cargo +nightly fix --allow-dirty -Z unstable-options (skip if not nightly), else grep |
If tooling isn't available, fall back to reading + grep. Never invent imports being unused without a grep that proves zero callers.
3. Optional — load the code-map
Check for graphify-out/graph.code-map.json in the repo root. If present and ≤ 7 days old, parse nodes and surface the unreferenced nodes (zero incoming edges) within the scope as the first cleanup candidates. Format:
Code-map suggests these are unused (verify before removing):
- <symbol> <file>:<line> (graph: 0 incoming edges)
...
If the map is stale or missing, skip silently — fall back to language tooling + grep.
4. Build the cleanup proposal
List every change as a bullet:
<file>:<line> — remove unused import foo``
<file>:<lines a–b> — delete unreferenced function helper_x (0 callers)
<file>:<line> — delete narration comment
<file>:<lines a–b> — delete commented-out block (last touched <date> per git blame)
Cap at 50 items. If there are more, show the top 50 by impact and stop with Run /my-tidy <subpath> to continue.
5. Show, don't apply — request confirmation
Show the proposal as a unified diff (git diff style preview, but generated yourself; do not edit yet). End with the literal sentence:
Apply these changes? Reply 'apply' to proceed, or list line numbers to skip.
6. Apply on approval
On apply:
- Make the edits.
- Run the project's test suite (detect via the same matrix as
/my-ship-it). If tests fail, revert touched files with git checkout -- <files>, report which test broke, stop. Tidying that breaks tests means you removed something that wasn't actually unused.
- On success: print
Tidy complete: <N> changes, <K> tests still passing. Show git diff --stat.
Hard rules
- Refuse vague scope. "Tidy the project" → ask for a path.
- Never touch logic-bearing lines. A dead
else: return None is dead code; a return None reachable in any branch is logic.
- Never delete a public symbol unless the user explicitly named it.
- Always run tests after applying. A green tidy is the only kind that ships.
- Always show the diff first. No surprise edits.
Anti-patterns
- "While I'm here, I refactored the loop too." No. Out of scope. Surface as a follow-up suggestion.
- Removing imports that look unused but are imported for side effects (e.g.
import package_that_registers_handlers). When in doubt, keep.
- Stripping comments wholesale. Some comments encode constraints (
# must run before X, # do not parallelize — DB locks). If the comment explains why anything, keep it.