Companion CLI · Open source
prepass
Coding agents spend their first turns grepping to work out where your code lives. prepass ranks the repository against the request and hands over a shortlist before the model speaks — in 22ms, with no API key, no index, and no network call.
Agent Retrieval Bench · trace2code · n=101 · Recall@5
First of eight, on someone else's benchmark.
A published benchmark with 287 hand-reviewed samples and a leaderboard for seven retrievers. Given the output of a failing test, find the source at fault. prepass ranks the benchmark's own corpus snapshots and is scored against its published answer key — so neither the questions nor the answers are ours.
Recall@20 reaches 0.941 and MRR 0.574, against 0.165 for the 8-billion-parameter model. Median query time on their corpus: 16ms.
Where it loses
Two of the three tasks, it does not win.
The same benchmark asks two other questions, and prepass is mid-pack on both. A page that showed you only trace2code would be selling you something.
The pattern is not mysterious. A stack trace is a dense list of exact identifiers printed verbatim — the best possible input for a lexical ranker. "Which tests should change with this code?" requires knowing what a test covers, which no amount of word overlap tells you.
1,007 real GitHub issues · 53 repositories
Three corpora, none of them written here.
The query is the issue text as a stranger filed it. The correct answer is whichever files the accepted patch touched. Every figure below was re-derived through a rewritten harness on 9 August 2026 and reproduced exactly, with none of the instances skipped.
Picking 20 files at random from the same pools hits 1.56%, so this is roughly 50x chance.
The number that matters more than the average
78% is not what any single repository gets.
Across repositories with at least ten issues, top-20 accuracy runs from 43.8% on sphinx to 87.0% on matplotlib — a 43-point spread. The multilingual corpus hides 41 points the same way.
The cause is the design, stated plainly: prepass leans hardest on the filename. It is strong where names are distinctive and weak in a repository full of index.ts and utils.py. That is why JS/TS is its worst language and C++ its best.
Worth knowing about the benchmark too: SWE-bench Lite is 38% django and 26% sympy. Removing both entirely leaves 76.1% — 1.9 points off the headline, so the number is not propped up by them.
Speed
One number would be the wrong shape for this claim.
Latency is dominated by I/O that scales with the candidate pool, so here is all of it — measured end to end across 27 real repositories.
Worst case measured: 221 ms on Django at the 5,000-file discovery cap. Benchmark tables quote 106 ms, which is the SWE-bench median over a 1,867-file pool — larger than most projects, and not what you will see.
In practice
An agent choosing it, unprompted.
Codex desktop, asked a symptom-shaped question about a real iOS codebase. Nothing in the prompt mentions prepass. The agent reached for it on its own, and said why:
That is the whole design in one screenshot: orient first, then narrow — instead of opening with a repository-wide grep.
Why it works
It is the rarity of the rarest shared word.
BM25F is the document-ranking maths behind essentially every search engine — arithmetic, not a model, which is why there is nothing to download. prepass scores three fields separately: file contents, filename, and directory path.
The mechanism was proven by intervention rather than assumed: degrade the rarest shared term between prompt and file and accuracy collapses 2.7x harder than degrading the count of shared terms. One unusual identifier you both mention beats fifty ordinary words.
It reads the repository fresh on every prompt. No index means nothing to build, nothing to invalidate, and no way to silently return stale files — the worst failure mode a tool like this can have.
Install
One command, then you forget it exists.
npx @nharing/prepass init
- No API key and no account — it never makes a network call
- No index and no background process
- No config file required
- Apache-2.0, including the patent grant — usable inside closed source
It runs as a UserPromptSubmit hook, verified live on Claude Code and Codex CLI, as a skill on Codex desktop, and as an MCP server for editors that speak MCP rather than hooks.
Don't take my word for it
How to check every number here.
The raw per-instance results ship in the repository — every candidate list, every rank, every miss. You can recompute the percentages from them without running anything. If you want to reproduce the runs themselves:
# Agent Retrieval Bench — their corpus, their published answer key
ARB_ROOT=<their release> node bench/arb.mjs
# SWE-bench Lite — 300 real GitHub issues
node bench/swebench.mjs --repos <clones> --data swebench-lite.json
Both harnesses exit non-zero rather than print a number they cannot stand behind: zero scored instances is fatal, and so is a run where more instances failed to check out than succeeded. That rule exists because earlier versions did the opposite.
What went wrong
Three numbers on this page were wrong first.
Every measurement error in this project was a definition error — counting one thing and describing it as another. None would have been caught by running the test again, because they were perfectly reproducible and perfectly wrong.
- The ARB answer key. I first derived the correct files myself from the sample records, using a field that looked right. It was a subset of the real answer and wrong on 22 of 287 samples, which inflated recall. Those numbers were thrown away. The figures above read the benchmark's own published per-sample results.
- The latency claim. This tool was described as "110ms" for several days. That was the SWE-bench median — measured on repositories with a median of 1,867 files — quoted as if it were typical. The real figure on ordinary projects is 22ms, and the table above now gives the whole distribution instead of one number.
- A table row built on a single prompt. One experiment, one prompt, generalised into a claim about when prepass does not help. Deleted, and replaced with what was actually measured across a corpus.
The second pass over the benchmarks was not a re-run of the same code. The harnesses were rewritten first — new failure accounting, new guards — and then the numbers were re-derived. Re-running identical code tests whether a machine is flaky. Running different code against the same definitions is what tests whether the claim was ever true.
Benchmarks used: Agent Retrieval Bench, SWE-bench Lite, SWE-bench Multilingual, and a held-out set never used for tuning. I wrote neither the questions nor the answers in any of them.