Skip to content

cupofcat/hashline-gemini-cli

Repository files navigation

Hashline

Hash-anchored file editing for Gemini CLI. Replaces the built-in read_file, replace, and grep_search tools with versions that use content hashes instead of exact string matching.

The Problem

Gemini CLI's replace tool requires byte-exact string matching. Models frequently get whitespace wrong, causing "0 occurrences found" loops. This is the most common editing failure.

Read The Harness Problem for the full context.

The Solution

Every line gets a 4-character content hash. The model references lines by hash instead of reproducing content.

1#ZTVK:import os
2#HBPH:import sys
3#RKSY:
4#XMXP:def hello():
5#ZSTX:    return "world"

Editing targets the hash, not the text:

{"op": "replace", "anchor": "5#ZSTX", "new_text": "    return \"hello world\""}

If the file changed since the read, hashes won't match and the edit fails safely with corrected anchors. The model re-reads and retries.

Based on the hashline concept by Can Bölük (oh-my-pi).

Install

gemini extensions install https://github.com/cupofcat/hashline-gemini-cli

Prerequisites: Node.js 18+. For best hashline_grep performance, install ripgrep (rg). Falls back to grep if rg is not available.

To uninstall:

gemini extensions uninstall hashline

What It Adds

Three new tools alongside the built-ins (nothing is disabled by default):

Tool Use when Built-in equivalent
hashline_read You plan to edit the file read_file (still available for plain reads)
hashline_edit Surgical edits with anchors replace (still available as fallback)
hashline_grep Search then edit the matches grep_search (still available for plain search)

The model learns to use hashline tools for editing and built-ins for reading via the bundled GEMINI.md context.

Want to go all-in? To disable the built-in tools entirely, add excludeTools to gemini-extension.json in the installed extension directory:

{
  "excludeTools": ["read_file", "replace", "grep_search"]
}

Tools

hashline_read

Read a file. Every line is tagged LINE#HASH:content.

Parameter Required Description
file_path yes Absolute path
offset no Start line (1-indexed)
limit no Max lines

hashline_edit

Edit a file using anchors from hashline_read.

Parameter Required Description
file_path yes Absolute path
edits yes Array of operations

Operations:

// Replace one line
{"op": "replace", "anchor": "5#ZSTX", "new_text": "new content"}

// Replace a range (inclusive)
{"op": "replace", "anchor": "5#ZSTX", "end_anchor": "8#HBPH", "new_text": "line1\nline2"}

// Insert after a line (omit anchor for EOF)
{"op": "append", "anchor": "5#ZSTX", "new_text": "inserted line"}

// Insert before a line (omit anchor for BOF)
{"op": "prepend", "anchor": "5#ZSTX", "new_text": "inserted line"}

Rules: Always hashline_read first. Copy anchors exactly. new_text is plain content (no hashes). Batch edits into one call. Don't anchor on blank lines or closing delimiters.

hashline_grep

Search files. Results include anchors usable with hashline_edit.

Parameter Required Description
pattern yes Regex pattern
path no File or directory
glob no File filter (e.g., "*.py")
case_insensitive no Case-insensitive
context no Context lines (0-10)

Uses ripgrep. Falls back to grep.

How It Works

The hash is xxHash32 of each line's whitespace-stripped content, truncated to 2 bytes (65,536 possible values), encoded as 4 characters from the alphabet ZPMQVRWSNKTXJBYH. Punctuation-only lines (like }) mix the line number into the hash seed to avoid collisions.

Pure JavaScript — no WASM, no native modules.

Safety features:

  • Stale anchor detection with ±20 line closest-match relocation
  • Overlapping edit detection
  • CRLF and BOM preservation
  • Atomic file writes with permission preservation
  • Binary file rejection
  • Auto-stripping of hash prefixes models copy into replacements
  • Boundary autocorrection (trailing/leading line dedup)
  • Escaped tab autocorrection
  • Noop detection

Development

git clone https://github.com/cupofcat/hashline-gemini-cli
cd hashline-gemini-cli
npm install
npm run build
npm test              # 150 unit + E2E tests
gemini extensions link .

# Gemini integration tests (slow, needs API access)
bash test/gemini-integration.sh   # basic CUJ tests
bash test/gemini-stress.sh        # complex editing scenarios

License

Apache 2.0. See LICENSE and NOTICE.

Based on oh-my-pi by Can Bölük (MIT). xxHash32 from the public spec (BSD-2).


hashline, hash-anchored editing, content-addressable line references, gemini cli extension, MCP file editing, coding agent tools, replace_in_file alternative, 0 occurrences found fix, AI coding agent file editing, whitespace-invariant editing, model context protocol

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors