teachyou.ai academy
← All posts
CodexrefactoringAI coding agentsdeveloper productivitycode migration

Large-Scale Refactoring with OpenAI Codex

Pramod Dutta · Jul 5, 2026 · 12 min read

Codex refactoring is the practice of using OpenAI's Codex CLI as an autonomous coding agent to plan, execute, and verify sweeping code changes across a large repository, things like renaming a core API, migrating a framework version, or splitting a monolith into modules, without a human hand-editing every file. Done well, it turns a multi-week refactor into a supervised run that finishes in hours. Done carelessly, it turns into a giant unreviewable diff that nobody trusts. This guide walks through a repeatable process: scoping the change, giving Codex a plan it can execute in slices, verifying each slice with tests, and merging in a way your team can actually review.

Large refactors fail for predictable reasons: the blast radius is underestimated, the agent runs unsupervised for too long, or the diff lands as one enormous commit with no checkpoint to roll back to. The fixes are also predictable: scope the refactor into independently verifiable batches, keep a test suite (or write one first) that catches regressions batch by batch, and use Codex's plan-then-execute workflow so you approve the strategy before thousands of lines change. The rest of this article shows exactly how to set that up.

Why large-scale refactors are a good fit for Codex

Refactoring is mechanical in a way that green-field feature work isn't. Renaming UserRepository to UserStore across 400 files, updating every call site of a deprecated function, or migrating from a callback-based API to async/await all follow a pattern: find every instance, apply a consistent transformation, verify nothing broke. That's exactly the kind of task an agent with a big context window, shell access, and a test runner in the loop is good at, and it's tedious enough that humans introduce mistakes doing it by hand (missed call sites, inconsistent renames, forgotten imports).

The risk profile is different from a normal Codex session, though. A feature branch that goes wrong touches one area of the app. A bad refactor touches everywhere, including files you didn't think were related. That's why the workflow below leans hard on planning, batching, and verification rather than "point Codex at the repo and let it run."

Step 1: Scope the refactor before writing a single prompt

Before opening Codex, write down three things in a plain text file (call it REFACTOR-PLAN.md and keep it in the repo during the work):

  • The exact transformation. Not "clean up the auth module" but "replace every direct call to db.query() with the new Repository interface, preserving existing error handling behavior."
  • The blast radius. Run a search first to get a real count: grep -rl "db.query(" src | wc -l. If it's 12 files, this is a single Codex session. If it's 600, you need batching (see Step 3).
  • The success criteria. What does "done" mean? Usually: the existing test suite passes, a new lint rule catches any remaining old-pattern usage, and the app boots and smoke-tests clean.

This scoping step matters more for codex refactoring than for feature work because an agent given a vague instruction ("modernize this codebase") will make judgment calls you didn't sign off on, at scale, across hundreds of files. A precise transformation description removes that ambiguity.

Step 2: Establish a safety net before Codex touches anything

Never run a large refactor against a codebase with weak test coverage. If the area you're refactoring doesn't have tests, write characterization tests first, tests that lock in current behavior, not tests that assert the "right" behavior. This is a one-time investment that pays for itself the moment an agent makes a plausible-looking change that quietly breaks an edge case.

A minimal safety net for a refactor:

# 1. Confirm the suite is green before you start
npm test

# 2. Add a coverage check scoped to the files you're about to touch
npx nyc --include 'src/repositories/**' npm test

# 3. Commit the baseline so you have a clean diff point
git add -A && git commit -m "chore: baseline before repository refactor"

If coverage on the target files is low, spend an hour writing tests for the current behavior before you start the refactor proper. It's tempting to skip this when you're excited to see Codex rip through hundreds of files, but this is the single biggest predictor of whether a large refactor lands cleanly or turns into a multi-day cleanup.

Step 3: Break the refactor into independently mergeable batches

This is the core discipline of codex refactoring at scale. Instead of one Codex session touching 600 files, split the work into batches of 20 to 50 files each, grouped by module or directory boundary, and run Codex once per batch with its own review and commit.

A practical batching approach:

# List every file that needs the transformation
grep -rl "db.query(" src > /tmp/refactor-targets.txt
wc -l /tmp/refactor-targets.txt

# Split into batches aligned with directory structure, not arbitrary chunks
grep -rl "db.query(" src/auth > /tmp/batch-auth.txt
grep -rl "db.query(" src/billing > /tmp/batch-billing.txt
grep -rl "db.query(" src/reporting > /tmp/batch-reporting.txt

Why directory-aligned batches beat arbitrary file-count chunks: each batch corresponds to a module a reviewer already understands, so the resulting pull request is reviewable by someone who owns that area. It also means a bad batch can be reverted without touching the batches that already merged cleanly.

Run one Codex session per batch:

codex "Read REFACTOR-PLAN.md for the exact transformation rules. \
Apply the db.query() to Repository migration only to files listed \
in /tmp/batch-auth.txt. Do not touch files outside this list. \
After each file, run the relevant test file and fix failures before \
moving to the next file. Stop and summarize when the batch is complete."

Constraining the agent to an explicit file list is the single most useful guardrail for this kind of work. It stops Codex from "helpfully" wandering into adjacent files that look related but weren't part of the plan, which is the most common way a scoped refactor turns into a sprawling diff.

Step 4: Use plan mode before execution mode

Codex CLI supports separating planning from execution: ask it to produce a written plan for the batch, review that plan yourself, and only then approve execution. For a refactor this large, always use this two-step flow rather than letting the agent plan and act in the same breath.

codex --plan "Propose a step-by-step plan for migrating src/auth to the \
new Repository interface as defined in REFACTOR-PLAN.md. List every file \
you intend to change and the specific edit for each. Do not write code yet."

Read the plan. Look specifically for:

  • Files the agent proposes touching that aren't in your target list (a sign the transformation description was ambiguous).
  • Edits that change behavior, not just structure (a sign the agent is "improving" code beyond the scope you defined).
  • Missing files, ones you know reference the old pattern but the agent didn't find, usually because of an indirect import or a re-export.

Once the plan looks right, approve execution:

codex --approve-plan "Execute the plan exactly as written. Run tests after \
every file. If a test fails and the fix isn't obvious from the plan, stop \
and ask rather than guessing."

That last instruction, "stop and ask rather than guessing", is worth including in every large-refactor prompt. Agents left to their own devices will often patch around a failing test in a way that technically passes but doesn't match your intended transformation. Explicitly telling Codex to halt on ambiguity turns a silent wrong guess into a visible checkpoint you control.

Step 5: Verify every batch the same way, every time

Consistency here is what makes a multi-batch refactor trustworthy. Build a single verification script and run it identically after every batch, not just "run tests" loosely but a fixed sequence:

#!/usr/bin/env bash
set -e

echo "== Running full test suite =="
npm test

echo "== Type checking =="
npm run typecheck

echo "== Linting for leftover old-pattern usage =="
if grep -rl "db.query(" src; then
  echo "FAIL: old pattern still present"
  exit 1
fi

echo "== Smoke test: app boots =="
timeout 30 npm run start:smoke

echo "All checks passed for this batch"

Save this as verify-batch.sh, run it after each Codex session, and only commit the batch if it exits clean. This turns "does the refactor work" from a subjective judgment call into a scripted gate, which matters because you're going to repeat this ten or twenty times across a large codebase and you need the bar to stay identical on batch nineteen as it was on batch one.

Step 6: Commit and review per batch, not per refactor

Resist the urge to squash the whole refactor into one commit at the end. Commit each verified batch separately, with a message that names the batch and the file count:

git add src/auth
git commit -m "refactor(auth): migrate db.query() calls to Repository (14 files)"

This gives you three things a single giant commit can't: a git bisect-friendly history if something breaks in production three weeks later, a review unit small enough that a teammate will actually read it closely, and a natural rollback point, git revert one batch without touching the eighteen that were fine.

If your team uses pull requests, open one PR per batch rather than one PR for the entire refactor. A 40-file PR scoped to src/auth gets a real review. A 600-file PR touching the whole codebase gets an approve-without-reading rubber stamp, which defeats the point of having tests and plan review in the first place.

Step 7: Handle the long tail of edge cases

Every large refactor has a long tail: files that don't match the pattern the agent expected, generated code that shouldn't be touched, or call sites inside test fixtures that need a different transformation than production code. Don't let Codex guess its way through these. Maintain an explicit exclusion list and feed it into every batch prompt:

codex "Apply the migration from REFACTOR-PLAN.md to files in \
/tmp/batch-reporting.txt. Skip any file listed in REFACTOR-EXCLUDE.txt \
even if it matches the pattern, those are handled manually. If you find \
a file that doesn't fit the standard transformation (for example, a \
query built dynamically from a string template), stop and describe the \
case instead of improvising a fix."

Once you've collected a handful of these edge cases across a few batches, they usually cluster into two or three sub-patterns. Write a short addendum to REFACTOR-PLAN.md describing how to handle each sub-pattern, then run one final Codex session against the accumulated exclusion list with the addendum as context. This keeps the long tail from turning into dozens of one-off manual edits.

Step 8: Run a final consistency pass

After all batches are merged, run one more Codex session whose only job is auditing, not editing:

codex "Search the entire src/ directory for any remaining usage of \
db.query() that should have been migrated per REFACTOR-PLAN.md. Also \
check for inconsistencies between batches, for example, two files that \
solved the same edge case differently. Report findings only, do not \
make changes."

This catches drift that naturally creeps in across a multi-day, multi-batch refactor, where the agent (or a human reviewer) made slightly different judgment calls in batch three versus batch fifteen. Fix any drift in one small final commit, and only then delete the temporary batch files and the refactor plan document, or move the plan into your team's docs if the pattern is one you'll repeat.

A checklist for your next large refactor

  • Write the exact transformation and success criteria in a plan file before touching Codex.
  • Confirm test coverage on the target area; write characterization tests first if it's thin.
  • Split the change into directory-aligned batches of roughly 20 to 50 files.
  • Use plan mode to review Codex's intended edits before approving execution.
  • Constrain each session to an explicit file list, and tell the agent to stop on ambiguity rather than guess.
  • Run an identical, scripted verification gate after every batch.
  • Commit and (if applicable) open a pull request per batch, never one commit for the whole refactor.
  • Maintain an exclusion list for edge cases and resolve them separately from the bulk pattern.
  • Run a final read-only consistency pass across the whole codebase before closing out the work.

FAQ

Is codex refactoring safe for production codebases? It's safe when treated as a supervised process rather than a one-shot command. The combination of a written plan reviewed before execution, batches small enough to review individually, and a scripted test gate after every batch is what makes it safe, not the agent's capability alone. Skipping any of those steps is where large refactors go wrong, with or without an AI agent involved.

How large should each batch be? Size batches by what a human reviewer can meaningfully check in one sitting, typically 20 to 50 files, not by an arbitrary token or time budget. Align batch boundaries with existing module or directory structure so each batch maps to something a code owner already understands, rather than splitting alphabetically or by file count alone.

What if Codex makes an incorrect change partway through a batch? Because each batch is its own commit gated by a verification script, the fix is a targeted revert of that one batch, not a rollback of the entire refactor. This is the main reason to avoid squashing everything into a single commit at the end: it preserves fine-grained rollback points exactly where you're most likely to need one.

Can Codex handle refactors that span multiple languages or services? Yes, but treat each language or service as its own refactor plan and batch set, since the transformation rules, test tooling, and verification scripts differ. Run them as separate, parallel efforts rather than one Codex session juggling a Python service and a TypeScript frontend at once, the context switching increases the chance of an inconsistent edit slipping through.

Do I still need to write tests if I'm using an agent to refactor? Yes, arguably more than usual. The tests are what let you verify each batch objectively instead of trusting that the diff "looks right" on read-through. If the target code lacks coverage, writing characterization tests before the refactor starts is the highest-leverage hour you'll spend on the whole project.

How is this different from just asking Codex to "refactor the whole app"? An unscoped instruction gives the agent latitude to make judgment calls across the entire codebase in one pass, which is exactly the failure mode this workflow avoids. Explicit scoping, batching, plan review, and per-batch verification turn an open-ended request into a series of small, checkable changes, the actual work Codex does might look similar, but the process around it is what determines whether you can trust and review the result.