The real UI on excalidraw (687 files, indexed in under half a second): search, a symbol's code and callers, then the blast radius of a change. Try it in your browser, no install needed.
One issue-text search finds every fix file in the top 10 for 83.0% of SWE-bench Verified issues (semble: 71.0%). File retrieval, not issue resolution.
| Method | Acc@1 | Acc@5 | Acc@10 |
|---|---|---|---|
| repomap | 48.8% | 74.8% | 83.0% |
| semble | 34.0% | 61.6% | 71.0% |
| BM25 | 20.8% | 45.4% | 55.8% |
Defaults selected on 300 disjoint SWE-bench test instances, excluding every Verified ID, then frozen before one evaluation on all 500 Verified instances. One search per issue, at its base commit; gold files are used only for scoring. All three methods scored 500/500, with zero errors.
Split definitions, pinned revisions and full results · Committed chart data
Trade-off: on semble's public code-search set, NDCG@10 is 0.845 versus semble's 0.851; semble wins there. This is not a claim of better search on every task. Measured search quality and limitations.
## Why Agents burn most of their context on `grep`, `ls` and reading whole files just to work out where things are. repomap gives them the map up front: - **Where is it?** Hybrid search that matches symbol names, the words inside functions *and* what the code means, with the lines that matched. Ask "where are failed requests retried" or `parseConfig`. - **What is this?** One call returns a symbol's code, callers with call-site lines, callees, subtypes and the tests that reach it. - **How does A reach B?** The shortest call path, each hop cited `file:line`. - **What breaks if I change this?** Direct and indirect callers, importing files, modules touched, tests to run, and a risk level. Point it at your `git diff` before you commit. - **What does this repo look like?** Modules found from real dependencies (not just folders), the most central files, the most used symbols, and entry points. All of it comes from a local index: tree-sitter parsing, a resolved import and call graph, PageRank, Louvain communities, BM25 over AST chunks, and a small static code embedding model (33 MB, downloaded once from Hugging Face, then offline). Nothing leaves your machine, and no API is called; the model download is the only network request (set `REPOMAP_EMBED=0` to skip it). ## What your agent gets Six tools, each with an obvious job: | Tool | Ask it | Returns | |---|---|---| | `map` | "Give me the lay of the land" / `focus: "src/server"` | Modules, central files, key symbols, entry points; an outline with line numbers when focused | | `search` | `"where are failed requests retried"`, `"parseConfig"` | Ranked `file:line` ranges (functions, methods, classes) by keywords, names and meaning, with the matching lines | | `context` | `SessionStore.refresh`, `src/auth/token.ts`, `token.ts:42` | Code, callers (with call sites), callees, subtypes, members, imports, importers, tests | | `trace` | `from: handleRequest, to: db.query` | Shortest call path, or the call tree above/below a symbol | | `impact` | `target: verifyToken` or `changed: true` | Risk level, callers by depth, importing files, modules, tests to run | | `db` | `table: users`, or `url_env: DATABASE_URL` for a live database | Tables, keys, indexes, and the code (`file:line`) that queries each table | Answers are compact text that cites `file:line`, so they cost few tokens. Pass `format: "json"` for structured output. ```text > impact target=decode # Impact (LOW risk) Changing: function decode (src/auth/token.ts:14) 1 direct caller, 3 symbols affected in total across 3 files and 2 modules; 1 file importing the changed files; no tests reach this. ## Direct callers (will break if the contract changes) - function verifyToken — src/auth/token.ts:8 ## Indirect (depth 2) - method SessionStore.refresh — src/auth/session.ts:5 ## Indirect (depth 3) - function handleRefresh — src/api/router.ts:6 ## Importing files - src/auth/session.ts ``` The same commands work in your terminal: `repomap map`, `repomap search "…"`, `repomap context X`, `repomap trace A B`, `repomap impact --changed`, `repomap db`. ## The graph UI ```bash npx -y @sylphx/repomap serve # live, with code preview npx -y @sylphx/repomap export # repomap.html: one self-contained file you can publish ```![]() |
![]() |
| Impact. Select a file and press i: everything that depends on it lights up by depth, with a list you can click through. | Code. Click a symbol to see its source, callers and callees. Open ↗ jumps to your editor or to GitHub. |
Live connections are strictly read-only:
- **Postgres** runs in a `READ ONLY` transaction that the server must confirm.
- **MySQL** runs in a `START TRANSACTION READ ONLY` transaction.
- **SQLite** is opened read-only with `query_only`.
Only catalog metadata is read, never table rows. The connection string comes from an argument or an environment variable, and it is never stored or printed. Agents get the same data through the `db` MCP tool; pass `url_env` rather than the URL itself.
## Agent-readiness score
```bash
npx -y @sylphx/repomap score
```
The score rates how well an AI agent can work in the repository, from 0 to 100. It covers eight checks:
- agent instructions (AGENTS.md / CLAUDE.md and how useful they are)
- discoverable build and test commands
- test coverage
- CI
- module boundaries
- file sizes
- docs
- types
Each check that falls short comes with a concrete fix, and the score ends with a badge line for your README. For CI, use `--min 70`; `--update-readme README.md` refreshes the badge.
Keep the badge fresh with the GitHub Action:
```yaml
# .github/workflows/agent-ready.yml
on: { push: { branches: [main] } }
permissions: { contents: write, pull-requests: write }
jobs:
score:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: SylphxAI/repomap@v1
with:
update-readme: true # opens or updates one PR with the fresh badge
min-score: 0 # set e.g. 70 to fail below a bar
```
## Claude Code hook
```bash
npx -y @sylphx/repomap setup --claude-hooks
```
This is opt-in and safe to run again; `setup --remove` takes it out. It installs a PreToolUse hook: whenever Claude Code runs `Grep` or `Glob`, repomap adds where the symbol is defined, who calls it and which module it belongs to. It answers in tens of milliseconds and never blocks the search.
```text
repomap (code map) for this search:
- function `compose` defined at src/compose.ts:15 (module router); 3 callers: Hono.route (src/hono-base.ts:228), Hono.#dispatch (src/hono-base.ts:452), every (src/middleware/combine/index.ts:102)
```
## Languages
Parsed with tree-sitter for symbols, calls, imports and inheritance: **TypeScript, TSX, JavaScript, Python, Go, Rust, Java, Kotlin, Swift, C, C++, C#, Ruby, PHP.**
Search also covers Markdown, YAML, TOML, JSON, SQL, shell, Protobuf, GraphQL, HTML/CSS, Vue, Svelte, Scala and more.
Modules are found among your core code only. Tests, examples, docs and benchmarks are grouped separately, so they never name or blur a module.
Import resolution understands relative paths, `@/` aliases, npm workspace packages, Python packages and relative imports, Go modules, Rust `mod`/`use`/workspace crates, Java/PHP namespaces, C/C++ includes and Ruby `require`. `.gitignore` is respected, and so is `.repomapignore`.
## Search that understands the question
On [semble's public code-search benchmark](https://sylphxai.github.io/repomap/benchmarks) (63 repositories, 19 languages, 1,251 questions), repomap's `search` scores NDCG@10 **0.845**, versus semble **0.851** on the same runner. The previous repomap score was 0.851: stronger issue localization trades about 0.006 here. On our 60 large-repository questions, repomap scores **0.846** versus semble **0.799**, but semble still wins on VS Code. The 137M-parameter CodeRankEmbed model's published score is 0.839 and plain BM25's 0.673 (cited, not re-run).
On [file localization](https://sylphxai.github.io/repomap/benchmarks#file-localization) (500 SWE-bench Verified issues, one `search` call with the issue text), repomap finds every fix file in the top 10 for **83.0%** of issues (Acc@10; **74.8%** at 5, **48.8%** at 1), versus semble's **71.0% / 61.6% / 34.0%**. Before this change, repomap scored 62.2% / 51.8% / 23.6%. Plain BM25 scores 55.8% at 10, and repomap with embeddings off 77.6%. Same-run median index/query costs are **1.682 s / 54.4 ms**, versus the old binary's 1.686 s / 59.8 ms and semble's 12.813 s / 354.4 ms. Defaults were selected only on a disjoint 300-instance tuning split, then frozen before one Verified measurement. Agent systems such as LocAgent report higher numbers on a different subset with a language model in the loop; those are cited, not re-run.
This needs no GPU, no vector database and no API key. A 33 MB static code model runs on the CPU, next to BM25 and symbol names.
## Fast
The index is built in parallel and cached per file, so after the first run only changed files are parsed again. The MCP server keeps the graph in memory and refreshes it when files change.
Measured on a 4 vCPU GitHub-hosted runner ([method and full table](https://sylphxai.github.io/repomap/benchmarks)):
| Repository | Code files | Cold index | Warm index | search p50 | impact p50 |
|---|---:|---:|---:|---:|---:|
| kubernetes | 11,710 | 13.1 s | 2.0 s | 74 ms | 6 ms |
| vscode | 6,126 | 9.3 s | 1.4 s | 17 ms | 8 ms |
| django | 2,271 | 2.6 s | 0.5 s | 24 ms | 1 ms |
| rust-analyzer | 1,512 | 2.1 s | 0.4 s | 8 ms | 2 ms |
## How it compares
| | **repomap** | GitNexus | Serena | claude-context | Aider repo map |
|---|---|---|---|---|---|
| Licence | **MIT** | PolyForm Noncommercial | MIT | MIT | Apache-2.0 (inside Aider) |
| Setup | `npx … setup`, one binary, or a one-click `.mcpb` | `npx`, Node | Python + language servers | Vector DB + embedding API key | Part of Aider |
| API key / network | **None** (model downloaded once) | None for the graph | None | Required (embeddings) | None |
| Code graph (calls, imports, inheritance) | ✅ | ✅ | Via LSP references | — | Ranking only |
| Change impact / blast radius | ✅ incl. `git diff` | ✅ | — | — | — |
| Call path between two symbols | ✅ | ✅ | — | — | — |
| Search | ✅ names + BM25 + local embeddings | ✅ | ✅ symbols | Semantic (vectors) | — |
| Interactive graph UI | ✅ local + static export | ✅ | — | — | — |
| Claude Code Grep/Glob hook | ✅ opt-in | ✅ | — | — | — |
| Database schema map linked to code | ✅ live (read-only) + migrations/ORMs | — | — | — | — |
| Agent-readiness score + badge | ✅ + GitHub Action | — | — | — | — |
| Module detection | ✅ Louvain | ✅ | — | — | — |
| Edits code | — (read-only) | — | ✅ | — | ✅ |
| Engine | Rust | TypeScript | Python | TypeScript | Python |
Pick Serena if you want LSP-precise refactoring edits. repomap is for understanding and navigating a codebase with zero setup, including semantic search without a vector database or an API key, and a licence you can use at work. Search quality is measured on public benchmarks in [Benchmarks](https://sylphxai.github.io/repomap/benchmarks).
## Free
Everything repomap does is free under MIT, including the multi-repository workspace (`--workspace`) and `impact` in your own CI. There is no licence key and no paid tier.
## CLI
```text
repomap setup [--client cursor,codex] [--claude-hooks] [--dry-run] [--remove]
repomap serve [dir] [--port 7878] [--no-open]
repomap export [dir] [--out repomap.html] [--json]
repomap map [dir-to-focus] [-C root] [--tokens 1000] [--json]
repomap search