Skip to content

Benchmarks ​

Search quality ​

Run 36781120651, frozen defaults at 0f8bdad, 4 vCPU ubuntu-latest. NDCG@10, where higher is better and 1.0 means every relevant file is at the top.

semble's public benchmark: 63 repositories, 19 languages, 1,251 questions.

MethodNDCG@10architecturesemanticsymbolindex, meanquery p50
repomap, frozen defaults0.8450.8070.8480.925199 ms2.90 ms
repomap, keywords only (REPOMAP_EMBED=0)0.8020.7500.8030.917163 ms2.22 ms
repomap 1.2.20.6850.6140.6680.883159 ms2.17 ms
semble, same runner0.8511,735 ms5.97 ms

semble's README also lists results from its authors' machine: CodeRankEmbed (a 137M-parameter transformer) 0.839, ColGREP 0.693, BM25 0.673, codebase-memory-mcp 0.630, ripgrep 0.126. These are cited, not re-run.

Large repositories: 60 questions of our own over Django, Kubernetes, VS Code and rust-analyzer.

Methodmeandjangokubernetesrust-analyzervscodeindex, mean
repomap, frozen defaults0.8460.9510.9460.7790.7076.9 s
repomap, keywords only0.7960.9120.8670.7420.6615.8 s
repomap 1.2.20.4630.4860.5670.3860.4125.5 s
semble, same runner0.7990.8290.8240.7120.83166.3 s

What this shows:

  • On the public set, semble wins: 0.851 versus repomap 0.845. The previous published repomap score was 0.851 (run 36204314484); this localization-focused change trades about 0.006 NDCG@10 here. The earlier score is a separate execution, not the 1.2.2 baseline in this table.
  • On large repositories, repomap improves from the previous published 0.794 to 0.846, ahead of semble at 0.799. semble still wins on VS Code (0.831 versus 0.707); repomap wins on Django, Kubernetes and rust-analyzer.
  • Embeddings add about 0.043 on the public set and 0.050 on large repositories.
  • TypeScript remains the weakest language. No weights were selected on either of these question sets in this outcome.
By language (frozen defaults, public set)
LanguageNDCG@10
bash0.829
c0.795
cpp0.893
csharp0.899
elixir0.908
go0.885
haskell0.813
java0.812
javascript0.901
kotlin0.782
lua0.882
php0.844
python0.876
ruby0.834
rust0.833
scala0.880
swift0.823
typescript0.721
zig0.851

Method ​

  • Question sets.
    • semble's benchmark, at commit 2449784: 1,251 questions over 63 open-source repositories in 19 languages, each pinned to a commit. The questions are sorted into architecture ("how are routes registered"), semantic ("session management") and symbol (Blueprint). semble's authors wrote the questions and relevant files with Claude Sonnet 4.6 and checked them with an LLM judge. We use the set as published.
    • Our large-repository set: 60 plain-language questions over Django, Kubernetes, VS Code and rust-analyzer, at the commits of the speed benchmark below. We wrote the questions and answers before running any search, and checked every answer path against the pinned tree. Because we wrote this set, read it together with the public one.
  • Scoring, the same as semble's run_benchmark.py:
    • Take the top 10 results of the MCP search tool.
    • A target file counts as found at the rank of the first result in that file whose lines overlap the target's lines, if the target gives any.
    • NDCG@10 is averaged per repository, then per language, then over the languages.
  • Runs. On one GitHub-hosted ubuntu-latest runner in the bench workflow:
    • this build;
    • this build with REPOMAP_EMBED=0 (keywords only);
    • repomap 1.2.2, an older release baseline;
    • semble itself, through its own harness, on the same repositories.
  • Speed columns.
    • repomap's index time is repomap index --no-cache as a new process, which includes loading the model.
    • repomap's query time is a round trip over MCP stdio.
    • semble's numbers come from its harness: indexing in-process, and a Python function call per query.
    • So the speed columns show the size of the costs. They are not a race.
  • Tuning. The older 1.3 ranking had been tuned on 20 of the 63 repositories. This localization-focused outcome selected changes only on the disjoint 300-instance SWE-bench tuning split below, froze them, then evaluated these question sets without tuning on their results. The public set is therefore a regression check, not a wholly unseen benchmark for the historical ranking.

File localization ​

Tuning split (300 instances, not Verified) ​

Defaults were selected only on manifest-tune.json: 300 instances from the pinned full SWE-bench test set (e48e2bd), excluding every Verified instance, evenly spaced by instance id. This is not SWE-bench Lite. Gold files score the candidates; the search query is only the issue text, truncated to 20,000 characters for every method.

Two tuning runs tested 26 individual changes and 10 combinations. We selected the highest Acc@5 + Acc@10 among candidates within 2× the old binary's median query time, then froze the defaults before measuring Verified: wh=1,wc=1,wf=2,qcap=48 (title and code embedding lists, file BM25 weight 2, at most 48 weighted lexical terms). Other defaults are unchanged from the tuning implementation.

MethodAcc@1Acc@5Acc@10index, medianquery, median
repomap before19.742.053.01.755 s48.5 ms
repomap, frozen defaults41.364.373.01.739 s45.0 ms
semble30.752.762.013.338 s342.9 ms
BM25 over files16.734.743.72.384 s68.6 ms

Before and selected repomap are from run 36779097206, same runner shards. semble and BM25 are from the earlier tuning run 36525197903, on the identical split and standard runner type, not the same execution. Every method scored 300/300 with zero errors. Selection-set gains are not held-out evidence; use Verified below for that. The selected query median is 0.93× before, and index median 0.99×. Full ranks, timings, experiment summaries and run provenance are in results-tune.json.

SWE-bench Verified (500 instances) ​

Given a GitHub issue, does search rank the files the fix touches near the top? This runs on SWE-bench Verified (500 instances, 12 Python repositories, dataset revision c104f84). Each repository is checked out at the instance's base commit, and each method gets the issue text as its only query, in one call. Files are ranked by their best-ranked result.

  • Acc@k: every file the gold patch modifies is among the top k files (the definition LocAgent and Agentless use).
  • Hit@k: at least one of them is.
  • Chunk@k: one of the top k result chunks overlaps a line the gold patch changes (repomap and semble only, since BM25 over files returns no line ranges).

Run 36781120696, frozen defaults at 0f8bdad, 4 vCPU ubuntu-latest, 10 shards. Every method scored 500/500 with zero errors. 500 instances scored.

MethodAcc@1Acc@5Acc@10Hit@1Hit@5Hit@10Chunk@5Chunk@10index, medianquery, median
repomap search, before (main)23.651.862.227.658.669.229.835.41.7 s60 ms
repomap search48.874.883.056.283.689.642.851.61.7 s54 ms
repomap, keywords only (REPOMAP_EMBED=0)43.871.077.650.679.284.043.447.61.5 s45 ms
BM25 over files20.845.455.823.251.062.82.3 s72 ms
semble34.061.671.039.469.679.220.225.612.8 s354 ms

Acc@10 by repository (every gold file in the top 10 files):

Repositoryinstancesrepomap search, before (main)repomap searchrepomap, keywords only (REPOMAP_EMBED=0)BM25 over filessemblerepomap index, medianrepomap query, median
astropy/astropy2263.686.481.863.663.62.1 s55 ms
django/django23163.285.779.255.073.61.7 s65 ms
matplotlib/matplotlib3464.782.476.550.058.81.8 s47 ms
mwaskom/seaborn2100.0100.0100.0100.0100.00.3 s10 ms
pallets/flask1100.0100.0100.00.0100.00.1 s4 ms
psf/requests8100.0100.0100.062.5100.00.2 s4 ms
pydata/xarray2272.786.481.854.577.30.5 s22 ms
pylint-dev/pylint1040.040.030.030.030.00.5 s23 ms
pytest-dev/pytest1947.468.473.747.468.40.3 s19 ms
scikit-learn/scikit-learn3281.293.893.881.290.61.1 s41 ms
sphinx-doc/sphinx4431.875.065.936.450.00.8 s27 ms
sympy/sympy7565.380.074.764.074.74.7 s59 ms

What this shows:

  • The file-localization goal is met. Acc@5 improves from 51.8 to 74.8 and Acc@10 from 62.2 to 83.0: +23.0 and +20.8 percentage points over before, and +13.2 and +12.0 over semble. Acc@1 rises from 23.6 to 48.8, versus semble's 34.0.
  • Speed stays within 2×. In this same execution, the old binary's median index/query costs are 1.686 s / 59.8 ms, versus 1.682 s / 54.4 ms for the new binary (1.00× / 0.91×). semble's costs are 12.813 s / 354.4 ms. Index time includes model loading; repomap queries are warmed MCP round trips, while semble queries are in-process Python calls.
  • The gains are not just embeddings: keywords-only repomap reaches 71.0 / 77.6 at Acc@5/10. Embeddings add another 3.8 / 5.4 points. Chunk@10 improves to 51.6, versus 35.4 before and 25.6 for semble.
  • repomap meets or exceeds semble's Acc@10 on every repository here, but this does not make it better on every query or benchmark. semble still wins on the public NDCG@10 set and on VS Code's large-repository questions above. Hybrid search also trails its own keywords-only result on pytest (68.4 versus 73.7 Acc@10).
  • Verified was measured once after freezing defaults at 0f8bdad; no weights were changed after reading its results. The before binary is pinned to ae40b64dbc1405564e21676871a53812e2cf4ad5, not a moving main branch. Full ranks and timings are in results.json.
  • This is one query per instance with the raw issue text. It is not an agent, so it is not comparable with the published agent numbers below.

Published file-level numbers on SWE-bench Lite (300 instances, a different subset with a different setup, the agents use a language model in a loop). Self-reported, different setup; we did not re-run them. From Table 4 of LocAgent (ACL 2025):

SystemAcc@1Acc@5
BM2538.761.7
CodeRankEmbed (CoRNStack)52.684.7
Agentless, Claude-3.5 (paper)72.679.6
LocAgent, Claude-3.577.794.2

Even plain BM25 scores higher there than on our run, which shows that the two subsets and setups differ: read these numbers next to each other only as context.

Method: bench/localization, run by the bench-localization workflow on ubuntu-latest runners in 10 shards. BM25 is rank_bm25 over the tracked text files, with identifiers split at camelCase and underscores. semble is at commit 2449784. repomap ran with frozen defaults selected only on the disjoint tuning split above, never on Verified.

Indexing speed ​

Measured by scripts/bench.py in the bench workflow on a standard GitHub-hosted ubuntu-latest runner. Anyone can re-run it.

Run 36781120651 (frozen search defaults, 0f8bdad, 4 vCPU ubuntu-latest), with embeddings and with REPOMAP_EMBED=0:

RepositoryCode filesSymbolsResolved callsCold indexCold, keywords onlyWarm indexPeak RSS
kubernetes (Go)11,710101,176200,25613.1 s11.0 s1.96 s574 MB
vscode (TypeScript)6,12695,786182,5069.3 s8.0 s1.45 s408 MB
django (Python)2,27141,01959,6432.6 s2.2 s0.47 s170 MB
rust-analyzer (Rust)1,51229,02459,4382.1 s1.8 s0.37 s152 MB

Query latency over MCP stdio, p50 / p95:

Repositorysearchcontextimpacttrace
kubernetes73.7 / 85.7 ms0.8 / 4.4 ms5.7 / 10.6 ms0.6 / 8.1 ms
vscode16.8 / 54.8 ms2.0 / 2.8 ms7.2 / 10.5 ms0.5 / 0.6 ms
django23.9 / 28.8 ms0.4 / 2.1 ms0.9 / 3.6 ms0.3 / 0.4 ms
rust-analyzer7.7 / 22.1 ms0.6 / 1.2 ms2.0 / 3.4 ms0.4 / 0.5 ms

Against the previous published run (36202944872), search p50 is 0.98–1.05× and cold index 1.01–1.03× across these four repositories, comfortably within 2×. These are separate executions on the same runner type; the localization table compares old and new binaries within the same execution.

Method ​

  • Corpora: shallow clones at fixed tags: microsoft/vscode 1.104.0 (TypeScript), rust-lang/rust-analyzer 2026-09-21 (Rust), django/django 5.2.6 (Python) and kubernetes/kubernetes v1.34.1 (Go).
  • Cold index: repomap index <repo> --no-cache, the median of 3 runs. This covers the walk, tree-sitter parse, embeddings, import and call resolution, PageRank, Louvain and BM25.
  • Warm index: the same command with the per-file cache populated. This is what a restart of the MCP server costs.
  • Peak RSS: the highest resident memory of the index runs.
  • Query latency: one long-lived repomap mcp process, with the round trip measured over stdio JSON-RPC. search runs 5 phrases plus the 10 most used symbol names. context, impact and trace (callers) each run on those 10 symbols. The table shows p50; p95 is in the JSON artifact.

Versus GitNexus ​

We have not run GitNexus in this benchmark. Its PolyForm Noncommercial licence does not allow use for a company's commercial purposes, and a vendor benchmark could count as one. Its README documents its own performance. You are welcome to run both tools on the same corpora on your own machine.