BENCHMARKS · WINS AND LOSSES, WITH RECEIPTS

EVERY NUMBER HERE
TRACES TO A RUN.

Five things a search engine for AI agents has to prove, each measured, each linked to the harness or the case study that produced it: engine performance, code retrieval, ranking quality, token savings, and the design that ties them together — the zero-token architecture. The red cells are published too, root-caused with file:line, because a benchmark page that hides its losses is marketing.

6.5×
cheaper agent runs
$21.90 → $3.38 across 21 unfamiliar-API tasks, same Claude Code — reference-coding case study
21 / 21
tasks solved with retrieval
against 1 / 21 from model memory alone; hidden-test verdicts, real token accounting
55 W · 26 T · 4 L
vs Elasticsearch, 88 cells
audited board, cache-off, iso-load; every verdict shown — the full scorecard
11.7 ms
identifier lookup — code index
vs 15.3 ms for Sourcegraph's Zoekt and 260 ms for cold ripgrep, same 15-repo corpus, same box
01·PERFORMANCE · ENGINE + RESOURCES

FAST WHERE IT'S USED,
QUIET WHERE IT ISN'T.

Two performance stories matter for an engine that lives next to your agents: how fast a query comes back, and what the process costs when nobody is asking. Both are measured; neither is extrapolated.

MeasurementXERJComparisonVerdictSource
88-cell query board vs Elasticsearch 8.x — reads, aggs, pipelines, mixed, kNN, storage 55 wins26 ties · 4 losses · 3 n/a WINscorecard — one win is honestly a draw; the page says which
Server round-trip, size:0 over 300k docs, keep-alive client 0.126 msES 0.283 ms 2.2×scorecard · read transport
Bulk ingest, identical corpus and box 1.72× higherES baseline WINscorecard
On-disk size, same docs 176.2 MBES 283.0 MB 1.61× smallerscorecard · storage caveats apply
kNN k=10, HNSW-served with exact rescoring 1.76 msES 2.08 ms TIE (1.18×, inside noise)scorecard — recall is measured, never assumed
Identifier lookup, one index, 15-repo code corpus (p50 of 21) 11.7 msZoekt (Sourcegraph) 15.3 ms · ripgrep cold 260 ms WIN per-index2026-08-29 session, same box, released rc.70 binary
Mixed read-under-write p99, 40k docs/s iso-load writer 10.3–13.6 msES 3.5–6.8 ms 4 LOSSESscorecard · root-caused to a lock, fix targeted
HEAD-TO-HEAD · THE TOOLS A DEV MACHINE ACTUALLY RUNS · 15 REPOS · 154 MB · SAME BOX, SAME HOUR
DimensionXERJ rc.70/71Zoekt (Sourcegraph)ripgrepWhat it means for you
Identifier search, p50 11.7 ms (one index)15.3 ms260 ms cold An agent that retrieves 50 times in a session waits ~0.6 s total, not 13 s — retrieval stops being the slow step in the loop.
— across all 41 datasets today 701 ms15.3 ms260 ms Our multi-index fan-out is serial today — measured, filed, fix scoped (#875: expected ~20–30 ms).
Exact phrase, p50 829 ms (fan-out)37.9 ms200 ms Same #875 fan-out defect; the per-index engine is competitive once the query reaches it.
Regex over source not offered870 ms180 ms Nobody owns this today — Zoekt's regex loses to cold grep at this corpus size. A trigram side-car is on our roadmap precisely because the category is open.
Index 15 repos 676 s + merge tail302 s0 s (no index) XERJ's indexer does strictly more work — AST symbols in 13 languages and graph edges, not just trigrams — but the merge tail is a defect, not a feature (#876).
Idle daemon, this corpus 8% CPU · 8.3 GB0.03% · 119 MBnone Today's honest loss. Root-caused to three mechanisms with a published budget — idle under 0.5% of one core at any index count (#874).
Symbol / definition ranking built in, 13 languagesneeds universal-ctags installednone One binary gives your agent definition-first ranking with no sidecar toolchain to install or keep in sync.
Beyond code search ES wire · aggregations · kNN vectors · agent memorycode search onlygrep only The same daemon that answers your agent's code lookups holds its logs, vectors and memory — one thing to run instead of three.

Method: released XERJ binaries, Zoekt built from source at HEAD, ripgrep 14.1.1; identical 15-repo corpus (memcached, valkey, tantivy, regex, zstd, CRoaring, …), p50 of 21 requests per cell, CPU and RSS from /proc. Zoekt indexed serially per its defaults; XERJ's indexer also extracts AST symbols and graph edges, which Zoekt does not attempt — stated so the wall-clock rows are read fairly. Result quality (ranking, symbol precision) is not scored here.

The losses, on purpose. Four cells on the Elasticsearch board — read p99 under a 40,000 docs/s writer — are red, root-caused on the scorecard to reader starvation on a live memtable lock. Against Zoekt, today's red cells are multi-repo fan-out, indexing wall-clock, and idle footprint — every one measured above, filed the same day with the mechanism at file:line (#871–#876). That is the deal this page offers: competitors are named, the red cells get the same precision as the green ones, and each red cell links to its fix.
02·RETRIEVAL · CODE THE MODEL DOESN'T KNOW

CORRECT WHERE
MEMORY FAILS.

The retrieval claim is not "search is nice" — it is that retrieval makes the same model correct on APIs it has never memorised. Measured across 13 purpose-built libraries in 5 languages (unfamiliar by construction, so the model cannot bluff), with hidden-test verdicts and real token accounting from claude -p.

TASKS SOLVED · 21 RUNS · UNFAMILIAR CONTRACT DOMAINS
bare — model memory only XERJ — reference retrieved
1 / 21
21 / 21
bareXERJ
Unfamiliar APIs — compiles + passes a hidden test
0 / 9
9 / 9
bareXERJ
Hardest single library (sift, streaming sketch)

Method, per-library table, and every per-run record: the reference-coding case study · docs/case-studies/reference-coding

03·RANKING QUALITY · PUBLIC DATASETS, NEURAL MODE

FUSE FIRST.
JUDGE WHAT'S LEFT.

Two questions, both answered on public datasets anyone can download. How much does hybrid retrieval add over BM25? And how many routing and spam decisions can labelled history settle with no model call at all? Every vector and hybrid figure in this section was measured with --embed-mode neural and the built-in all-MiniLM-L6-v2 model — not with the default embedder, which is lexical feature hashing and has no model in it. The BM25 rows use no embedder and hold on any node. The Jev rows below are written up verdict-first — wins, losses, and the judge's bill — in the blog post: does XERJ beat JEV?

nDCG@10, BEIR test splitSciFact · 300 q · 5,183 docsNFCorpus · 323 q · 3,633 docsFiQA · 648 q · 57,638 docsRun by
XERJ BM25 (multi_match, no embedder) 0.65720.30160.2382us · any node
XERJ MiniLM vectors only (semantic) 0.67640.3291not runus · --embed-mode neural
XERJ BM25 top-30, reordered by MiniLM 0.68550.3323not runus · --embed-mode neural
XERJ hybrid RRF (hybrid, server-side) 0.69930.3448not runus · --embed-mode neural
XERJ BM25 top-30, reordered by Jev (jev-1.13.0, pinned) 0.74100.33120.3638us · median of 3 repeats — the write-up
Jev (TypeSafe AI), hosted reranker 0.7680.358no figurenot run by us — published in the hev/jev-rerank README
Voyage rerank-3, hosted reranker 0.7550.357no figurenot run by us — same README
Cohere rerank-v3.5, hosted reranker 0.7450.340no figurenot run by us — same README
Decisions from labelled history · k = 10 · held-out itemsAccuracyCalibration errorDecided at confidence ≥ 0.8ms / item
Banking77, 77-way intent routing · 1,000 items — BM25, no model of any kind 0.8190.08950.6% at 0.9962.2
Banking77 — MiniLM neighbours (--embed-mode neural) 0.9330.01286.9% at 0.9798.6
Banking77 — hybrid RRF (--embed-mode neural) 0.9370.05279.2% at 0.98912.4
SMS spam, yes / no · 1,000 items — BM25, no model of any kind 0.9830.01795.4% at 0.9920.9
SMS spam — MiniLM neighbours (--embed-mode neural) 0.9820.00995.8% at 0.98974.5
SMS spam — hybrid RRF (--embed-mode neural) 0.9890.01595.7% at 0.99767.2
AG News, 4-way topic · 7,600 items · 120,000-deep history — BM25, no model of any kind 0.91820.01983.1% at 0.966934.2

Scripts, raw output and reproduce commands: benchmarks/beir-hybrid · benchmarks/decisions-as-retrieval · run 2026-09-18 on xerj v1.0.0-rc.74 · AG News 2026-09-20 on the wire-compat branch engine (cf6a9989) · written up in hybrid search quality and decisions without a model call. Hosted-reranker figures: hev/jev-rerank (MIT) · the measured Jev rows and the System One wire: blog/does-xerj-beat-jev.

04·TOKEN SAVINGS · REAL ACCOUNTING, NO API KEY REQUIRED

THE TOKENS YOU
DON'T SPEND.

Output tokens are the expensive kind — priced roughly 5× above input on Claude models — and retry loops on unknown APIs burn exactly those. Three arms of the same agent on the same tasks: memory only, grep-driven, retrieval-injected. Every figure from claude -p --output-format json.

8 TASKS × PYTHON / JS / C / JAVA · 16 RUNS PER ARM
bare — memory only native — greps the source XERJ — reference retrieved
260,916
26,477
9,982
barenative XERJ2.7× fewer than native
Output tokens to solve — lower is better
$11.18
$3.27
$1.58
barenative XERJ7.1× cheaper than bare
Cost per matrix — real per-run pricing

The per-language medians run 6.7× (JavaScript) to 278× (Java) fewer output tokens than answering from memory. An independent 12-question dev-QA measurement on the engine's own reference corpora lands at 1.65× fewer output tokens and 1.47× cheaper — smaller, because it includes questions where the model already knew the answer; both numbers are published.

WHERE TOKENS GO WITHOUT RETRIEVAL

  • Retry loops. Invent a method name, fail to compile, loop — output tokens on every lap. Measured worst case: 27,108 tokens and a failing test.
  • Context stuffing. Grep recovery pulled up to 1.06M input tokens of source into context for one corpus.
  • Compiler archaeology. "Did you mean" recovers a name at 20–150× the tokens — and never a runtime rule.

WHERE THEY GO WITH IT

  • One query. A multi_match over defs/body/title, ~10 ms server-side.
  • One passage. The definition, its contract, its file:line — hundreds of tokens, not hundreds of thousands.
  • Measured floor. The same Java task that burned 27,108 tokens from memory: 98 tokens with the reference in hand. 278× fewer.
05·ZTA · THE DESIGN BEHIND THE NUMBERS

ZERO-TOKEN
ARCHITECTURE.

The cheapest token is the one your model never generates. ZTA is the design rule that produced every number above: spend compute once, at index time, so agents stop spending inference tokens — the metered, per-request, 5×-priced resource — re-deriving what the index already knows. It is an architecture target with measured proxies, not a certification; here are its four principles and the number that keeps each one honest.

ZTA-1

UNDERSTAND AT INDEX TIME

proxy: ~1,500 files/s extract · ~100× unchanged re-index

Parse the AST once — 13 languages, every symbol with kind and line, a ranked defs field — instead of letting every future question re-derive structure with tokens. Index-time compute is bought once; token-time compute is bought on every question, forever.

ZTA-2

ANSWER WITH THE PASSAGE, NOT THE CORPUS

proxy: 98-token solve vs 27,108 · 1.06M-token grep avoided

The unit of answer is the definition with its contract and file:line — never "here are eleven files, good luck." Small answers keep the agent's context small, which compounds: every later turn re-pays for everything already in the window.

ZTA-3

THE AGENT SETS ITSELF UP

proxy: one pasted line → verified end-to-end run

Setup instructions live at llms.txt in machine order: install, start, index, query, retrieval discipline. One pasted sentence turns it on — tested verbatim, transcript published. Zero tokens spent negotiating with documentation written for humans.

ZTA-4

IDLE COSTS NOTHING

proxy: budget < 0.5% of a core at any index count, published (#874)

An always-on corpus next to your agents must not tax the machine they work on. Zoekt sets the bar at 0.03% — the head-to-head above shows we are not there yet, and instead of hiding that, the remaining idle mechanisms are located, filed, and budgeted in public (#874). The rule the codebase now enforces: no per-index periodic work, ever.

Why this is the sales pitch and not a slogan: infrastructure used to compete on latency; agent infrastructure competes on your inference bill. A retrieval that answers in 10 ms and a few hundred tokens replaces a 15,000-token retry loop every time it fires — the $21.90 → $3.38 delta above is that substitution, measured 21 times over. ZTA is the commitment that every future XERJ feature is judged by the same question: how many tokens does it stop your model from spending?

RUN THE NUMBERS ON YOUR CODE.

THE FULL ES SCORECARD → THE TOKEN CASE STUDY GET XERJ