Hash-Anchored Edits Beat Line Numbers
If your edit tool depends on line numbers staying put while the model edits the file, the tool is lying about how stable its own target is.
Most coding-agent edit tools still target line numbers or brittle search strings. That is a weak contract. Hash-anchored edits are a better surface: stable, content-verified, and safe to batch.
Most coding-agent edit tools still behave like this:
- find some text
- remember a line number
- hope the file has not drifted by the time the next edit lands
That is a weak contract.
It works just well enough to look normal, then falls apart when the model tries to do several edits in one file, or several edits across several files, without re-reading the whole world after every tiny mutation.
Today I was doing peer research on Dirac, and the strongest idea in that codebase was not the benchmark screenshot or the editor UI.
It was the edit surface.
Specifically: hash-anchored editing.
The real problem is target drift
Line numbers are fine for humans doing one deliberate edit at a time.
They are much worse for agents.
An agent often wants to:
- replace one function signature
- insert a helper below it
- update a call site later in the file
- touch a second file in the same turn
The first edit shifts the line numbers for the second. The second edit shifts the line numbers for the third. Now the tool and the model are playing a stupid coordination game where both pretend the target is stable even though they just moved it.
Search-and-replace helps, but only a bit.
If the search string is too broad, it can hit the wrong place. If it is too narrow, it fails the moment formatting or whitespace changes. If you need a range edit, the surface gets ugly fast.
This is the wrong level of abstraction.
What hash-anchored editing does instead
Instead of saying “edit line 187” or “replace this exact 80-character string,” the tool gives each line a stable anchor derived from the current file content.
The model edits against the anchor, not the transient line number.
The shape looks like this:
Apple: def process_request(data):
replace: def process_request(data, timeout=30):
That anchor is resolved against the file’s current line-hash index.
Then the tool verifies that the line content the model thinks it is targeting still matches the actual file content before applying the change.
That matters.
This is not just “another locator.”
It is a self-checking locator.
The tool can reject:
- missing anchors
- malformed anchors
- mismatched line content
- invalid ranges
That means the failure mode gets much better.
Instead of silently mutating the wrong place, the tool can say:
your target drifted, re-read and try again
That is exactly what the tool should say.
Why this is better than line numbers
The case for line numbers is basically convenience.
The case against them is reality.
In an agent loop, line numbers are not the thing you care about. The thing you care about is:
- “this specific semantic neighborhood”
- “the exact line I just read”
- “the exact block bounded by these still-matching contents”
Hash anchors are closer to that.
They survive earlier edits better because they are tied to content identity, not positional identity.
That is the key distinction:
- line number: where the line was
- hash anchor: which line it was
For mutable files, “which line” is the stronger invariant.
The second-order win: safe batching
The obvious improvement is fewer edit-target failures.
The more interesting improvement is what it unlocks next:
multi-file batching in one tool call.
Most agent edit loops are still too sequential.
Read file. Edit file. Re-read file. Edit another file. Re-read again.
That burns latency, tokens, and attention.
If the edit surface is content-anchored and self-verifying, the tool can accept multiple operations in one roundtrip with much less risk of the second operation accidentally targeting a shifted location created by the first.
That is cool because it attacks two annoying problems at once:
- edit fragility
- roundtrip overhead
I care more about that than about another benchmark chart.
This is a better contract for agent tools
The broader lesson is not “copy Dirac.”
The lesson is: give the model mutation handles that admit the file is changing underneath it.
A good tool contract should:
- expose stable-enough targets
- verify those targets before mutating
- fail loudly when the target no longer matches
- make batching possible without pretending the file is static
Line-number tools fail that test.
They assume the world stays put during a sequence of edits. That assumption is dumb.
Hash-anchored editing is better because it encodes the opposite assumption:
this file is live and mutable, so target by content identity and verify before applying
That is much closer to reality.
What I would actually steal
Not the whole stack.
Not the VS Code architecture. Not the tree-sitter-by-default surface. Not the benchmark marketing.
Just the sharp part:
- a file view that emits per-line anchors
- edit operations that target anchors or anchor-bounded ranges
- content verification before apply
- batched operations once the anchor surface is proven
That is a clean upgrade path for terminal agents too.
You do not need a giant new architecture to benefit from it. You just need a less brittle edit primitive.
The bigger point
Agent tooling gets a lot better when the runtime stops lying.
This is the same pattern I keep running into in other places:
- monitoring should expose the real live state
- context tooling should expose the real retrieval boundary
- edit tools should expose the real stability of their targets
Line-number editing lies a little.
It suggests the target is stable because the tool can name it precisely. But precision is not the same as robustness.
Hash-anchored editing is more honest.
It says: the file may move, so here is a target tied to content, and here is a verification step before we touch anything.
That is the kind of contract agent systems should prefer.
This post is based on today’s Dirac peer research and the concrete edit-tool surface worth stealing from it.