Multi-File Edits With a CLI Agent
A CLI agent multi-file edit that goes half-right is worse than none — you get a codebase inconsistently broken. Here's the all-or-nothing workflow: enumerate the set first, apply scope-aware, verify the whole change.
claude > rename the UserCard component to AccountCard everywhere in the codebase
Picture this: you're a frontend engineer renaming a core component — UserCard becomes AccountCard — and it's imported in thirty-two files across the codebase. This is the kind of change that's tedious by hand and perfect for an agent, so you ask it to do the rename everywhere. Ten minutes later the build is broken in a way it wasn't before: the agent renamed the component in twenty-eight files, missed three, and in one file it renamed a different UserCard that happened to be an unrelated local variable. A CLI agent multi-file edit that goes half-right is often worse than no edit at all, because now you have a codebase that's inconsistently broken and a diff too tangled to trust.
Let's tear down the naive whole-repo rename and rebuild it into a multi-file edit workflow that lands all-or-nothing, correctly.
Before: The Fire-and-Forget Multi-File Edit
The weak approach is to state the change and let the agent loose across the repo with no structure.
claude
> rename the UserCard component to AccountCard everywhere ,[object Object], the codebaseWhat this does: Hands the agent a repo-wide edit with no plan, no verification between files, and no atomicity. The agent works file by file, and if it misjudges scope — misses a file, catches a false match, loses track partway — you find out only after it's touched dozens of files. There's no checkpoint where a mistake gets caught early.
The problem is that a CLI agent multi-file edit isn't really many independent edits — it's one logically atomic change that happens to span many files. The rename is only correct if all the call sites move together. Twenty-eight of thirty-two isn't 88% done; it's broken, because the four stragglers reference a component that no longer exists.
⚠️ Common mistake: Treating a multi-file change as a loose batch of edits rather than one atomic operation. A rename, an API signature change, a moved interface — these are all-or-nothing. Partial application doesn't leave you partly finished; it leaves you broken in new places, with a half-applied change that's harder to reason about than the original state.
Why It Fails: Coordination, Not Capability
The fire-and-forget approach fails on coordination, not on the agent's ability to edit any single file. Each individual edit might be perfect. The failure is in the set: did the agent find every site, edit only the right ones, and leave the codebase consistent? Those are questions about the whole operation, and the naive approach never checks them as a whole.
Two specific failure modes come from missing coordination. The first is incomplete coverage — the agent misses call sites it didn't find, often in dynamically-referenced code, string templates, or config the repo-map didn't surface. The second is false matches — the agent edits things that share a name but aren't the target, like that unrelated local UserCard. Both are coordination failures: the agent needed to reason about the complete, exact set of edit sites, and instead it improvised file by file.
The fix is to make the plan explicit before any editing happens, and to verify the whole set landed correctly after.
After: Plan the Set, Edit, Then Verify as a Whole
The strong workflow has three phases the naive one collapses into one.
Phase one: enumerate the exact edit set first, read-only. Make the agent find and list every site before it changes anything, so you can confirm the scope is right while it's still free to fix.
claude --permission-mode plan
> find every reference to the UserCard component — imports, usages, types, tests, \
stories. list them with file and line. don,[object Object]What this does: Produces the complete map of what would change, without changing anything. You review the list — is anything missing, is anything a false match — and correct the scope before a single edit lands. The coordination decision is made deliberately, up front, instead of improvised mid-edit.
Phase two: execute the edit against the confirmed set, ideally with a mechanical tool where one exists. For a pure rename, the agent invoking a language-server rename or a scoped sed is more reliable than freehand editing, because those tools understand scope in a way text matching doesn't.
[object Object],
claude
> using the confirmed list, apply the rename. ,[object Object], the component identifier use \
the language server,[object Object],t catch unrelated same-named symbols.What this does: Applies the change through a scope-aware mechanism rather than blind text replacement, so an unrelated local UserCard isn't caught in the net. The agent orchestrates the tool that understands the difference between the component and a coincidentally-named variable.
Phase three: verify the whole change landed consistently — compile, type-check, and test as the all-or-nothing gate.
tsc --noEmit && npm ,[object Object], ,[object Object],What this does: Confirms the codebase is consistent after the multi-file edit. A type error here means a missed or broken site — exactly the incomplete-coverage failure — caught immediately as one signal over the whole change, not discovered later in production.
⚡ Pro tip: Make the compiler your coverage check for renames. In a typed language, a clean type-check after a rename is strong evidence you caught every site, because a missed reference to the old name won't compile. Run the type-check as the gate, and it turns "did I get them all?" from a hope into a verified fact.
The Ordering Problem in Multi-File Edits
There's a subtlety the plan-edit-verify workflow has to handle: some multi-file changes have a required order, and getting the order wrong leaves the codebase un-buildable at intermediate steps even when the final state is correct. Change a function's signature before its callers and every caller is momentarily broken; change the callers first and they reference a signature that doesn't exist yet. Either way there's a window where nothing compiles.
For a change you apply and commit as one unit, the intermediate broken state doesn't matter — you never commit it. But it matters a lot if you're editing in batches with verification between them, because the verification will fail on the intermediate state and you can't tell a real problem from an expected-transient one.
Dependency order for a signature change:
1. Change the definition AND all callers together (one atomic edit), OR
2. Add the new signature alongside the old (overload), migrate callers, remove oldWhat this does: Lays out the two safe strategies for an ordered change — do it all at once so there's no broken intermediate, or use a temporary parallel version so every step compiles. Both avoid the trap of a verification failing on a state that was only ever meant to be transient.
The parallel-version approach should feel familiar — it's the same expand/contract idea that keeps database migrations safe, applied to code. When a change is too large to land atomically, making it backward-compatible at each step keeps every intermediate state valid.
⚠️ Common mistake: Editing files in an order that leaves the build broken between steps, then not knowing whether a failing check is a real error or just the expected intermediate state. If you must edit incrementally, use the parallel-version approach so every step compiles — then a failure always means a real problem.
⚡ Pro tip: For ordered changes, tell the agent the strategy explicitly: "make this change backward-compatible at each step so the build stays green throughout." The agent knows the overload-then-migrate pattern but defaults to the direct change unless you ask for the safe sequencing. Naming the strategy is what gets you green intermediate states.
⚡ Pro tip: When a change genuinely must be atomic, do it as one edit and one commit — don't split it. Some changes have no safe intermediate state, and forcing them into batches just manufactures broken windows. Recognizing which changes are atomic-only is part of planning the edit set.
Breaking Down Each Element
The plan phase converts an improvised operation into a reviewed one. By enumerating the edit set before touching anything, you catch scope errors while they're free to fix. This is the single most important change over fire-and-forget.
The scope-aware execution prevents false matches. A rename that goes through a language server or a carefully-scoped pattern understands what's actually the target, so it doesn't catch same-named-but-unrelated symbols.
The whole-change verification enforces atomicity. Compile and test after the full edit checks the property that actually matters — is the codebase consistent — rather than whether any individual file looks right.
The review-as-one-unit step keeps you honest. You review the multi-file diff as a single logical change, confirming it's complete and contains nothing extra, before it becomes a commit.
⚡ Pro tip: For large multi-file edits, have the agent work in a sequence of verifiable batches rather than one giant sweep — but commit only when the whole change is consistent. Editing in batches keeps each step reviewable; gating the commit on the full compile-and-test keeps the atomicity. You get reviewable progress without shipping a half-applied change.
Variations for Different Contexts
A backend engineer changing an API signature used across services: enumerate every caller first, apply through a typed refactor, and let the compiler prove full coverage before committing.
A frontend developer migrating a design-system prop: plan the exact set of components using the prop, edit in verifiable batches, and run the visual and unit tests as the atomic gate.
A platform engineer moving a shared interface across a monorepo: scope the plan to the affected packages, apply per-package, and gate the whole change on a full build so no package is left referencing the old shape.
⚠️ Common mistake: Committing a multi-file edit before running the full build and test suite. The whole risk of a multi-file change is inconsistency across the set, and only a complete build surfaces it. A commit that passed on the files you happened to open but breaks the ones you didn't is the exact failure this workflow exists to prevent.
Save and Reuse This
A reliable CLI agent multi-file edit treats the change as one atomic operation: enumerate the exact edit set first while it's free to correct, apply through scope-aware tools that don't catch false matches, and verify the whole change with a compile-and-test gate before committing. The broken half-rename comes from improvising file by file; the clean one comes from planning the set and proving coverage.
The enumerate-first prompts, the scope-aware rename instructions, the compile-as-coverage-check pattern — these apply to every cross-cutting change you'll make. Save them in PromptABCD so your next big rename lands all-or-nothing instead of leaving your codebase inconsistently broken in places you haven't found yet.
Continue Reading
Save the prompts from this post
PromptABCD is a free prompt manager. Paste, organize, and reuse your best AI prompts — no more hunting through chat history.
