CASE STUDY · REFERENCE-CODING

STOP RE-DERIVING APIs.
START LOOKING THEM UP.

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. We measured it across 13 purpose-built libraries in 5 languages against the same Claude Code. Below is the one prompt that turns it on — and every number behind it.

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.
That is the current one-line setup — llms.txt walks the agent through the full loop. The measurement below ran the study's original long-form prompt.
◆ The exact prompt the study measured
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.
We tested this exact prompt end-to-end — see Verified: the prompt works below. Full text: OPENER_PROMPT.md →
MEASURED · 8 TASKS × PYTHON / JS / C / JAVA · 16 RUNS PER ARM · REAL OUTPUT TOKENS FROM claude -p
Output tokens to solve — lower is better
bare (memory)260,916
native CC26,477
XERJ9,982 · 2.7× < native
Tasks solved (compiles + passes a hidden test) — higher is better
bare11 / 16
native CC16 / 16
XERJ16 / 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
bare · 1/21$21.90
native · 21/21$4.26
XERJ · 21/21$3.38

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

MEMORISED · valkey + memcached · 6 RUNS · TOTAL COST
bare · 6/6$1.49
native · 6/6$9.14
XERJ · 5/6$4.40

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).

Python — LRU cache (warden)
bare14,752
XERJ214 · 69× fewer
JavaScript — prefix trie (garner)
bare4,300
XERJ646 · 6.7× fewer
C — generational allocator (arena)
bare18,792
XERJ988 · 19× fewer
Java — append-only log (ledger)
bare27,108
XERJ98 · 278× fewer

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.

The whole study reproduces from the repo. 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.
  2. Build a corpus. xc-corpus.sh async-rust https://github.com/tokio-rs/tokio https://github.com/hyperium/hyper — group by problem domain, not language.
  3. Index it. xc-index.sh async-rust — runs xerj autoindex; a 100k-record tree indexes in ~10 s.
  4. Retrieve before you write. xc.py async-rust "graceful shutdown with a broadcast channel" — returns the matching definition with file:line.
  5. Measure it honestly. The 3-arm harness (csrun.py, csmulti.py) runs bare / native / XERJ, one hidden-test verdict, real tokens from claude -p --output-format json — no API key. Full recipe in MEASURE / CASE_STUDY.md.

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