Refactor the code in $ARGUMENTS to improve its internal structure without changing any observable behaviour.
If $ARGUMENTS is empty, ask which file, function, or selection to refactor and stop. Do not guess.
Establish a safety net first
- Detect the stack and test runner from the repo (package.json, pyproject.toml, go.mod, Makefile, CI config). Use the project's existing command to run tests, lint, and typecheck.
- Run the relevant tests now. If they are red, stop and report — never refactor on a broken baseline.
- If the target code has no tests covering it, write characterization tests that pin down the current behaviour (including current edge cases and quirks) before touching anything. Run them; they must pass against the code as-is.
- Skim the target to map its public surface: exported signatures, return types, thrown errors, side effects, logged output. This contract must not change.
Refactor in small steps
Apply one transformation at a time. After each, re-run tests (and typecheck) and only proceed when green. On green, checkpoint immediately — commit the step (or git stash/git add it) with a short message like "refactor: extract X" — so any later step that fails can be rolled back to the last known-good state cheaply. Prefer these moves, in rough priority:
- Rename variables, functions, and types to state intent; delete misleading or stale names.
- Replace nested conditionals and arrow code with guard clauses / early returns.
- Extract a well-named function or variable for any block that needs a what-comment explaining its mechanics — the name replaces the comment. Leave why-comments (rationale, caveats, links) and doc-comments in place; those explain things a name cannot and are not a trigger to extract.
- Split functions doing multiple things; each should operate at a single level of abstraction.
- De-duplicate only on the third occurrence (rule of three); unify genuinely identical logic, not superficial lookalikes.
- Delete dead code, unreachable branches, unused params, commented-out blocks, and redundant comments.
- Replace magic numbers/strings with named constants.
- Follow the file's existing conventions (naming, error handling, imports, formatting) — match the surrounding code, do not impose your own style.
Hard rules
- Never change behaviour, public signatures, serialization formats, or error semantics. If you find a bug, leave it, and note it separately — do not silently "fix" it mid-refactor.
- Never mix refactoring with feature changes or dependency upgrades in the same pass.
- Do not add abstraction for a single caller or hypothetical future needs; the diff must be justified by the code that exists today.
- Keep the diff small and reviewable. If the target is large, refactor the highest-value section and stop rather than rewriting wholesale.
- Run the formatter/linter before finishing.
Report
End with: the tests/typecheck command you ran and its result, a bulleted list of each transformation applied and why, any behaviour-preserving assumptions the characterization tests locked in, and any bugs or smells you deliberately left untouched.