Context your agent can explain.
repoctx gives an AI coding agent compact repository evidence — with a machine-readable reason for every hit, and a hard token budget per answer. The goal is fewer unnecessary file reads at the same task quality. See the economics.
Built for agents that have to be trusted.
Three constraints, enforced — not aspirations. They are what make the output safe to feed a model and safe to run on a private codebase.
Nothing leaves the machine
No network calls, no telemetry, no embedding or LLM requests — ever. The ban is verified at compile time and re-checked in CI with networking switched off.
A reason for every hit
Each result carries machine-readable reasons — fts, symbol:loginUser, imported-by:…, test-of:… — so an agent (and you) can see why a file was chosen.
Byte-identical output
The same index and the same query always produce the same bytes. Stable sort, no timestamps in results, no randomness. Diff-friendly and cache-friendly.
The reads are the bill — not the answers.
Every token an agent reads is billed. The way to spend less is not to write shorter answers; it is to stop the agent from opening half the repository to find three functions.
Measured on this repository for the task “improve token budget packing in the context engine”: an agent that asks for file pointers and then opens the top three files pays ~886 tokens for the answer and ~5,336 for the reads. The answer is 14 % of the cost.
Ask for the evidence instead of a reading list, and the follow-up reads simply do not happen — the same task, answered in one call, at roughly a third of the tokens.
Exact o200k_base counts, measured at milestone M6 (ADR 0010). Your repository is not this one, which is why repoctx stats measures yours instead of asking you to believe these.
And when a full read really is needed, the decision itself is cheap: an outline of that repository's main file costs 1,111 tokens against the file's 3,256 — an agent decides whether to read for a third of the price.
A ceiling that is measured
--response-budget-tokens is enforced against the exact rendered response, with no first-item exception. If nothing useful fits, you get an error and a retry budget — never a partial answer billed anyway.
Never pay twice
Every span, symbol and pointer carries a receipt. Echo it — or use a --session, which costs zero output tokens — and that unit is acknowledged instead of resent. Freed slots buy new evidence, not markers.
Cheaper serialization
--format md avoids JSON's escape tax and --compact drops legacy duplicate fields: 217,869 against 246,297 tokens for identical evidence across 36 frozen tasks.
Cheap prompt overhead
The block loaded into every prompt is a ~100-token pointer, capped by a test at 150. The full protocol arrives on demand, as a skill or via repoctx guide.
Cheaper, not thinner.
Any tool can cut tokens by returning less. These are the rules that keep a smaller answer from becoming a worse one — properties of the code and its tests, not intentions.
Symbol-aligned, never truncated
Up to three non-overlapping ranges per file, the matching symbol's range first, reconstructed so the line numbers match the delivered bytes exactly. Whole declarations — not a function cut in half.
The graph adds what search misses
Bounded two-hop expansion brings in the test that covers a file and the module that imports it, while vendor, generated and unrequested fixture/test/doc paths are penalized. Fewer tokens, and different ones.
Nothing is dropped silently
Every hit carries its reasons, and --explain names the omitted candidates with the constraint that excluded them. The opposite of a context window that quietly ran out.
Reuse never over-claims
A receipt suppresses exactly one delivered unit; --known asserts a whole file. Conflating them would tell the model it holds lines it was never sent — the dangerous way to save tokens.
Staleness is visible
Responses carry content and analysis state, --ensure-fresh re-indexes before querying, and memories whose files drifted come back flagged stale.
Regression-gated, not asserted
36 frozen retrieval tasks over four repositories, labelled with exact line ranges before the corpus was ever run. The tests reject any change that drops a previously delivered required file or labelled line.
A 94.7 % recall win — rejected.
An experimental packer raised required-file recall from 29/38 to 36/38, past the 90 % target on the roadmap. It got there by delivering one fragment of more files: relevant lines fell from 204 to 115, evidence-complete tasks from 9/30 to 3/30, and the follow-up reads those tasks still needed rose from 26 to 32. The headline metric improved while the agent's real cost got worse, so the patch was kept for reproduction and left out of the product.
A token saving that costs relevant evidence is not a saving.
What is not claimed. These corpora measure evidence retrieval and response cost — not a coding agent's task success or total session spend. “Reads replaced” credits a read that would probably have happened; it is an estimate, not a lower bound. Under a tight 2,000-token JSON ceiling the holdout still delivers only 29/38 required file occurrences (76.3 %; Markdown 32/38; unbudgeted 38/38) — the 90 % target is not met, and is recorded as open work. Full reasoning, evidence and limits · measurement methodology.
Less to read. Enough to solve the task.
The goal is the same quality at a lower total cost. These changes make context handling more reliable; their effect on completed-task cost still needs a real-agent comparison.
Try smaller evidence first
Before a large file read, the Claude Code guard can suggest an outline or exact source excerpts. It starts in observe mode, which counts without blocking. Enforce mode is an explicit, experimental choice.
Know when to read again
Generated sessions stop relying on old evidence after conversation changes such as compaction or restart. A child agent must not inherit its parent's claims. Manually named sessions remain the caller's responsibility.
Keep the agent moving
A repeated read can proceed through normal client handling. If the guard cannot safely save a redirect, it does not block. Client permissions still apply, and installation preserves other tools' hooks and settings.
Measure the whole task
A blocked read is not money saved. The comparison must include task quality, failed attempts, follow-up reads and repair work. Incomplete measurements cannot establish lower costs or equal quality.
Current limits. No total-cost or equal-quality improvement has been demonstrated for the guard. The full comparison still needs executable scenarios, cache controls and a usage adapter. The measured hook latency also misses its 100 ms target. RepoContext does not call another model to summarize files or write code. Setup and modes · Comparison status.
Four ways in.
Simplest route: npm install — it ships a self-contained binary, so no .NET runtime is involved. Already on .NET 10? Install the global tool. Prefer no package manager at all? Take a binary from Releases. Tool installs blocked by policy? Add it as a plain NuGet package.
npm new
No .NET runtime required — the package ships a self-contained binary. The natural route for a TypeScript / JavaScript repository. The package is repocontext-tool; the command it installs is repoctx.
# globally — puts repoctx on your PATH npm install -g repocontext-tool repoctx --version # or pinned per repository, so the whole team gets the same version npm install --save-dev repocontext-tool npx repoctx --version
Prebuilt for Linux x64/arm64, macOS arm64/x64 and Windows x64/arm64. The platform payloads are optional dependencies, so npm downloads only the one matching your machine. Alpine and other musl-based distributions are not covered by the prebuilt binaries — use the .NET tool there.
.NET global tool
Needs the .NET 10 runtime. Puts repoctx on your PATH.
# from NuGet.org dotnet tool install --global RepoContext.Tool repoctx --version
Self-contained binary
No runtime. From GitHub Releases: linux-x64, win-x64, osx-arm64.
# download for your platform, then tar -xzf repoctx-linux-x64.tar.gz ./repoctx --version
Plain NuGet PackageReference
dotnet tool install blocked by company policy? RepoContext.MSBuild delivers the same CLI through the NuGet restore your build already runs — a development-only dependency, nothing ships with your app.
# in exactly one project of the repository dotnet add src/YourProject package RepoContext.MSBuild # sets up init, index, local CLI payload, wrappers, and portable MCP config dotnet build ./.repoctx/bin/repoctx context "change the login logic"
Index once, then ask.
A genuine three-step flow. After the first build, indexing is incremental — it diffs by content hash and re-reads only what changed.
Set up the repo
repoctx init writes .repoctx/ and a config, and can add usage notes to your CLAUDE.md / AGENTS.md.
Build the index
repoctx index scans the tree into a local SQLite store — files, symbols and the import/dependent graph.
Ask for what matters
repoctx context "add logout" returns a ranked, explained, budgeted bundle — ready to hand to an agent.
Fifteen commands, one contract.
Every command speaks --format text, json or md. The JSON is stable, snake_case and always carries schema_version.
| Command | What it does | Key options |
|---|---|---|
init | Create .repoctx/ and config; optionally wire up agent instructions. | --agents |
integrate | Wire RepoContext into the agents this repo already uses — instructions, skills, rules, MCP registration. | --client · --check |
guide | Print the full usage protocol on demand, so it never sits in every prompt. | — |
index | Build or incrementally update the index (hash diff). | --full |
search | BM25 full-text search over content and symbols. | --symbols · --top · --path |
related | A file's imports, dependents, linked tests and the documents describing it. | --format |
trace | Every file declaring or mentioning one exact key, link, symbol or path. | --top · --path |
context | Ranked, explained bundle under exact response and read budgets. | --response-budget-tokens · --detail · --path |
outline | A compact symbol skeleton before a full-file read. | --format |
changed | Working-tree changes, impacted files, and optional delta hunks. | --patch |
architecture | LOC tree, language mix, centrality, entrypoints. | --format |
prime | A cache-stable repository primer for unfamiliar work. | --files · --format |
memory | Store and recall short agent-authored notes, decisions, and constraints. | add · search · rm |
stats | Local token-savings and optional cost dashboard; opens in your browser when run in a terminal. | --format · --open · --no-open |
mcp | Serve the same deterministic tools over stdio. | — |
Or skip the shell entirely.
GitHub Copilot, Claude Code, Cursor — anything that speaks MCP can call RepoContext directly. repoctx mcp runs a local, non-destructive server over stdio and exposes eight compact tools. Query calls may append aggregate counts to the local usage ledger.
- repoctx_search — full-text and symbol search
- repoctx_get_context — the ranked, budgeted bundle
- repoctx_trace — one exact key, link, symbol or path
- repoctx_get_related_files — imports, dependents, tests
- repoctx_get_outline — compact symbol skeleton
- repoctx_get_changes — changes, impact, delta hunks
- repoctx_memory_add — retain a durable finding
- repoctx_memory_search — recall local knowledge
Register it
# Claude Code — run inside your repo claude mcp add repoctx -- repoctx mcp # GitHub Copilot (VS Code) — .vscode/mcp.json { "servers": { "repoctx": { "type": "stdio", "command": "repoctx", "args": ["mcp"] } } }