grep-hygiene · hay · v0.3.0

A ranked grep for coding agents.

hay returns exactly ripgrep's matches — never more, never fewer — reordered so the line that declares what you asked about comes first, and so the first page is ten files rather than ten lines of one file. Because an agent reads the first page and opens something.

See the benchmark Read the manual Source on GitHub
Rust · MSRV 1.88 no index · no daemon · no state differential-tested vs rg exit codes that refuse to lie

why hay

One opinion replaces shelf order.

the problem

Path order is shelf order.

ripgrep is prior-free by design: every match, in walk order. For an agent that reads the first page and acts, a dead planning document sorting before the real function isn't a quirk of ranking — it's the whole answer being wrong.

the choice

Definitions outrank mentions.

hay adds one prior: a line that declares the thing beats a line that merely names it. Declaration keywords, typed-declaration shapes, key styles — each signal counted before it was coded, each switchable with --no-*.

the honesty

The win says how weak it is.

The public benchmark's ground truth is declarations — hay's home turf. So the report leads with its own warning, shows intervals, cross-checks with Fisher randomization, and points at the behavioural evaluation nobody designed around the tool. That evaluation still fails the ship gate written before the first line of Rust: 0.44 median MRR against 0.50, 78.5% against 80%. The gate has not been moved.

watch

The benchmark in eighteen seconds.

Ranked grep, measured. Mean reciprocal rank per corpus — muted bars are deterministic rg --sort path, gold is hay. Ground truth comes from ast-grep, a parser independent of every tool under test.

the numbers, animated

MRR by corpus — scroll to grow.

Mean reciprocal rank of the declaring file against deterministic rg --sort path. This definition-finding track is hay’s home turf; the separate docs track has no detected wins and four regressions. Full intervals, exclusions, and tests are in the complete report.

linux kernel
MRR 0.933
openclaw
MRR 0.928
ripgrep source
MRR 0.877
alamofire (swift)
MRR 0.776
muted = deterministic rg --sort path · gold = hay · n = 30/30/23/29 sampled queries · ground truth: ast-grep

what it does

Deliberately narrow, loudly honest.

drop-in shape

rg-compatible I/O

path:line:text, globs, file types, context windows, JSON Lines — combined short flags included, via lexopt. As of 0.3.0 every valid ripgrep invocation has an answer: -c, -v, -o and --stream run unranked, in ripgrep's own traversal, with no candidate cap.

the product

Definition-first ranking

Four signals and a file-interleaved layout, each with an ablation switch (--no-definition, --no-path, --no-word, --no-tf, --no-diversify): a contribution you cannot switch off is a belief, not a measurement. Four more were built, measured and deleted.

for agents

Loud by design

Candidate cap hit? stderr notice plus exit 2. Flag refused? The reason, out loud, with the ripgrep equivalent named. Quiet wrong answers are the defect this tool exists to prevent.

verified

Differential-tested

Every change to walking, matching, or output must return exactly ripgrep's matches — the harness has caught three defects no unit test could see.

install

One line.

brew install mneves75/tap/hay     # macOS and Linux, prebuilt and attested
hay validateSession src/          # best answer first

# or from source:
git clone https://github.com/mneves75/hay.git && cd hay && cargo install --path hay

Then read the manual — every flag, the JSON contract, exit codes — or the full benchmark report, or how all of it works from zero.