How to Not Fail When Delegating Refactoring to AI — Dependency Analysis, Scope Limiting, and Incremental Commits with Codex CLI
Refactoring is always daunting. Especially when you're thinking about swapping express for fastify, or ripping out all of lodash, from a codebase that's been accumulating for three-plus years — it's hard to know where to even start. At first I thought, "just open the files and change them one by one," but after changing two or three, something would quietly blow up somewhere. Router middleware execution order that static analysis tools can't catch, request context wrapped in custom decorators, mocking helpers used only in tests — these come back as red lights in CI long after the fact.
Once, while spending three days changing around twenty modules, I discovered just before the final deployment that a logging middleware was stuck in infinite recursion in production. Because all the changes were bundled into a single commit, it took half a day just to pinpoint which change was the culprit. What I learned then was: "the danger in refactoring doesn't come from the changes themselves, but from blurry boundaries around those changes."
When you hand refactoring off to an AI, those boundaries get even blurrier. It's natural to worry that letting it change multiple files at once could cause an even bigger disaster. But combining these three things — dependency graph analysis → AGENTS.md scope declaration → staged commits — makes the boundaries clear. You can guide the AI declaratively from the start about how far it's allowed to reach, and ensure it only commits after passing type checks and tests at each stage.
This article walks through why this combination is effective, how to set it up, and where you need to be careful.
Why You Shouldn't Hand It All Off at Once
First, let's pin down what kinds of failures actually happen. When you direct a framework migration with a single prompt, this is typically what unfolds:
- Missing hidden references: It catches middleware that directly accesses
req.body, but misses code that reaches it indirectly through a custom helper your team built. A limitation of static analysis. - Abandoned test fixtures: Production code gets changed, but test helpers still use the old API — CI passes, yet actual behavior differs.
- Commit bundling: Pushing 30 files in a single commit makes review impossible and eliminates any rollback unit.
- Scope creep: Unrelated files get their style changed "while we're at it," inflating the diff.
These four failure types are intertwined. Blurry scope leads to bundled commits, and bundled commits make it impossible to find where a reference went missing. So when delegating refactoring, the order of operations is to decide "how far to change" before "what to change."
What the Three Axes Do
Codex CLI is an open-source terminal coding agent that OpenAI released in April 2025. You give it natural-language instructions in the terminal, and it reads actual code, modifies it, and runs commands. In the context of multi-file refactoring, there are three axes to consider.
Dependency Graph Analysis — List the Impact Scope First
The scariest thing in refactoring is thinking "I just need to change this one file," making the change, and then something completely unrelated blows up. If you instruct Codex CLI to trace back the import/require references of the files you want to modify, you can make it list all affected modules first. If you need the latest migration documentation, you can request it with web search enabled — but for the specific flags and usage, it's safer to check codex --help for the version of Codex CLI you have installed locally. Since the CLI interface changes with each release, rather than copying from docs verbatim, it's better to verify support in your own environment first.
AGENTS.md — Declare the World the Agent Can See
AGENTS.md is a Markdown file that is automatically loaded from the hierarchy between the project root and the current working directory. It declares the paths the agent may access and modify, forbidden commands, and test gates to guide the scope of work.
The key caveat is that AGENTS.md is guidance. It's not a hard constraint — it's closer to a convention the model should follow. If the user prompt explicitly says "just change everything," it can be ignored. That's why sensitive constraints must be paired with OS sandbox policies, which we'll cover later.
Staged Commits — Leave Clear Rollback Points
Cut a large refactoring into logical units, and only commit after type checks, linting, and tests pass at each stage. If something breaks in the middle, having a rule to stop there means you can pinpoint "where did it break?" just by looking at git log.
Start with the AGENTS.md Scope Declaration
If you instruct "change express to fastify across the entire codebase" without an AGENTS.md, it's hard to predict how far the agent will reach. The scope declaration comes first.
Basic AGENTS.md Structure
# Refactoring Scope Guidance
## Modifiable Paths
- src/routes/**
- src/middleware/**
- src/controllers/**
## Paths to Never Touch
- src/config/database.ts
- migrations/
- .env*
## Forbidden Commands
- rm -rf
- DROP TABLE
- git push --force
## Test Gates
The following must pass before each commit:
1. npx tsc --noEmit
2. npx eslint src/ --max-warnings 0
3. npm test -- --passWithNoTests
## Recommended Commit Message Format
- One commit per logical unit
- Format: refactor(scope): summary of changeNote that "Recommended Commit Message Format" is not a convention Codex automatically enforces — it's simply an instruction passed to the model. There's no guarantee the model will always follow this format, so pairing it with a commit hook (e.g., commitlint) is more reliable.
Limits on AGENTS.md Effectiveness
- Guidance-level rules: They can be bypassed by a prompt. Constraints that absolutely must not be broken — like protecting production DB schema files — need to be enforced at the OS sandbox level (macOS
sandbox-exec, Linuxbwrap, Codex's filesystem policy settings, etc.) to actually block filesystem writes. Check the docs andcodex --helpfor your version to see which sandbox options are exposed. - Document length: If AGENTS.md becomes excessively long, some rules may fade away in long sessions. The exact threshold varies by model and version, so rather than citing a specific number, the practical principle is: "keep core rules short, split supplementary rules into AGENTS.md files in subdirectories."
- Path hierarchy: How the parent directory's AGENTS.md and a child AGENTS.md are merged varies by CLI version. You can verify which rules were actually merged and applied either by checking the instructions Codex loaded at session start (if the current version provides that command), or by directly asking in the prompt: "summarize the AGENTS.md content currently loaded."
Real Workflow: Express → Fastify Migration
Theory only gets you so far, so let's walk through the flow. The commands below are conceptual examples; the actual flag names and shapes need to be verified in your version of Codex CLI.
Step 1: Impact Analysis (No Modifications)
First, instruct it to identify the impact scope only, without making any changes. Whether Codex CLI provides a separate "plan" slash command varies by version, so here we substitute by explicitly stating "no modifications" in the prompt itself.
codex "Do not modify any files during this session.
Find all express imports across the entire codebase,
reference the latest Fastify migration guide,
and list all affected files and their expected change scope, organized by layer."Sample output (conceptual):
Affected Files:
- src/app.ts (express() → fastify() instance change)
- src/routes/users.ts (remove Router(), change route registration pattern)
- src/routes/products.ts (same)
- src/middleware/auth.ts (change req.body access pattern)
- src/middleware/errorHandler.ts (error handler signature change)
No Modification Needed:
- src/config/database.ts (no express dependency)
- src/utils/logger.ts (no express dependency)Step 2: Prepare an Isolated Environment with git worktree
To avoid contaminating the main branch, git worktree is useful. It provides an independent filesystem per branch, so if the refactoring fails, the original working environment is unaffected.
git worktree add ../project-fastify-migration refactor/express-to-fastify
cd ../project-fastify-migrationStep 3: Place AGENTS.md and Execute Layer by Layer
# Round 1: Routes layer
codex "Convert the express Router in files under src/routes/ to Fastify routing.
After converting, run npx tsc --noEmit and npm test,
and if they pass, commit with: refactor(routes): express Router to Fastify route plugins"
# Round 2: Middleware layer
codex "Convert the express middleware in files under src/middleware/ to Fastify hooks.
After converting, verify type checks and tests pass, then commit."
# Round 3: App entry point
codex "Replace the express() instance in src/app.ts with fastify(),
and change the plugin registration pattern to Fastify style."Monorepo Parallel Processing: Start by Splitting Terminal Tabs
In a monorepo with more than ten packages, processing them one by one is exhausting. The simplest parallelization is to create a worktree per package and split terminal tabs, running a Codex session in each.
git worktree add ../refactor-pkg-a refactor/pkg-a
git worktree add ../refactor-pkg-b refactor/pkg-b
# Tab 1
cd ../refactor-pkg-a && codex "Replace the lodash dependency in packages/pkg-a with native JS..."
# Tab 2
cd ../refactor-pkg-b && codex "Replace the lodash dependency in packages/pkg-b with native JS..."This approach is closer to human-directed parallel execution than "sub-agent orchestration." On the upside, each package's PR stays as a small diff, and only failing packages need to be individually reverted. Programmatically coordinating multiple Codex instances using an Agents SDK is also possible, but that integration is tightly coupled to the SDK version and API, which is beyond the scope of this article.
Setting Test Gates After Refactoring
This isn't TDD per se — rather than writing failing tests first, it's closer to a safety net that enforces that existing tests still pass after refactoring. Define gates in AGENTS.md and you can prompt verification to run automatically just before each commit.
#!/usr/bin/env bash
set -euo pipefail
npx tsc --noEmit
npx eslint src/ --max-warnings 0
npm test
STAGED=$(git diff --cached --name-only -- '*.ts' || true)
if [ -n "$STAGED" ]; then
if git diff --cached -- '*.ts' | grep -Eq 'TODO|FIXME|HACK'; then
echo "Incomplete marker found: aborting commit"
exit 1
fi
fiThe original draft wrote this as a one-liner grep && echo && exit 1 chain, but when grep returns exit 1 because there's no match, the && chain breaks and the script silently succeeds. The same happens when no files are staged. Extracting it into a script and adding the -E flag and file list check makes it behave as intended.
Trade-offs
The diagram captures "under what conditions does a problem arise," and the table captures "so how do you respond."
| Item | Mitigation |
|---|---|
| AGENTS.md is only guidance | Pair sensitive constraints with OS sandbox and file permissions |
| AGENTS.md bloat | Keep only core rules; split supplementary rules into subdirectory AGENTS.md files |
| Dynamic imports cannot be traced | Manually grep require(variable) and reflection-based references, or use MCP-style graph tools |
| Sandbox network blocked | Separate tests with external API calls into a dedicated stage |
| Prompt mistakes | Always start the first step with a no-modification prompt for scope analysis only |
| Commit message convention not followed | Enforce format with local hooks like commitlint |
Tools to Supplement Static Analysis
If Codex's built-in static analysis isn't enough, MCP (Model Context Protocol) integrated tools can help.
- Codegraph: An open-source project that builds a dependency map of your codebase locally.
- code-review-graph: An MCP-based code intelligence graph.
Because these tools maintain a graph of "if I change this function, how far does the impact reach," you don't need to re-scan the entire codebase at every session. That said, check each linked project's repository directly to verify its specific features and maturity level.
Closing
The reason handing multi-file refactoring to an AI feels scary is the uncertainty of "I don't know how far it'll reach." To reduce that uncertainty, you need three things: declare scope with AGENTS.md, make the first step scope-analysis-only with no modifications, then isolate with git worktree and only commit when staged gates pass. That way, even if the AI makes a mistake, the blast radius is clearly bounded and rollback points remain in the git log.
Dynamic imports and reflection-based references still need human review. It's safer to start by acknowledging that there are areas static analysis can't catch.
The lowest-friction entry point you can take right now is this: throw a prompt at Codex asking it to list the impact scope on your current branch without making any modifications. Since no files change, you can observe the tool's behavior risk-free — and the file list it produces becomes the first draft of the "Modifiable Paths" section in your AGENTS.md.