goberomsu/craft-skills/refactor
Claude Code and agent skill by goberomsu/craft-skills
- community
- ext:[{"type":"hook","description":"Pre/post lifecycle hooks"}]
Checking that the SKILL.md file is still in the repository.
Restructures code without changing what it does — extracting functions, renaming, removing duplication, flattening nested conditionals, and other mechanical moves backed by a detection command and threshold. Use when the user says \"refactor this\", \"clean up this code\", \"리팩토링 해줘\", or \"this function is a mess\", or a named smell (long function, deep nesting, feature envy) surfaces while reading code with no intended behavior change. Gates untested legacy code behind a characterization-test…
Install
npx vskill@latest install goberomsu/craft-skills/refactorSemi-extensibleMentions customization, but needs skill-specific knowledge. Read the extensible skills standard
SKILL.md
refactor
Restructures code so it is easier to work with without changing what it runs — the moment behavior changes, the work is a feature or a fix, not a refactor. Done well: verification stays green at checkpoints proportional to the change's blast radius, each move is mechanical, and the diff never mixes structure with behavior.
Phase 0 — is refactoring warranted?
| Trigger | Recognize it by | Action | |
|---|---|---|---|
| Rule of three | This is the third copy of the same shape | Extract now — the first or second copy is premature abstraction, a smell of its own | |
| Preparatory | The upcoming feature is hard because of the current shape | Refactor first in its own commit, add the feature second in a separate one | |
| Comprehension | The code needed a second read, or a scratch comment, to understand | Rename/extract while the understanding is fresh | |
| Boy-scout | An unrelated smell is visible while already in the file for other work | Fix only if trivial and local to the touched lines; anything bigger gets flagged, not fixed inline |
Before touching structure: a test suite exists for the path and is green right now (run it, don't trust memory), and the working tree isn't mixing this with in-flight feature work. No coverage for the path → the legacy-code protocol below runs first; restructuring un-pinned behavior is a guess.
Legacy-code protocol — characterization tests first
- Run coverage against the target and read the gaps:
uv run pytest --cov=<pkg> --cov-report=term-missing <path>(Python) ornpx vitest run --coverage(TypeScript). - Write characterization tests against representative inputs, including the odd already-in-production ones, asserting the actual observed output — not the output assumed correct.
assert compute(weird_input) == 47is right if47is genuinely what today's code returns, even if it looks wrong. - Get them green against current behavior. They pin what the code does now, bugs included — not yet a fix.
- Only then refactor, keeping every characterization test green after each step below.
- A real bug surfacing mid-characterization gets flagged (a note, a follow-up issue), never fixed in this pass — unless the task at hand is that fix, which runs as its own red-green-refactor cycle via
principle-programming, before or after the restructuring, never blended into it.
Safety protocol
- Tests green before starting (from Phase 0, or from the characterization protocol).
- One move at a time from
references/catalog.md— never combine two into one step. - Verify proportionally to blast radius: run a focused test after a local move, a broader suite after a cohesive checkpoint, and the final relevant suite when the refactor is complete. A red result reverts the move or cohesive group that caused it rather than debugging forward on a refactor that just broke something.
- Refactor commits stay separate from behavior commits. A planned change with declared breakage defers to the
principle-architectureskill's outcome-oriented-execution reference instead. Detect a commit mixing the two before it lands:
``bash git diff --staged --diff-filter=M -- '*test*' '*spec*' '*_test.*' '*.test.*' | grep -E '^[+-][^+-].*\b(assert|expect)\b' ``
--diff-filter=M exempts brand-new test files (characterization tests, added coverage) by construction — no output means clean. An existing assertion's expected value flipping (a -/+ pair changing assert x == 47 to == 48, or a deletion) is the behavior-change signal — split the commit. A +-only line adding a new assertion beside untouched ones is just added coverage, not proof of a mix.
Scope guard
- Split when the change no longer forms one cohesive, independently reviewable and revertible structural unit. File count is a reviewability signal, not a fixed ceiling.
- Boy-scout boundary, restated: spotting an unrelated smell mid-task is never license to fix it inline — flag it (a follow-up note or a message proposing a follow-up) and keep the current diff scoped to the stated task.
Routing
- Sequencing an addition, refactor, or rewrite → Subtract Before You Add: remove dead code, redundant validators, and stub references first, then build on the simpler base.
- Which smell, which detect command, which threshold →
references/code-smells.md. - Which mechanical move fixes which smell, with worked Python/TypeScript examples →
references/catalog.md. - Shrinking a whole package rather than one function — measure candidate linter rule sets, enable what pays, autofix, then hand-simplify what lint cannot express →
references/lint-first.md. Prefer linter configuration to a bespoke script, and keep the mechanical and judgment commits separate. - A one-shot terminal scan across a whole directory →
scripts/detect-smells.sh <dir>when the stated refactor concerns a smell class the script can detect (a reporter, always exits 0 — review relevant findings; false-positive profile documented per rule). Route it by the skill package's own directory, not the target project's cwd, since the agent's cwd at invocation time is the project being scanned:bash <skill-dir>/scripts/detect-smells.sh <target-dir>. - When symbol safety matters, prefer available language-server definitions, references, rename, and diagnostics; confirm support in the source project, not from another workspace's server status.
- Use an available AST tool when syntax-aware matching or transformation helps; consult an existing code graph only for a concrete dependency or impact question, checking its coverage and freshness.
- Without semantic support, use bounded text search and source inspection, disclose coverage limits, and validate with project checks; text matches are not semantic proof or complete reference coverage. Stop when that fallback cannot establish the move's safety rather than assuming a server, hook, or skill wrapper must be installed.
- File-size ceiling (250 pure LOC) and its escape hatches →
principle-programming; this skill owns function-level size, not file-level. - Turning any rule here into an enforced lint/hook/pre-commit check → use the target repository's existing enforcement tooling.
Mutable tool and LSP facts
For mutable language-server, test, runtime, and tool behavior, consult official primary documentation for the installed version and platform first. Disclose conflicts rather than silently choosing a source. A more-specific repository-local contract or reproducible evidence for the matching version and platform may override general or stale documentation. Unresolved support stays unknown: do not invent a command or semantic operation; stop or use the repository's verified fallback.
Requirements
git— the commit-separation check and churn-based smell detection. Consult Git documentation for the installed version, and safely recordgit --versionbefore relying on mutable Git behavior.grep,awk,find(POSIX) — used directly and insidescripts/detect-smells.sh.- A test runner:
pytest(+pytest-cov) for Python,vitest(--coverage) for TypeScript. Consult each incumbent runner's official documentation for its installed version and run its documented version probe. - When language-server support is used, consult the incumbent server's official documentation for its installed version and run its documented version probe before relying on semantic operations.
- Optional:
vulture(Python) /ts-prune(TypeScript) for the Dead Code entry inreferences/code-smells.md. - The repository's incumbent linter when
references/lint-first.mdapplies. Consult its official documentation for the installed version before enabling a rule set, run its documented version probe, and support only rule behavior verified for that version; a linter release that changes a rule's fix behavior re-triggers the re-evaluation below. - When Git, the incumbent language server, or the incumbent test runner changes version or capability, review the applicable official documentation, rerun affected detection and characterization evals, update this recipe if needed, bump the package version, and record the reason in the commit message before trusting prior results.
Common rationalizations
| Rationalization | Reality | |
|---|---|---|
| "Already in here, might as well fix everything I see." | Drive-by scope creep — flag anything beyond trivial and local instead. | |
| "It's just a rename, I'll bundle it with the fix." | A rename is a refactor commit; a fix is a behavior commit — bundling means reverting one reverts both. | |
| "No time for characterization tests, I already know what it does." | That certainty is exactly the guess this protocol replaces with a pinned assertion. | |
| "Two duplicates is basically three, I'll extract now." | Rule of three means three — the second occurrence is too early to know the right shape. | |
| "Tests still pass, so the commit is one change." | Passing tests don't prove that; check whether any assertion's expected value moved before assuming so. | |
| "The linter's autofix is mechanical, so it needs no review." | Autofixes have flipped tests by stripping suppression reasons, joining literals a scan searched for, and reordering a byte-pinned export list — see the failure classes in references/lint-first.md. Read the diff and run the suite. | |
| "A quick script that greps for this is faster than configuring the linter." | The script is a private tool CI must be taught to call and the next person must learn; configuration is already wired in. |
Verification
- [ ] Phase 0 passed: trigger identified, tests confirmed green (or the characterization protocol completed first).
- [ ] Verification matched blast radius: focused test after each local move, broader suite at cohesive checkpoints, and final relevant suite at completion.
- [ ] No commit mixes a structural change with a changed test assertion (checked with the detection command above); a planned change with declared breakage follows the
principle-architectureskill's outcome-oriented-execution reference instead. - [ ] Any applicable smell fixed cites its
references/code-smells.mdentry and the detect command's result. - [ ] Scope stayed within the stated task; anything spotted-but-out-of-scope was flagged, not fixed inline.
- [ ] For a lint-first pass: candidate rule sets were counted before being enabled, autofixes landed in their own commit ahead of the hand edits, and every reverted autofix is recorded as a scoped ignore with its reason.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/refactor/SKILL.md
Popularity
- 7-day trend score
- 0
Not refreshed yet.
Extension points
hookPre/post lifecycle hooks
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/goberomsu/craft-skills/refactor)