semlith
Benchmarks

Measured in public, win or lose.

Public code-retrieval benchmarks, run by semlith's own harness (bench/scorecard) on one M1 MacBook Air in October 2026 and published as measured, including where another tool wins. Every number here is the scorecard semlith 0.44.1 publishes, and the command under each table reproduces it.

The headline

Benchmarksemlithbaselineinstances
SWE-bench Verified, right file in the top 1076.8 %47.0 % grep then read500
SWE-bench Lite, right file in the top 1072.3 %47.3 % grep then read300
SWE-bench Verified, median tokens to the first right file22415 491 grep then read500
CodeRAG-Bench DS-1000, NDCG@100.2600.158 BM25513
Agents (Opus), cost per correct answer$0.065$0.072 grep only50 × 3 runs
Documents (PDF, Office, EPUB, …), passage found within 4k tokens116/12734/127 rga127
Agents (Opus) on those documents, passage found124/12780/127 grep only127
Real sessions, tokens sent against whole files read75.2× fewer1,575 retrievals

Run on one M1 MacBook Air (4P+4E, 8 GB), indexing on its Neural Engine. SWE-bench and the competitor table ran on the 0.38.0 build; CodeRAG-Bench, RepoBench-R and the agent round ran on 0.36.0, whose search path is the same for these image-free corpora; the documents round ran on 0.44.1. Each figure is the median of the runs named, with the spread when it is not zero.

The baselines are what an agent does without semlith. BM25 ranks the files one ripgrep pass hits; grep then read reads up to twenty of them whole, in that order. "Tokens" are bytes returned divided by four, up to the first gold file.

SWE-bench, retrieval only

The issue is the query; the gold is every file the reference patch edits; each instance is indexed at its own base commit.

setarminstancesfile hit@1@5@10all gold @10first gold within 4k tokensmedian tokens to first gold
Litegrep then read30018.7 %37.3 %47.3 %47.3 %22.3 %8813
Litesemlith30035.7 %59.0 %72.3 %72.3 %69.3 %225
Verifiedgrep then read50016.8 %37.6 %47.0 %42.2 %20.4 %15491
Verifiedsemlith50036.6 %64.8 %76.8 %70.4 %77.4 %224

uv run --with pyarrow python bench/scorecard/swe.py walk && uv run --with pyarrow python bench/scorecard/swe.py score <run dir>...

Nine other tools, SWE-bench Lite

The same base-commit checkouts and issue text for every tool, on a seeded random sample of SWE-bench Lite; semlith beside each tool on exactly the instances that tool completed (all runs without an error). A tool whose cumulative indexing passed 4x semlith's is stopped and its remaining instances are "not run".

toolversioncompletedfile hit@1@5@10first gold within 4k tokenssemlith hit@5, same instancessemlith within 4k, same instancesnot run
rg15.2.020/200.0 %15.0 %15.0 %15.0 %55.0 %60.0 %—
ugrep7.8.520/200.0 %15.0 %15.0 %15.0 %55.0 %60.0 %—
semble0.6.120/2035.0 %50.0 %70.0 %70.0 %55.0 %60.0 %—
graphify0.9.7420/2020.0 %35.0 %50.0 %65.0 %55.0 %60.0 %—
serena1.7.016/2018.8 %25.0 %25.0 %37.5 %56.2 %62.5 %4: search: TimeoutError
sourcebot5.1.1520/2020.0 %35.0 %35.0 %30.0 %55.0 %60.0 %—
grepai0.37.00/20——————19: not run: index budget; 1: index: TimeoutError
colgrep1.7.00/20——————19: not run: index budget; 1: index: TimeoutExpired
ck0.7.110/20——————19: not run: index budget; 1: index: TimeoutExpired
semlith, every instance2030.0 %55.0 %60.0 %60.0 %

cd bench/scorecard && python3.11 competitors_swe.py walk && python3.11 competitors_swe.py score (the slow tools in their own --out with SEMLITH_VECTOR_CACHE_MB=0, scored with --also; see bench/scorecard/README.md)

Agents on an unfamiliar codebase

Headless Claude Code on 50 held-out questions generated from the code of a 70-repository corpus (not a public set: Opus has memorised SWE-bench Lite, bench/scorecard/agent/contamination.md).

modelarmrunsquestionscorrectcost / sessioncost / correct answermedian input tokenssessions calling semlith
opusgrep (Grep, Glob, Read)35092.0 % ±2.0 %$0.068 ±$0.007$0.072 ±$0.00817910 ±3390
opussemlith installed, Grep built in35092.0 % ±2.0 %$0.061 ±$0.005$0.065 ±$0.00522541 ±11970 ±1
opussemlith installed, Grep gated to semlith first35096.0 % ±2.0 %$0.076 ±$0.006$0.080 ±$0.00830790 ±215945 ±6
haikugrep (Grep, Glob, Read)25086.0 % ±4.0 %$0.081 ±$0.003$0.099 ±$0.00860523 ±33160
haikusemlith installed, Grep built in25090.0 % ±2.0 %$0.076 ±$0.003$0.086 ±$0.00597593 ±1559047
haikusemlith installed, Grep gated to semlith first25088.0 % ±2.0 %$0.082 ±$0.018$0.095 ±$0.02294681 ±475542 ±2

python3 bench/scorecard/agent/corpus_round.py

Documents in 11 formats

127 questions about passages inside 53 public documents fetched from their publishers' own URLs, in 11 formats: PDF, Word, PowerPoint, Excel, OpenDocument text, sheets and slides, EPUB, RTF, notebooks and CSV (two mailing-list archives sit beside them, with no questions). A passage is found when a delivered excerpt is in the gold document and shares a run of six words with the gold passage, whichever extractor produced it.

armrunsfound within 2k tokens4k8kright document within 4kmedian tokens to the first find
rg, BM2536/1277/1279/12715/1271416
rga (rg with document adapters), BM25328/12734/12741/12777/1271008
semlith_search, k 503114/127116/127121/127127/12711
semlith_brief380/12780/12780/127126/12716

python3 bench/scorecard/documents/documents.py run && python3 bench/scorecard/documents/documents.py score <run dir>

Agents on those documents

Headless Claude Code on the same questions; the answer is up to five documents, each with a quote. A quote that shares no six-word run with the text semlith extracted from the document it names was written, not read.

modelarmrunsquestionsfoundcost / sessionsessions calling semlithtop quotes not in the named document
opusgrep (Grep, Glob, Read)112780/127$0.067—41 of 127
opussemlith installed, Grep built in1127124/127$0.0431270 of 126
opussemlith and Read only1127122/127$0.0421270 of 123

python3 bench/scorecard/documents/agent_round.py run g,s,sx && python3 bench/scorecard/documents/agent_round.py score

CodeRAG-Bench, retrieval

Each task's canonical corpus and gold documents.

taskqueriesNDCG@10 BM25NDCG@10 semlithRecall@10 BM25Recall@10 semlith
ds10005130.1580.2600.2460.379
humaneval1640.9930.9951.0001.000
mbpp5000.9730.9991.0001.000
odex2010.0810.1910.1490.292
repoeval3730.7350.6830.4960.485

uv run --with pyarrow python bench/scorecard/coderag.py run --out ~/semlith-bench/scorecard/results/coderag/full

RepoBench-R

The query is the last keep lines of the in-file code; the candidates are the instance's own cross-file snippets. A seeded sample of 500 instances per configuration and level (seed 20261003) of the 48 000-instance test split.

settinglevelkeepinstancesacc@1 BM25acc@1 semlithacc@5 BM25acc@5 semlith
java firsteasy350016.2 %16.8 %81.6 %83.4 %
java firsteasy1050013.4 %12.2 %80.4 %82.8 %
java firsthard350010.2 %11.2 %43.2 %51.0 %
java firsthard105008.6 %7.6 %38.0 %44.6 %
java randomeasy350026.0 %28.0 %82.8 %87.4 %
java randomeasy1050022.6 %23.0 %84.2 %86.4 %
java randomhard350020.0 %19.2 %57.0 %63.8 %
java randomhard1050016.2 %17.2 %59.2 %58.8 %
python firsteasy350021.6 %25.2 %80.2 %85.0 %
python firsteasy1050019.0 %25.0 %79.8 %84.0 %
python firsthard350013.0 %18.0 %49.0 %49.6 %
python firsthard1050012.6 %16.4 %44.6 %51.8 %
python randomeasy350026.4 %29.8 %85.8 %87.8 %
python randomeasy1050027.0 %26.2 %85.6 %84.8 %
python randomhard350021.2 %28.6 %57.8 %62.4 %
python randomhard1050021.0 %22.8 %60.0 %60.0 %

uv run --with pyarrow python bench/scorecard/repobench.py run --out ~/semlith-bench/scorecard/results/repobench/full

Savings in real sessions

The owner's own ledger across 8 stores, benchmark stores excluded: 1,575 retrievals, 87 % credited (measured/modelled). The excerpts returned were 1,281,313 tokens; the whole files they came from, 96,399,209 — 75.2x across all stores, 50.7x for the median store. That comparison is an upper bound on what reading would have cost, not a measurement of it; the agent table is the head-to-head. Counted under 0.38.0's rules: from 0.42.0 the whole-file side of a PDF, an Office file, an EPUB, a notebook or an HTML page is the text the store holds for it rather than its bytes over four, which lowers the saving for document stores, and this figure was not re-measured under that rule.

python3 bench/scorecard/ledger_savings.py

Where semlith does not win

Semble edges it at hit@1 and hit@10 on the 20-instance competitor sample, BM25 beats it on CodeRAG-Bench's RepoEval, and with Grep built in Opus rarely reaches for semlith on its own.

Run it yourself

Everything above is produced by bench/scorecard in the open-source repository. Each run writes a MANIFEST.json naming its command, the semlith version, the measured binary's SHA-256, the machine and the SHA-256 of every result file. The scorecard page lists what you need, what it downloads, how long each run takes and the known limits of the method: RepoBench-R and the competitor arms run on seeded samples, and times are wall-clock on one loaded laptop, not results.