Guides

Refactoring a large codebase with Claude Code

An agent that can rewrite a thousand files in a minute needs a way to prove it didn't break anything in file 400. Characterization tests give you that proof, small steps keep each change reviewable, and worktrees let you run more than one refactor at a time without the sessions colliding.

1. Pin current behavior with characterization tests

A characterization test doesn't check that the code is correct, only that it behaves the same before and after the refactor. Where the module has no tests yet, ask Claude to write these first, against the existing behavior, not the behavior you wish it had:

Before we refactor <module>, write characterization tests that capture its
current behavior, including quirks and edge cases you're not sure are
intentional. Feed it representative inputs and assert on the actual output.
Do not "fix" anything you find. Run them and show me they pass against
the current code.

Commit these tests before any refactor commit. If they fail after your changes, the refactor changed behavior, whether or not that behavior was a bug.

2. Break the refactor into small, verifiable steps

A single giant diff across a large codebase is nearly impossible to review. Ask for a step-by-step plan first, then have Claude execute and verify one step at a time:

Plan this refactor as a sequence of small, independently mergeable steps.
Each step should compile, pass tests, and leave the code in a working
state. After each step: run the full test suite, show me a summary of
what changed, and stop for review before starting the next step.

This also keeps each commit small enough that git bisect can actually find the step that introduced a regression. See test-driven development with Claude Code for the failing-test-first loop this pairs well with, and a safe git workflow for commit and review habits.

3. Isolate each refactor in its own worktree

Running two refactors in the same checkout means one session's half-finished edit corrupts the other's test run. Claude Code can create an isolated checkout on its own branch directly:

claude --worktree refactor-payments   # terminal 1
claude --worktree refactor-auth       # terminal 2, separate checkout and branch

The repository needs at least one commit for this to work — in an empty repo it fails with Failed to resolve base branch "HEAD". You can also create worktrees yourself with plain git:

git worktree add ../myapp-refactor-payments -b refactor-payments
git worktree list
git worktree remove ../myapp-refactor-payments   # once merged

Each worktree needs its own dependency install, since node_modules or a virtualenv isn't shared. If you're running several of these in parallel, a background-agent view that monitors all of them from one screen is easier than switching between terminals.

4. Use plan mode before large structural changes

For a change that touches many files, get the approach reviewed before anything is written to disk. Plan mode has Claude read the code and propose a plan without editing:

claude --permission-mode plan

Or press Shift+Tab mid-session until the status bar shows ⏸ plan mode on. Read the proposed plan for the parts that are hard to undo, like renaming a widely-imported module or changing a public interface, before approving it.

5. Keep context small across a long refactor

A refactor that spans hundreds of files will blow through your context window if every file read stays in the main conversation. A few habits keep it manageable:

6. Protect the tests while the refactor is in progress

Under pressure to get a large diff green, an agent may loosen an assertion in a characterization test instead of fixing the code. Say explicitly that test files are off-limits during the refactor step, and check git diff -- '*test*' stays empty until you've approved a deliberate test change. For a stricter guardrail, a PreToolUse hook can block edits to test files outright; build one without writing the script by hand with the free hook builder.

7. When a step goes wrong

SituationWhat to do
Claude is heading the wrong direction mid-stepPress Escape to stop immediately, before it edits more files
The last step's edits should be undone/rewind or double-tap Escape to restore conversation and code to a checkpoint
A committed step turns out to be wronggit revert <sha> rather than editing history on a shared branch
A worktree's branch is abandonedgit worktree remove <path>, then delete the branch

Checklist before merging

Skip the setup: get the tested versions

Keelwork bundles 10 workflow skills, 5 tested safety hooks (including a full guard-bash and a secret scanner), 3 subagents and 5 CLAUDE.md templates, with a one-command installer that safely merges into your settings.

Get Keelwork — $24 →