Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Hash-anchored line edits — refuse the edit if the target line content changed since the read. Use when editing a file that may have shifted between read and write, to avoid stale-line corruption.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 54% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 83% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 56% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 24% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 83% | 0% |
Catch stale-line edit failures BEFORE they corrupt a file. A stale-line edit happens when an agent reads a file, plans an edit, then submits the edit after another tool call has rewritten the line — the edit applies to the wrong content.
Adapted from oh-my-openagent's hashline_edit pattern (which reports reducing stale-line edit failures from ~93% to 32% on Grok Code).
The mechanism: every line read through read-with-hashes.sh is tagged with a content-hash anchor (<lineno>#<hash>|<content>). The edit companion edit-by-hash.sh applies the edit IFF the current line's hash matches the anchor. Mismatch → refuse + diff.
Two operations, no third:
by hash match
Multi-line edits and structural transforms (move blocks, refactor across files) are out of scope. Use the standard Edit tool for those, or break them into per-line hashed edits where the staleness risk is real.
may have changed by minute 35. Hash-anchored edits catch the staleness.
may touch the same file, hash anchors make race-condition edits fail loud instead of silently corrupting.
the line they think they're editing and the line they actually reference. Hash anchors catch the drift.
config, or anything where a wrong-line edit has compounding cost.
standard Edit tool's exact-string-match is enough.
staleness risk.
block moves, format conversions).
Two scripts under scripts/:
read-with-hashes.sh <file> [--start N] [--end N] — readsthe file (or a line range) and outputs each line in <lineno>#<hash>|<content> form. The hash is a 4-char hex digest (cksum % 65536) over the line content; ~65k buckets is more than enough collision space for a single file.
edit-by-hash.sh <file> <lineno>#<hash> <new-content> [--delete]— applies the edit IFF the current line's hash matches the anchor. Mismatch produces a stderr diff and exit code 5.
The agent's contract:
read-with-hashes.sh.42#a3f1),not its line number alone.
edit-by-hash.sh.Don't paper over the mismatch — the staleness is real.
The lead does the verification the runtime would otherwise do:
anchor matched, but read-with-hashes of the post-edit region is the audit trail proving the change is what was intended.
the file changed since the agent's read, the agent's reasoning was based on stale content. Re-read, re-reason, retry — don't blindly force-apply the edit by re-computing the hash on stale assumptions.
a pattern of mismatches against the same file means concurrent writers and the workflow needs sequencing, not retries.
cksum hashes byte-for-byte. A line that'sfoo\r\n and one that's foo\n produce different hashes. If your files mix line endings, normalize before hashing or expect the hash check to flag the difference.
cksum includes trailing spaces. Aline with a trailing space hashes differently from one without. The hash mismatch you see may be a whitespace edit, not a content edit.
same hash (0000 from cksum of empty input is actually ffff in cksum's representation, but consistent — empty hashes match each other). For edits to empty lines, line number alone disambiguates.
edit-by-hash.sh replaces ONE line.For multi-line replacement, delete N lines and re-insert via N separate edit calls, or use the standard Edit tool with full context.
falls back to a tail-based read for the last line) but verify on files where the final-line-no-newline matters semantically.
This release ships the helper scripts as opt-in tools. The next step is a PreToolUse hook that intercepts every Edit / MultiEdit call, detects when the agent's old_string doesn't match the file's current content (i.e., the file changed since the agent's last Read), and refuses the edit with a diff. That makes the staleness check the default, not the opt-in.
The hook is deferred to v0.3 for design reasons, not Phase 0.5 reasons:
Edit tool's stdin payload shape is already known(hi_old_string, hi_new_string, hi_file_path in lib/hooks/lib/hook-input.sh).
Edit's exact-string-match semantics already catch some cases; the hook should only fire when the agent's old_string matches but represents content that was true at a previous Read.
shape lets us iterate on the format before locking it.
Other measured skills in the registry, with their headline benchmark lift.