hashline — Edit by Content Anchor, Not Fragile Line Numbers
TL;DR
After installing @piex-dev/hashline, default edits go from "guessing line numbers" to "editing against the version you read": fewer silent mistakes, at the cost of occasional re-reads. A tax worth paying.
Overview
The edit tool of an AI coding assistant has a fundamental conflict: the model describes where to change with line numbers, but line numbers are deeply unstable in the real world. A user edits the file while the model thinks; a prior edit shifted lines; an unread region gets edited against an "assumed" line number — all cause silent, wrong writes.
@piex-dev/hashline overrides Pi's built-in edit with content anchors: tag on read, verify on write, reject lines never shown.
How it works
On read, a [path#TAG] is injected and seen-lines recorded; an edit must carry the same tag. The whole-file 4-hex tag acts like an optimistic lock: any external change invalidates it and forces a re-read. Stricter than per-line hashing, but it buys tree-sitter block ops and boundary repair.
[src/main.ts#A3F2]
SWAP 2.=2:
+const x = 2;
Phase 1 guards: 3 consecutive byte-identical noops → [E_NOOP_LOOP]; re-sending the same payload after success with an unchanged file → [E_DUPLICATE_EDIT]; CRLF / code-fence / extra-blank-line dialects normalized.
Usage
Install
pi install npm:@piex-dev/hashline
Active immediately: hashline overrides Pi's built-in edit tool and hooks read results. No extra switch, no config file.
Source: extensions/hashline
Configuration
Works out of the box, no required config. For local development, install runtime deps first:
cd extensions/hashline && npm install && cd ../..
Deps: @oh-my-pi/hashline ^16.4.0 (runtime), @earendil-works/pi-coding-agent (peer), typebox (peer).
Workflow
1. LLM calls read /tmp/file.js
2. hashline hook → inject header: [/tmp/file.js#A1B2]
3. LLM receives tagged file content
4. LLM emits a hashline patch
5. Patcher verifies #A1B2 + seen-lines → applies edit
6. Returns new tag: #C3D4
Verify
pi -e ./extensions/hashline/src/hashline.ts -p "what is 1+1" --no-session
Implementation
Wraps @oh-my-pi/hashline: hashline.ts overrides edit and hooks read; PiexNodeFilesystem drives node:fs + realpath directly; EditGuard handles noop/duplicate; Bun polyfill only provides xxHash32.
| Capability | Status |
|---|---|
| tree-sitter block / REM·MV | ✅ via engine |
| Noop / Duplicate / normalize | ✅ Phase 1 |
| Stale auto-recovery / multi-version snapshot | ❌ Phase 2 |
Design notes
| Project | Mechanism | piex choice |
|---|---|---|
| oh-my-pi hashline | whole-file tag + tree-sitter block grammar + boundary repair engine | Adopted: wrap @oh-my-pi/hashline, inherit tag, SWAP.BLK, REM/MV and the engine. Not adopted: in-tree integration, Bun FS, LSP writethrough; use Node + an outer EditGuard instead |
| pi-hashline-edit | per-line context hash + 3-way merge recovery + JSON DSL | Not adopted core algorithm (route divergence), borrowed the fault-tolerance intent (noop/dup guard). ADRs kept as Phase 2 Stale-recovery reference |
| pi-hashline-edit-pro | per-line content hash + stable mapping | Not adopted algorithm, borrowed "minimize re-reads" as a long-term goal |
Core trade-off: whole-file tag (strict and simple) over per-line tag (locally usable), with a wrapper layer for fault tolerance. Three phases: Phase 1 tolerance (done) → Phase 2 recovery → Phase 3 undo/LSP integration.
Changelog
Roadmap
Conflict policy leans toward reject (safe but costly) → add 3-way merge / Recovery; snapshots are thin → multi-version LRU + anchored Grep; duplicate granularity per section; wrapper-layer unit tests and optional LSP integration.
Phase 1 ✅ Noop Loop / Duplicate Edit / dialect normalize
Phase 2 Stale recovery · multi-version snapshot · anchored Grep
Phase 3 Undo · Auto/Raw Read · LSP integration · denser tests
Version history
| Version | Date | Changes |
|---|---|---|
| 0.1.1 | 2026-07-14 | Initial release: wraps @oh-my-pi/hashline, overrides built-in edit; Phase 1 guards (Noop Loop / Duplicate Edit / dialect normalize); Node.js native FS + realpath path normalization |
Appendix: comparison with other hashline implementations
Three industry routes: oh-my-pi whole-file tag, pi-hashline-edit context per-line hash, pi-hashline-edit-pro stable mapping. piex picks the first as engine, borrowing fault tolerance from the latter. Full comparison in the source.
Source Markdown: docs/packages/hashline.md