CASE STUDY · REFERENCE-CODING

REFERENCE CODING MAKES CLAUDE CODE
6.5× CHEAPER — MEASURED.

When a coding agent meets an API it does not know, it guesses, fails, and guesses again — each lap burning the expensive kind of token. Reference-coding fixes that: clone the libraries that already solved your problem, index them with XERJ, and retrieve the real implementation before writing code. Measured across 13 purpose-built libraries in 5 languages against the same Claude Code: on code it has not memorised, plain Claude Code solved 1 of 21 tasks and burned $21.90 doing it — with XERJ retrieval it solved 21 of 21 for $3.38. Same model, same tasks — only the retrieval differs. Paste the one line below to turn it on. Every number behind it is underneath, including where retrieval is worth nothing.

PASTE THIS TO YOUR AI AGENT — IT DOES THE REST Install XERJ (docs: https://xerj.org/llms.txt), index this project's sources, and set up reference coding: clone and index the open-source repos closest to what we're building, and search how they solved a problem before writing code.
We tested this exact prompt end-to-end — see Verified: the prompt works below. Full text: OPENER_PROMPT.md →. It drove the loop through xc-corpus.sh / xc-index.sh / xc.py — at the time, internal wrappers from the maintainers' own agent skill. They now ship at tools/xerj-code/, but nothing requires them: they are thin shells around git clone --depth 1, xerj autoindex, and one multi_match query, and Do it yourself below runs the same method with plain commands.
MEASURED · 8 TASKS × PYTHON / JS / C / JAVA · 16 RUNS PER ARM · REAL OUTPUT TOKENS FROM claude -p
bare — memory only native Claude Code — greps the source XERJ — reference retrieved
260,916
26,477
9,982
bare native XERJ2.7× fewer than native
Output tokens to solve — lower is better · shared scale
11
16
16
bare native XERJ
Tasks solved — compiles + passes a hidden test · out of 16

bare = Claude Code with tools off (memory only) · native CC = Claude Code as-is, greps the source · XERJ = the SAME agent, reference retrieved and injected · cost $11.18 / $3.27 / $1.58 · NOT A LATENCY BENCHMARK

THE MEMORISATION WALL

THE THREE-STEP LOOP

HOW IT WORKS, IN DEPTH.

EVERYTHING WE BUILT TO TEST IT.

You cannot measure retrieval on code the model has memorised — it reproduces even a 256-value table from memory. So the unfamiliar corpus is 13 real libraries written for this study (each compiles and passes its own tests), each carrying a runtime contract the compiler cannot warn about. Each task returns the library's own type, so a hand-rolled workaround cannot pass. bare = from memory; XERJ = same model, reference retrieved.

LibraryLangDomainThe contract you can't guessbareXERJtokens bare→XERJ
siftRuststreaming sketchconservative-update count-min; seal before any read0/99/917,350 → 796
groveRustarena allocatorgenerational handles — freed handle stays stale after reuse0/22/215,233 → 1,236
weftRustlexerbuilder → weave → scanner; maximal munch1/22/216,112 → 610
tallyRustfixed-point decimalbanker's rounding (round half to even)0/22/215,599 → 892
spoolRustring bufferpush returns the evicted item; power-of-two capacity via shift2/2*2/215,974 → 656
cadenceRustrate limitertoken bucket, lazy refill only on advance0/22/218,162 → 744
quillRustvarint codeczig-zag + LEB128 (a memorised convention)2/22/21,355 → 999
trellisRusttopological sortsmallest-index tie-break; exact cycle-node set on failure0/22/221,317 → 782
sieveRustbloom filterKirsch–Mitzenmacher double hashing; settle before sense0/22/213,817 → 669
wardenPythonLRU cachefetch promotes to most-recent; overflow evicts LRU3/4*4/415,370 → 240
garnerJavaScriptprefix triestored word vs bare prefix (a known structure)4/44/44,360 → 667
arenaCgenerational allocatoropaque handle; stale after slot reuse2/4*4/418,730 → 1,489
ledgerJavaappend-only logmust seal before replay; checkpoint truncation2/44/426,767 → 97

* bare "passes" some cases by recovering an API name from a compiler/runtime error at 20–150× XERJ's tokens, or because the task spec necessarily stated the one non-obvious rule — never by recalling a genuine runtime contract. On the two memorised cases (quill varint, garner trie) the model already knows the algorithm and retrieval saves nothing — which is the point of including them. Source for every library: docs/case-studies/reference-coding →

THE LINE IS SHARP.

Two controls on real, public code the model has trained on — valkey + memcached (a KV server), and tantivy (a search engine) — pin down exactly where retrieval stops paying. The value is gated by memorization.

UNFAMILIAR · 7 CONTRACT DOMAINS · 21 RUNS · TOTAL COST
$21.90
$4.26
$3.38
bare1 / 21 solved native21 / 21 solved XERJ21 / 21 solved

RETRIEVAL WINS: correct where memory fails, 6.5× cheaper than bare, 1.3× cheaper than native.

MEMORISED · valkey + memcached · 6 RUNS · TOTAL COST
$1.49
$9.14
$4.40
bare6 / 6 solved native6 / 6 solved XERJ5 / 6 solved

RETRIEVAL LOSES: the model knows the protocol, so pure memory is cheapest; searching or injecting a reference is overhead.

EVERY LANGUAGE, SAME SHAPE.

Median output tokens to solve, XERJ vs answering from memory. Verdict is the real toolchain in each language (python3, node, cc, javac).

bare — memory only XERJ — reference retrieved
14,752
214
bare XERJ69× fewer
Python — LRU cache (warden)
4,300
646
bare XERJ6.7× fewer
JavaScript — prefix trie (garner)
18,792
988
bare XERJ19× fewer
C — generational allocator (arena)
27,108
98
bare XERJ278× fewer
Java — append-only log (ledger)

Each pair is drawn against its own bare baseline, because the four libraries differ by two orders of magnitude in absolute cost — the comparison that matters here is within a language, not across them. Absolute medians are printed on every bar.

THE SAME TASK, TWO WAYS.

One Java task: build an append-only ledger that must be sealed before replay, truncated to a checkpoint. bare cannot read the library, so it reinvents the whole thing — 503 lines — and still fails the seal contract. XERJ, handed the reference, writes it in four lines and cites the rule it learned:

bare · 503 LINES · ~36,000 TOKENS · FAILED
// reinvented an entire append-log + checkpoint + seal
// state machine from memory, guessing the API surface …
// 503 lines … wrong truncation semantics
// → hidden test FAILED.
XERJ · 4 LINES · 103 TOKENS · PASSED
public static Ledger upTo(long[] vals, long seq) {
    Ledger l = Ledger.open();
    for (long v : vals) l.append(v);
    l.checkpoint(seq);   // keep 0..seq
    l.seal();            // required before replay
    return l;
}

CAPTURED VERBATIM · docs/case-studies/reference-coding/generated →

VERIFIED: THE PROMPT WORKS.

We ran the opener above verbatim on a fresh task — implement a top-3 heavy-hitters function using the unfamiliar sift crate (whose API is not new()/push()/top_k()). Following the prompt, Claude Code indexed the reference, retrieved sift's real API, and wrote code that compiles and passes a hidden test — using furnish / absorb / seal / crest, the seal-before-read contract a from-memory attempt cannot recover. The full transcript and the generated program are in the repo.

REPRODUCE THE VERIFICATION ITSELF · docs/case-studies/reference-coding →

DO IT YOURSELF.

Four commands, no tooling beyond the xerj binary and git. The method works on any repository — including your own private code, which is the real use case.

  1. Start XERJ. xerj -d ./.xerj-data --insecure & — the ES-compatible API comes up on :9200. autoindex is a client of a running node; without one it exits 1.
  2. Build a corpus. git clone --depth 1 https://github.com/tokio-rs/tokio ref/tokio (and the same for each peer) — group by problem domain, not language.
  3. Index it. xerj autoindex ref/tokio — a 100k-record tree indexes in ~10 s; re-run when the references change and the journal makes it incremental.
  4. Retrieve before you write. One query against the new indices returns the matching definition with file:line:
    curl -sXPOST 'localhost:9200/ax-*/_search' -H 'content-type: application/json' \
      -d '{"size":3,"query":{"multi_match":{
            "query":"graceful shutdown with a broadcast channel",
            "fields":["defs^3","body","title"]}}}'
    defs, symbols, body, title and language are the fields autoindex writes for source files. ax-* matches every dataset on the node, your own project included — check GET /_cat/indices after each index run and narrow the pattern to the reference datasets when you want your own code kept out of the results.
  5. Or let the wrappers do it. xc-corpus.sh / xc-index.sh / xc.py ship in the repo at tools/xerj-code/ and wrap exactly the four steps above. They add a corpus definition: xc-corpus.sh --from hub/xerj-search.json rebuilds a corpus someone already vetted — URLs, pinned commit SHAs and licences; no source, so nothing to redistribute, and the same file gives two machines the same bytes.
  6. Measure it honestly. Three arms of the same agent — memory only, grep-driven, retrieval-injected — one hidden-test verdict, real tokens from claude -p --output-format json, no API key. The numbers and every per-run record are in CASE_STUDY.md; the harness itself is not shipped.
Archive · the long-form opener this study measured, verbatim
Set me up for reference-coding with XERJ and then use it automatically for the
rest of our work, so I stop burning output tokens re-deriving APIs I could just
look up.

1. Make sure a local XERJ instance is running and the `xerj-code` skill is
   available. If XERJ isn't installed, get it from https://xerj.org/get
   (curl -fsSL https://xerj.org/get | sh) and start it.
2. Look at this project — its dependencies, the domains its code touches — and
   decide which well-known open-source libraries already solve those problems.
   Clone them into a reference corpus with the skill's xc-corpus.sh, grouped by
   problem domain, not by language.
3. Index that corpus with xc-index.sh (it runs `xerj autoindex`).
4. From now on, for every coding task this session: before writing non-trivial
   code against an unfamiliar or external API, first run
   xc.py <corpus> "<what you need>" to retrieve the real implementation, read the
   returned definition, and adapt it — cite file:line, check the licence. If
   retrieval returns nothing relevant, say so and fall back to normal work.
5. Re-index whenever the references change.

Do this proactively for the rest of the session without me asking again.

Kept for reproducibility, not as current instructions — the one-line prompt at the top of this page is what to use today.

WHAT WE WON'T OVERCLAIM.

01
ON MEMORISED CODE, RETRIEVAL IS OVERHEAD.
On popular public code the model has trained on — even a 256-value quantization table it reproduces from memory — bare is cheapest. Reference-coding pays on your private, proprietary, or genuinely unfamiliar code, not on library references the model already knows.
02
THE WIN IS MEASURED ON SYNTHETIC LIBRARIES.
The unfamiliar corpus is 13 libraries written for this study — unfamiliar by construction, so the model cannot bluff. A genuinely large private codebase is the honest end-state we have not yet measured; the native-vs-XERJ gap should grow there, because grep cost scales with the tree while retrieval stays flat.
03
WE TRIED TO IMPROVE THE SERVER AND MEASURED A NEAR-NULL.
We enriched XERJ's index (richer symbols + identifier sub-word splitting) and measured it against the old server. On realistic queries it barely moved ranking, because the references carry enough prose for lexical BM25 to saturate. The robust win is retrieval-vs-none, which both server versions deliver equally. Full scorecard published.

POINT IT AT YOUR CODE.

READ THE FULL CASE STUDY → GET XERJ