Production and case studies
Patch edit tools
Unique-match search-and-replace with a clear error beats sloppy full-file rewrites for most coding-agent edits.
How the agent writes to disk decides whether the diff is reviewable and whether unrelated code survives. Production agents lean on unique-match apply_patch with retries. If old_str matches 0 times or more than once, return an error and let the model re-read.
Concept
Before you start: agentic search found the file. An edit tool is the only way the model should change it. Never apply edits outside the workspace root.
The big idea
| Style | Pros | Cons |
|---|---|---|
| Search-replace / patch | Small, reviewable, less drift | Fails if the unique-match is wrong |
| Full-file write | Simple for new or small files | Easy to delete unrelated code; huge tokens |
| AST-aware edit | Structurally safe | Harder to build; language-specific |
Validate after edit: the file still parses, the formatter runs, or a compile check passes. Symlink escapes and ../ paths are classic sandbox holes. See sandboxes.
def apply_replace(text: str, old: str, new: str) -> str:
count = text.count(old)
if count != 1:
return f"ERROR: expected 1 match, found {count}. Re-read the file."
return text.replace(old, new, 1)
src = "def add(a, b):\n return a + b\n"
print(apply_replace(src, "return a + b", "return a + b + 0"))
print(apply_replace("x = 1\nx = 1\n", "x = 1", "x = 2"))Output:
def add(a, b):
return a + b + 0
ERROR: expected 1 match, found 2. Re-read the file.The second call refuses to guess. The model must read and tighten old_str.
For multi-file refactors ("rename this concept across 80 files"), prefer language-aware renames (IDE/LSP) over 80 search-replaces. Require plan approval listing files to touch. Run tests after each batch of N files, not only at the end. Forbid formatting-only churn in unrelated files.
Planning weight
"Plan mode" is both a product surface and a prompting strategy. Forcing a written plan before edits reduces wrong-branch work on multi-file tasks. Inside the loop, light planning ("list files you will read next") helps without a rigid state machine.
Do not over-prescribe step lists for every task. Anthropic's SWE-bench writeup notes that giving the model autonomy with good tools outperformed heavy workflow graphs. Use plans when uncertainty or blast radius is high. Skip them for "fix the typo in utils.ts."
Common mistakes
- Full-file rewrite of a 2,000-line module to change one function. Unrelated code disappears.
- Applying a match that hits three times. The tool should error, not pick one.
- Edits outside the workspace root. Treat
../and symlinks as holes.
Check yourself
old_strmatches twice. What should the tool return? An error asking the model to re-read, not a guessed replace.- When is a full-file write reasonable? New files, or files small enough that the whole contents are the patch.
Key takeaways
- Unique-match patches with clear tool errors beat sloppy full-file rewrites.
- Validate that the file still parses after the edit.
- Never write outside the workspace root.
- Match plan weight to blast radius.
Further learning
Edits are only done when tests say so. Measure that in coding agent evals.
Related
Case study: coding agent
How coding agents work: repo context, edit tools, test loops, sandboxes and review.
Agent sandboxes
Code, browsers and filesystems run somewhere else, with no production secrets, capped resources and an allowlisted network.
Agentic code search
Grep, glob and targeted reads beat dumping a repo or trusting a nearest-neighbor hit that looks relevant and is the wrong module.