Skip to content

Benchmarks

We benchmark quality and speed across all methods on ~1,250 queries over 63 repositories in 19 languages.

Main Results

MethodNDCG@10Index timeQuery p50
semble0.854306 ms0.91 ms
CodeRankEmbed0.839116 s16 ms
ColGREP0.6935.4 s122 ms
BM250.67347 ms0.17 ms
zvec-grep0.6703.4 s391 ms
ck0.64296 s187 ms
codebase-memory-mcp0.630454 ms46 ms
grepai0.56135 s48 ms
probe0.387-207 ms
cs0.200-22 ms
ripgrep0.126-14 ms

Semble matches the NDCG@10 of the 137M-parameter CodeRankEmbed while indexing ~380× faster and answering queries ~17× faster, entirely on CPU.

NDCG@10 is averaged across all queries. Speed numbers use one repo per language, CPU only: cold-start index time and warm query p50 (median across 5 consecutive runs). The charts below plot latency against NDCG@10. Marker size reflects model parameter count.

Speed vs quality (cold start) Time to first result (index + query) vs NDCG@10

Speed vs quality (warm) Query latency on a warm index vs NDCG@10

Token Efficiency

Coding agents (Claude Code, OpenCode, etc.) typically find code by running grep on keywords and reading the matched files. We model that workflow and compare it against semble’s chunk retrieval across our full benchmark of 1,251 queries.

Token efficiency: recall vs. retrieved tokens

Expected tokens per query

For each query: tokens consumed at first relevant hit, or 32k if the method never finds anything. Averaged across all 1,251 queries.

MethodExpected tokensSavings
ripgrep + read file45,587baseline
semble34899% fewer

Recall at fixed token budgets

A relevant file is “covered” once any retrieved unit comes from it.

Method5001k2k4k8k16k32k
semble0.8420.9230.9670.9880.9950.9950.995
ripgrep + read file0.0010.0080.0370.0860.2070.3740.583
Methodology

Semble returns the top-50 ranked chunks. ripgrep+read splits the query into keywords (dropping stopwords and short words), runs rg --fixed-strings --ignore-case for each keyword, then reads matched files in full ranked by how many distinct keywords they contain. Both methods search the same set of file types and ignored directories. Tokens are counted with cl100k_base via tiktoken. A relevant file is “covered” once any retrieved unit overlaps its annotated span.

By Language

NDCG@10 per language, sorted by semble. CRE = CodeRankEmbed, cbm = codebase-memory-mcp. Best score per row is bolded.

LanguagesembleCREColGREPzvec-grepckcbmgrepaiprobecsripgrep
javascript0.9170.9250.8230.7600.7720.7700.6750.5880.1710.176
cpp0.9150.8970.6260.6770.6870.6300.7310.3750.2620.126
zig0.9130.9110.4740.6640.5110.7660.7550.3690.1210.000
scala0.9090.9250.7650.7990.7170.7040.3300.3920.1110.180
ruby0.9090.9050.7080.7580.7380.6890.6430.3820.2550.230
go0.8950.7130.7850.5120.4580.5060.7220.4100.1830.133
elixir0.8940.8930.8080.8110.7860.5060.6690.4120.3970.134
csharp0.8850.8480.6140.6090.5480.7750.2770.3920.2480.117
python0.8670.8780.7770.7040.7210.6430.6340.4880.3050.202
swift0.8600.8450.7100.7090.6720.6300.4290.2800.1510.160
php0.8580.8470.6630.5830.6150.6080.4020.3400.1800.123
rust0.8560.7540.6620.5410.4190.4540.5190.2420.1930.162
java0.8490.7900.6410.6850.6060.5540.3860.5360.1360.198
bash0.8250.8340.7060.7250.6770.7680.7230.2260.1700.000
lua0.8230.8290.7980.7360.7380.5910.6990.3360.0500.000
kotlin0.8210.8230.6370.6280.5870.6110.4780.3350.1700.166
haskell0.7650.8110.6830.6890.7330.6240.4830.3130.1600.000
c0.7410.7710.6760.5980.6060.6550.5550.3840.1750.000
typescript0.7060.6710.4300.4760.4560.4550.3940.3540.1450.128
overall0.8540.8390.6930.6700.6420.6300.5610.3870.2000.126

Ablations

raw returns retrieval scores directly; + ranking feeds them through semble’s hybrid ranker.

RetrievalRaw+ ranking
BM250.6750.834
potion-code-16M-v20.6500.821
BM25 + potion-code-16M-v2-0.854

By query category:

ModeArchitectureSemanticSymbol
BM25 raw0.6280.6760.719
potion-code-16M raw0.6260.6660.629
semble BM25 (+ ranking)0.7700.8190.957
semble potion-code-16M (+ ranking)0.7570.8080.943
semble hybrid0.8020.8460.958

Dataset

~1,250 queries over 63 repositories in 19 languages, grouped into three categories:

CategoryQueriesWhat it tests
semantic711Code that implements a specific behavior or concept
architecture343Design decisions, module boundaries, structural patterns
symbol204Named entity lookup (function, class, type, variable)

Three repos per language (nine for Python): bash, C, C++, C#, Elixir, Go, Haskell, Java, JavaScript, Kotlin, Lua, PHP, Python, Ruby, Rust, Scala, Swift, TypeScript, Zig. Repos are pinned by revision. Queries and ground-truth relevance labels are generated by Claude Sonnet 4.6, and the same model is used as LLM-as-judge to verify label quality.

Methods

  • ripgrep: fast regex search, included as a raw keyword-match baseline.
  • probe: BM25 keyword ranking backed by tree-sitter parse trees. No persistent index; scans on the fly.
  • cs (Code Spelunker): structural BM25 ranker that ranks matches differently in code, comments, and strings.
  • ColGREP: late-interaction code retrieval with the LateOn-Code-edge model.
  • grepai: semantic search using nomic-embed-text (137M params) via a local Ollama daemon.
  • codebase-memory-mcp: code intelligence engine that indexes a repo into a SQLite/graph store. Benchmarked via its search_graph tool in fast mode (BM25 full-text search with structural boosting).
  • ck: hybrid regex + semantic search using bge-small-en-v1.5.
  • zvec-grep: potion-code-16M-v2 static embeddings + BM25, benchmarked in direct mode.
  • CodeRankEmbed: 137M-param transformer embedding model for code retrieval, used for semantic-only dense search.
  • semble: potion-code-16M-v2 static embeddings + BM25 + the semble reranking stack.

Several other tools (codanna, claude-context, GitNexus, codegraph, tgrep) were considered but excluded, either because they don’t support a large share of the benchmark languages, require paid API keys, or produce results nearly identical to ripgrep. See the benchmarks README for details and instructions for reproducing the results.