Hashline Edit Format
Hashline is the harness’s read/edit format. Each line is tagged with a short hash of its content, so an edit can be rejected when the file has changed since the agent last read it.
Source: crates/core/src/hashline.rs. Exposed as the built-in tools
__HASHLINE_READ__ and __HASHLINE_EDIT__.
Format
Lines are formatted as {line_num}:{hash}|{content}:
1:a3|fn main() {
2:7f| println!("hello");
3:b2|}
__HASHLINE_READ__ returns a file in this form. The agent then references
lines by line:hash when editing.
Hash function
The hash is FNV-1a (offset basis 2166136261, prime 16777619) truncated to the
low byte (hash & 0xff) and formatted as two lowercase hex characters. With
256 possible values it is meant for change detection, not collision resistance.
Edit operations
__HASHLINE_EDIT__ takes an array of operations. Each references a target line
by line:hash:
replace— replace lines fromstartto optionalend(inclusive) with new contentinsert_before— insert content before the referenced lineinsert_after— insert content after the referenced linedelete— delete lines fromstartto optionalend(inclusive)
Every referenced line’s hash is validated against a fresh read of the file
before anything is applied. If any hash does not match, the whole edit is
rejected and the agent is told to re-read. Operations are applied in reverse
line order (so earlier edits don’t shift later line numbers), then the file is
rewritten in place with exactly the computed bytes — a file without a trailing
newline stays without one, and a blank last line stays. The write itself
re-checks that the file still holds the bytes that were read (cksum, in the
same shell invocation): if it changed in between, nothing is written and the
error names the stale line references. That check needs cksum on the agent’s
PATH and allowed by its sandbox policy (Bash(cksum) is in the default allow
list); if the check itself cannot run, the edit is refused with the shell’s
error rather than a retry hint. Files that are not valid UTF-8 or that contain
NUL bytes are refused, since the write cannot reproduce them byte-exact.
The parser accepts either operations or edits for the array key, and either
content or new_text for the text field.