How Claude Code Edits Your Repo: Inside the Agentic Edit Loop
▶ Watch on YouTube & subscribe to The Stack Underflow
When Claude Code rewrites a dozen files and your tests still pass, it feels like wizardry. It is not. It is the agent loop — the same mechanism covered in How Claude Code Works: The Agent Loop — applied to your filesystem with one strict discipline: read before you write, plan before you edit, verify before you claim done.
Understanding this loop makes you a better Claude Code user immediately. You will know why skipping a Read causes hallucinated API calls, why Plan Mode exists, and why the Edit tool rejects edits that are “almost” right. This is the mechanism behind every change the tool makes to your repo.
The one-sentence version: Claude Code does not regenerate your files — it runs a loop of search, read, exact-string-replace, and test execution, so every edit is targeted, reviewable, and driven by real feedback from your code.
The wrong model vs. the real one
Most people assume AI coding tools work like a very fast programmer who reads a file and rewrites it from memory. That model is wrong in every dimension that matters to a production codebase.
| The myth | What actually happens |
|---|---|
| Reads a file, regenerates the whole thing | Reads a file, replaces a specific string with another string |
| Edit cost scales with file size | Edit cost scales with the size of the change |
| Can silently touch unrelated lines | Can only change the exact bytes it targeted |
| One shot: prompt in, result out | A loop: edit, run tests, read errors, fix, repeat |
| Needs the whole repo in context | Searches to find relevant files; reads only those |
The shift from “generate the file” to “apply a targeted diff” is the whole game. It is what makes agentic editing safe enough to trust on a real codebase, and it is why a single bad prompt does not usually nuke your formatting.
The four tools in the edit loop
Claude Code is a model wired to a tight set of tools — callable functions that reach your filesystem and shell. The edit loop uses four of them.
┌─────────────────────────────────────────────────────┐
│ CLAUDE CODE EDIT LOOP │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ SEARCH │──▶│ READ │──▶│ EDIT │──┐ │
│ │ Grep/Glob│ │ (slice) │ │ (diff) │ │ │
│ └──────────┘ └──────────┘ └──────────┘ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ RUN (Bash) │ │
│ │ npm test / tsc │ │
│ └────────┬─────────┘ │
│ │ │
│ PASS ◀────────┴────▶ FAIL │
│ │ │ │
│ done back to │
│ READ │
└─────────────────────────────────────────────────────┘
- Search (
Grep/Glob) — find where the relevant code lives without pulling the whole repo into context. A monorepo with 50,000 files is no problem; only a few paths make it through. - Read — pull the exact file (or a line-range slice of it) into the context window. The model sees the real current text, not a guess from training data.
- Edit — perform an exact string replacement: “find this precise block, swap it for that block.” Not a regex, not fuzzy matching — the old string must match byte-for-byte, indentation included.
- Run (
Bash) — execute something real:npm test,tsc --noEmit, your linter, your build. The output lands back in context as feedback for the next iteration.
That is the entire repertoire for code changes. Multi-file refactors, dependency upgrades, bug fixes across ten modules — all of it is this four-tool loop, repeated.
Walking one edit, start to finish
Say you ask: “Fix the null check in the data processor.” Here is the actual sequence of tool calls the agent makes:
1. SEARCH Glob / Grep: "data processor"
→ finds src/processor.ts
2. READ Read: src/processor.ts (lines 40-80)
→ model sees the real current code
3. EDIT Edit: src/processor.ts
old_string: "if (data.value) {"
new_string: "if (data?.value != null) {"
4. RUN Bash: npm test
→ PASS: loop ends, change is done
→ FAIL: model reads the error, goes back to step 2
Step 3 is where the key constraint lives. The model must reproduce the old string exactly as it exists on disk — same whitespace, same indentation, same line endings. If it is even one character off, the Edit tool rejects the call with an error. That sounds frustrating until you understand why it exists: the tool will not let the model edit code it did not actually look at and reproduce correctly. It is a forced proof-of-read.
Why exact string replacement, not whole-file rewriting
Three reasons, each of which matters on a real repo:
| Property | What it gives you |
|---|---|
| Precision | Only the targeted bytes change. Unrelated functions, comments, and formatting are physically outside the operation’s scope. |
| Reviewability | A targeted replacement is a diff — old block out, new block in. You can git diff it and see exactly what changed, not play spot-the-difference in two 600-line files. |
| Token efficiency | You pay for the change, not the file. Editing one function in a 3,000-line module does not cost a 3,000-line context. |
The Edit tool also enforces uniqueness: if the old string appears more than once in the file, the edit fails by default and asks for more surrounding context to pin down the right location. Pass replace_all: true only when you genuinely want every occurrence changed. This default is another safety mechanism — it prevents the model from accidentally touching the wrong instance of a repeated pattern.
Plan Mode: approve before the first edit fires
Between your prompt and the first Edit call, Claude Code can operate in Plan Mode — a read-only analysis phase where it searches and reads freely but is prohibited from modifying files or executing state-changing commands.
You: "Refactor the auth module to use the new token format"
│
▼
┌───────────────────────┐
│ PLAN MODE │
│ Search → Read → Read │
│ Produces a checklist │
│ of planned edits │
└───────────┬───────────┘
│
[You approve the plan]
│
▼
┌───────────────────────┐
│ EDIT PHASE │
│ Edit → Run → Edit… │
└───────────────────────┘
Plan Mode is the right choice before any change that would be expensive to undo: database migrations, auth flows, multi-file refactors, anything touching production configuration. It surfaces the agent’s intent before it acts, so you can catch a misunderstanding when it costs nothing to correct. As of 2025–2026, Plan Mode is a first-class permission mode in Claude Code, enabled with Shift+Tab in the interactive session (docs.anthropic.com, 2025).
CLAUDE.md: your conventions in context
Every iteration of the loop — every search, read, edit, and verify pass — has one file pinned in context the entire time: your CLAUDE.md. This is a Markdown file (stored at the project root, or in a hierarchy of directories for subtree-specific rules) that Claude Code reads at the start of every session and keeps in its context window throughout.
CLAUDE.md is where you tell the agent things it cannot infer from code alone:
- Coding style rules (“use ES modules, not CommonJS”)
- Test commands to run before claiming done (“always run
npm run test:integration”) - Forbidden files or patterns (“never edit generated files in
src/generated/”) - Workflow constraints (“open a GitHub issue before creating a new branch”)
Because CLAUDE.md rides in context through every loop iteration, those rules apply to every edit the agent makes — not just the first one. This is the mechanism behind “it follows our house style” and the reason a missing or badly written CLAUDE.md is often the root cause of an agent drifting from your conventions (docs.anthropic.com, 2026).
The verify loop is the real intelligence
The single most underrated part of the loop: Claude Code runs things and reads the output. It does not edit and hope. It runs your tests, reads the failure message, and uses that as the input for the next edit decision.
edit → npm test → FAIL: TypeError: data.value is undefined
→ read stack trace (processor.ts:54)
→ read processor.ts lines 50-60
→ edit the actual cause (wrong optional chain)
→ npm test → PASS
A coding agent without a verify loop is sophisticated autocomplete. The verify step is what separates “I made a change” from “I made the right change.” The model is not expected to be correct on the first attempt — it is expected to converge, using real feedback from your actual runtime. The target condition is always “tests pass,” not “the model expressed confidence.”
The failure mode: skipping READ
The most common source of Claude Code producing hallucinatory edits — calling a method that does not exist, importing from a path that was moved, referencing an interface that was renamed — is a missed Read. If the model edits without reading the current file first, it is working from training-time knowledge or earlier context, not the live state of your repo.
CORRECT sequence: FAILURE sequence:
Grep → Read → Edit Edit (no prior Read)
(matches real code) (matches stale memory)
Edit succeeds Edit fails OR worse:
edit succeeds but writes
a hallucinated API call
The Edit tool’s read-before-edit requirement is a partial guard — it rejects edits where the old_string does not match, which forces a fresh Read. But if the model constructs an old_string from stale context that happens to match real content, the guard does not trigger. The discipline of “always read first, explicitly” is yours to enforce via CLAUDE.md or Plan Mode review.
Permissions: you stay in control
Edits and shell commands do not fire blind. Claude Code runs under a layered permission model:
| Rule type | Effect |
|---|---|
| Allow | Tool runs without prompting (e.g., npm test is always safe) |
| Ask | Agent pauses and waits for your approval before the call |
| Deny | Call is blocked outright (e.g., never run git push --force) |
PreToolUse hooks sit upstream of this permission system — they run before any permission check and can approve, deny, or mutate tool calls programmatically. This is how teams enforce constraints that static allow/deny rules cannot express: “block any Edit to files in src/generated/,” “require an issue ID in the commit message,” “run the security scanner before any dependency change.” See Claude Code Hooks Explained for the full mechanics.
Permission settings can be committed to version control in .claude/settings.json and distributed to every developer in the organization, so the team’s constraints are consistent across machines.
Common misconceptions
- “It regenerates the whole file.” No. Every change is a targeted string replacement scoped to the exact bytes you gave it. The rest of the file is physically untouched by that operation.
- “It edits code it has not seen.” It cannot, by design — the exact-match requirement means it must reproduce the current on-disk text correctly, or the Edit call is rejected. A failed match is a signal to re-read.
- “One prompt, one shot, done.” No. The loop can run many iterations. The model is expected to converge via test feedback, not to nail every edit first try.
- “It can do anything to my machine.” Only what the permission model allows. Allow rules, Ask rules, Deny rules, and PreToolUse hooks together mean no command or edit runs without authorization — either pre-approved or confirmed at runtime.
Frequently asked questions
What happens if the file changes on disk after Claude Code reads it? The exact-match Edit fails, because the on-disk text no longer matches the old_string the model reproduced from its earlier Read. That is intentional — it forces a fresh Read of the updated file rather than silently clobbering a change someone else made or that another tool applied.
How does it handle edits across many files? The same four-tool loop, repeated per file: search to locate each file, read each one, apply a targeted Edit, verify after all edits are done. There is no magic “multi-file rewrite” mode. Scale is achieved by looping, not by a different mechanism.
Does it need to read my whole repo? No. Grep and Glob let it find the specific files that matter and pull only those (or slices of those) into context. A repo far larger than any context window is handled by searching well, not by reading everything. Context-window size is not the constraint on repo size.
Why does it sometimes run tests before making any change? To establish a baseline — knowing which tests already pass means it can distinguish between “this was broken before I touched it” and “I broke this.” A green baseline at the start of a session is the honest reference point for “did my edits cause this failure?”
What model powers Claude Code?
As of mid-2026, Claude Code defaults to Claude Opus 4.8 for complex, long-horizon tasks. The underlying model uses the same Messages API agent loop — stop_reason: "tool_use" triggers a tool call, the result is appended to the conversation, and the loop continues until stop_reason: "end_turn" (docs.anthropic.com, 2026). The Agent SDK exposes this same loop as a programmable library for teams building their own agentic workflows.
What is the relationship between Claude Code and the Agent SDK? The Agent SDK is Claude Code’s loop extracted as a library — same agent loop, same built-in tools (Read, Grep/Glob, Edit, Bash), same context management, programmable in Python and TypeScript. If you want to run a version of this loop inside your own process, with custom tools and your own orchestration, the Agent SDK is the entry point. See Claude Agent SDK Explained.
Where this fits in the series
This tutorial is part of How Claude Actually Works — a course that builds a mechanistic picture of Claude, layer by layer. The agent loop this tutorial describes lives inside a broader stack: tools and MCP at Layer 2, the agent loop at Layer 3, and Claude Code as a Layer 4 surface. Before this tutorial, How Claude Code Works: The Agent Loop covers the core loop in depth. After it, Claude Code Hooks Explained covers PreToolUse and PostToolUse hooks, and CLAUDE.md File Hierarchy covers every level of the CLAUDE.md layering system. Browse all tutorials to move through the series in order.
Found this useful? The deep version lives on YouTube — new breakdowns of how AI dev tools actually work, weekly.
Subscribe on YouTube →