Form B · measured 2026-08-24
Every number, and where it came from.
recall publishes its benchmarks in full, including the slow ones. Every figure below runs against a corpus generated from a fixed seed rather than anybody’s session store, so the same three commands reproduce this page on your machine.
- 7/7
- wall-clock gates inside budgetthe harness fails the build otherwise
- 9×
- the tightest margin of the sevencold archive build
- 0.8 ms
- to search every tier of a 50 MB storeconversation, tool commands and tool output
- 8.5 ms
- for the whole binary, start to exitprocess spawn, search, render, exit
git clone https://github.com/mayberuk/recall && cd recall
make bench # writes bench/RESULTS.md, the source of this page
make bench-gate # the wall-clock ceilings alone, which is the quick checkMeasured on AMD Ryzen 7 5700X3D 8-Core Processor · 16 cores · linux/amd64 · go1.25.4. The same figures as plain markdown, or in the repository at bench/RESULTS.md.
The ceilings, and the distance to them
A gate is a wall-clock limit that fails the build when it is crossed. What matters is not the measurement but the gap: the margin is what has to survive a year of changes, and the tightest of the seven is 9×.
- find, conversation tier medium corpus limit 250 ms0.3 ms 833× under
- find, all tiers medium corpus limit 1200 ms0.8 ms 1500× under
- cold strip of the whole corpus medium corpus limit 4000 ms185 ms 22× under
- cold archive build medium corpus limit 4000 ms468 ms 9× under
- incremental archive update medium corpus limit 1500 ms0.6 ms 2500× under
- archive load, conversation tier medium corpus limit 195 ms1.3 ms 150× under
- archive load, all tiers medium corpus limit 890 ms5.7 ms 156× under
The bar is the measurement drawn against its own ceiling. Six of the seven are too small to see at this scale, which is the point of drawing them.
The binary, end to end
Process spawn to exit, for every command and every flag that changes the shape of the work. Small is about 5 MB of transcript; medium is about 50 MB. The output bytes column is what an agent pays to read the answer.
| Command | 5 MB store | 50 MB store | Output | Peak RSS |
|---|---|---|---|---|
| recall find bare | 4.0 ms | 8.5 ms | 484 B | 111 MB |
| recall find --all | 3.9 ms | 8.2 ms | 485 B | 111 MB |
| recall find --results | 6.3 ms | 16.3 ms | 461 B | 111 MB |
| recall find --tools | 4.3 ms | 14.7 ms | 494 B | 111 MB |
| recall find --brief | 3.7 ms | 8.3 ms | 383 B | 111 MB |
| recall find --json | 4.3 ms | 8.0 ms | 1,501 B | 111 MB |
| recall find --format jsonl | 3.7 ms | 8.1 ms | 1,041 B | 111 MB |
| recall find --ids | 3.9 ms | 8.1 ms | 37 B | 111 MB |
| recall find --all-terms | 3.9 ms | 8.3 ms | 484 B | 111 MB |
| recall find --not | 3.8 ms | 8.3 ms | 534 B | 111 MB |
| recall find --since | 3.9 ms | 8.1 ms | 537 B | 111 MB |
| recall find --author | 3.8 ms | 8.1 ms | 537 B | 111 MB |
| recall find --repo | 3.9 ms | 8.2 ms | 484 B | 111 MB |
| recall find --limit | 3.6 ms | 8.1 ms | 484 B | 111 MB |
| recall find --words | 4.0 ms | 9.1 ms | 513 B | 111 MB |
| recall find --all --words | 4.7 ms | 12.2 ms | 517 B | 111 MB |
| recall turns bare | 3.8 ms | 7.8 ms | 544 B | 111 MB |
| recall turns --budget | 3.7 ms | 7.9 ms | 544 B | 111 MB |
| recall turns --brief | 3.8 ms | 8.1 ms | 371 B | 111 MB |
| recall show bare | 3.7 ms | 7.7 ms | 8,203 B | 111 MB |
| recall show --chars | 3.8 ms | 7.9 ms | 2,454 B | 111 MB |
| recall when | 3.7 ms | 7.9 ms | 567 B | 111 MB |
| recall doctor | 44.6 ms | 321 ms | 797 B | 295 MB |
| recall guide | 2.7 ms | 2.7 ms | 3,455 B | 111 MB |
The one row that is not fast is recall doctor at
321 ms, and it is supposed to be: doctor verifies every frame of every
tier and re-reads the corpus to compare it against the archive. It is the only command with
no latency gate, because nobody runs it inside a loop.
Inside the process
The Go benchmarks, grouped by what they measure. Allocation counts are gated separately:
make bench-compare fails on a regression against a committed baseline,
which is why the numbers in the last column are worth printing at all.
Archive
| Case | Time | Allocated | Allocations |
|---|---|---|---|
| medium/cold | 202 ms | 498.4 MB | 634,105 |
| medium/warm | 472.0 µs | 169.3 KB | 889 |
| small/cold | 25.2 ms | 58.6 MB | 64,401 |
| small/warm | 248.0 µs | 65.8 KB | 436 |
Load
| Case | Time | Allocated | Allocations |
|---|---|---|---|
| medium/all-tiers | 5.0 ms | 51.2 MB | 95 |
| medium/conversation | 1.0 ms | 8.7 MB | 30 |
| small/all-tiers | 1.3 ms | 5.1 MB | 57 |
| small/conversation | 281.4 µs | 869.4 KB | 17 |
Rank
| Case | Time | Allocated | Allocations |
|---|---|---|---|
| medium/collapse | 3.4 ms | 6.8 MB | 66 |
| medium/score | 14.0 ms | 23.2 MB | 1,813 |
| small/collapse | 339.4 µs | 745.6 KB | 10 |
| small/score | 1.4 ms | 2.3 MB | 460 |
Search
| Case | Time | Allocated | Allocations |
|---|---|---|---|
| medium/conjunction | 3.2 ms | 28.4 MB | 526 |
| medium/miss | 2.4 ms | 115.2 KB | 378 |
| medium/phrase | 483.0 µs | 211.4 KB | 345 |
| medium/relaxed | 387.4 µs | 47.5 KB | 273 |
| medium/single-common-term | 1.5 ms | 13.4 MB | 476 |
| medium/single-term | 344.1 µs | 46.6 KB | 261 |
| medium/single-term-all-tiers | 822.6 µs | 76.1 KB | 274 |
| small/conjunction | 827.0 µs | 1.4 MB | 67 |
| small/miss | 1.3 ms | 9.4 KB | 55 |
| small/phrase | 254.8 µs | 16.2 KB | 48 |
| small/relaxed | 152.2 µs | 5.0 KB | 53 |
| small/single-common-term | 420.5 µs | 610.6 KB | 56 |
| small/single-term | 128.0 µs | 4.3 KB | 43 |
| small/single-term-all-tiers | 476.1 µs | 7.0 KB | 44 |
Strip
| Case | Time | Allocated | Allocations |
|---|---|---|---|
| medium/cold | 188 ms | 126.0 MB | 424,799 |
| medium/incremental | 13.6 ms | 59.4 MB | 4,226 |
| small/cold | 19.7 ms | 24.5 MB | 42,560 |
| small/incremental | 3.1 ms | 17.9 MB | 296 |
StripRecord
| Case | Time | Allocated | Allocations |
|---|---|---|---|
| medium | 5.3 µs | 2.9 KB | 18 |
| small | 5.4 µs | 2.8 KB | 18 |
What was measured against
A session store generated from a seed, never a private one. The generator reproduces the tier shape of a working store: conversation, tool commands and tool output hold 20.0% / 40.5% / 39.5% of the turns and 16.1% / 8.4% / 75.5% of the bytes, and every corpus lands within 2% of each of those six shares.
| Corpus | Files | On disk | Turns | Conversation | Tool commands | Tool output |
|---|---|---|---|---|---|---|
| small | 17 | 5.1 MB | 2,972 | 594 turns / 0.6 MB | 1,189 turns / 0.3 MB | 1,189 turns / 2.9 MB |
| medium | 56 | 51.4 MB | 29,564 | 5,898 turns / 6.0 MB | 11,833 turns / 3.1 MB | 11,833 turns / 28.5 MB |
The caveat this page will not bury. The generator is denser than a real store: about 72% of its on-disk bytes strip into text, where a real store measured at 1,402 MB of JSONL yielded only 244 MB, roughly 17%. The tier ratio still holds, so comparing an all-tier figure against its conversation-tier neighbour is sound. An absolute figure like a cold strip time does not transfer directly, because 50 MB of this corpus holds several times the searchable text that 50 MB of a real store does. The 30 ms on the front page is a different measurement entirely: one developer machine, 143 real conversations, 1.52 GB.