The ripgrep of AI context: a zero-dependency C++23 CLI + MCP server for coding agents. Find what you
# Rip'n Fast. Fewer Tokens. Better Code.
**The ripgrep of AI context. Give your coding agent a map before it reads the repo.**
Point it at any repository and your agent gets a ranked, deterministic call graph — what to touch,
what it breaks, which tests to run — instead of grepping around and reading whole files.
**Just want to use it?** Install it with the one line below, then start each coding session by telling your agent to
use it, for example: *"Use ripwire on this repo."* That is all most people need: the install also teaches your agent
when to reach for each command.
**Want every detail?** [The reference guide](#reference-guide) near the bottom covers install, commands, output
format, exit codes and limits. You do not need it to get started.
Fifty years of software-engineering results, and research from last month. 49 repositories and 71 papers folded — McCabe (1976) through to
seven published in the last two months — each row in
docs/LINEAGE.md naming the lesson taken and the file it lives in
Beside those sits a labelled survey of **237 tools** that contributed nothing and says so. The two
sets are disjoint by construction, so they add rather than nest — a tool that gave a lesson is never
counted twice.
**Both halves are load-bearing, and they are doing different jobs.** The settled results are what
make the quality lens trustworthy: McCabe on complexity (1976), Halstead on volume (1977), Spärck
Jones on term specificity (1972), Nagappan & Ball on churn. Fifty years of replication means those
are not opinions, and a tool that measures your code should be built on the ones that survived.
The recent work is what makes it *current*: **seventeen of the folded papers are from 2026, seven
published in the last two months and three in the last thirty days** (dates as of 2026-09-08; every
row carries its arXiv id, so the claim is checkable rather than atmospheric). Retrieval for coding
agents, context-compression cost, placebo-controlled localization — that literature is months old,
not decades, and several rows were folded within weeks of the paper appearing.
Neither half alone would be enough. A tool built only on the classics would not know what an agent
needs; one built only on last month's preprints would have nothing underneath it. And the newest row
is a result that **failed** when it was tested here — which is the point of writing them down. All three counts are re-derived from that document's own tables by
`test/readmedriftcheck.sh` on every run, which fails if this page and those tables disagree, so the
claim cannot quietly drift. The row-by-row ledger is
[`docs/LINEAGE.md`](docs/LINEAGE.md).
**Languages:** Rust · C++ · Objective-C/C++ · C · Metal · CUDA · Python · Go · Swift · TypeScript ·
JavaScript · Java · Ruby · PHP · Lua · Elixir · Dart · Kotlin · Bash · C# · JSON · TOML · YAML · Markdown — see
[language support and limits](#languages).
**ripwire 0.6.1 — out now. The answers an agent reads got smaller.** A compact answer is 46–66% smaller per
call — 2.8–5.8 KB less on `--callers`, `--uses`, `--impact` and `--affected` — the flagless map is 15.3% smaller at
identical rows, and the new `--in=DIR` scopes "what changed recently" to a directory: 39.8 KB down to 10.2 KB per
answer on RocksDB. It got smaller in memory too: on llvm-project the declined-call index drops from **114 MB to
368 KB**, with every count and every byte of output unchanged. Elixir resolves natively by module, name and arity
(thanks @henry-hz), `--scip` reads scip-java indexes (thanks @dpunosevac), and a `file:name` selector no longer
answers with a definition that belongs to another file (thanks @andriytyurnikov). Every number in a compact answer
now arrives with its definition, and the focus verbs say when a definition could not be proven instead of
reporting a quiet zero.
**ripwire 0.6.0 — out now.** Kotlin and Dart bring it to 24 vendored grammars, and Ruby now reads the dependencies a
Rails application actually has: superclasses, mixins, `autoload`, and the constant receivers an autoloader loads
through. On llvm-project — 182,555 files — the cold parse drops from 194 s to 156 s of CPU. Declined calls, derailed parses
and cut answers now say so, instead of returning a quiet zero.
**[The presentation](present/ripwire-showcase.pdf) · [the changelog](CHANGELOG.md)** — with thanks to the
contributors named there; this release is largely theirs.
---
One process, no server — indexes this repository in
0.25 s using
6.6 MB, against
46.8 s and
391 MB for the graph-database MCP server it was measured against; warm queries answer in
197 ms to its
1,082 ms
Measured on 48 matched questions across django, webpack and this repository. Across all three,
ripwire indexes in **0.25–0.45 s** and **6.6–16.5 MB** against that server's **23–52 s** and
**391–623 MB**. The full method, the wins named one by one and the losses included, is in
[Against the leading graph-database code-context MCP server](#against-the-leading-graph-database-code-context-mcp-server)
and [`docs/EVALS.md`](docs/EVALS.md).
One binary, offline — and the same line
activates the skills for every agent it finds: Claude Code · Codex · Cursor · Windsurf · Gemini · opencode · aider
One self-contained binary on your own machine, offline, installed in one line — and the same line
installs *and activates* the task-shaped skills that teach your agent *when* to reach for it, not
just how, for every agent it finds on the machine. If your
agent can run shell commands — Claude Code, Codex, Cursor, Windsurf, Gemini, opencode, aider — it is
set up the moment the install finishes; [the MCP server is the optional second
interface](#set-it-up-in-your-coding-agent). Install it and ask it something before you finish
reading this page:
```bash
RIPWIRE_REPO=redhat-et/ripwire bash -c "$(curl -fsSL https://raw.githubusercontent.com/redhat-et/ripwire/main/scripts/install.sh)"
export PATH="$HOME/.local/bin:$PATH" # where it installed; the installer prints this line if you need it
cd your-repo
ripwire . --for=""
```
Every install route (prebuilt, from source, per-agent skills, hooks, the MCP server) is in [INSTALL.md](INSTALL.md).
**Reach for the CLI first — it is the cheaper interface.** The MCP server is the optional second
way in, and its convenience has a cost the shell pipe does not carry: its verb schemas sit in your
agent's context every session, whether or not it calls them.
### The goal: one question, one complete answer.
**Terminality is the objective.** Ask the codebase a question and the answer should carry everything
you need — no follow-on grep, no three more whole-file reads to fill in what it left out. A call
followed by three greps is the same search paid for twice: it does not save you tokens and it does
not make the coding faster.
The two stair-steps that make it reachable —
honest about what is missing,
priced in what it spends
**Two things make that reachable in practice, and neither is the destination.** Answers are honest
about their own limits — a count that cannot be a total is labelled a floor, a zero means "none
found" and never "none exists", every truncation is disclosed — so an answer never looks more
complete than it is, and the map never degrades the code by guessing. And an answer can be given a
token budget, so what one costs is something you ask for rather than discover; where a complete
answer will not fit, it says it went over rather than silently dropping the row you needed.
Those two are the stair-steps: honest about what is missing, priced in what it spends. The step they
climb toward is a question fully answered in one call, which is not always trivial to reach — and
where it is not, the output says so rather than pretending otherwise.
### Same answer, a fraction of the tokens — read this table first if your agent is on a budget
How these ten rows were measured —
2026-08-08, figures in ~tokens (≈ bytes/4), every ratio from a real run reproduced by the command in its row
Ten everyday moments, re-measured on this repository, 2026-08-08. Figures are ~tokens (≈ bytes/4);
every ratio comes from a real run, reproduced by the command in its row — raw byte counts and exact
commands in
[`docs/EVALS.md` §5](docs/EVALS.md#readme-grade-rows-re-measured-on-this-repository-2026-08-08).
Ordered understand → navigate → review-the-change:
| Ask it | Command | ripwire | naive read | token savings |
| --- | --- | --- | --- | --- |
| "Orient me in this repo" | `ripwire .` | **~5.6K tok** | ~20K–25K tok — read `README.md` (+`docs/ARCHITECTURE.md`) | 3.6×–4.5× |
| "Where is X handled?" | `ripwire . --for="…"` | **~2.1K tok** | ~4.9K–20K tok — `grep -rn src/`, then read the file it points at | 2.3×–9.3× |
| "What do I already know?" | `ripwire . --recall="…"` | **~15K tok** | ~445K tok — read all 119 markdown docs this repo carries | 29.2× |
| "Set me up for this task" | `ripwire . --pack-task="…"` | **~2.1K tok** | ~16K–80K tok — read every relevant file, whole | 7.7×–37.7× |
| "Show me this one function" | `ripwire . --expand=SYM --top-k=0` | **~260–16.5K tok** body (+~5.7K for the ranked-neighborhood bundle) | ~43K–174K tok — read the whole file it lives in | 2.6×–670× |
| "Who calls this function?" | `ripwire . --callers=SYM` | **~580 tok** | ~40K–52K tok — `grep -rn SYM src/` (mostly noise), then open 2–3 files to sort real calls from mentions | 69.2×–89.1× |
| "Is it safe to change this?" | `ripwire . --impact=SYM` + `--uses=SYM` | **~1.3K tok** | ~18K tok — open every direct-use file, whole | 14.4× |
| "I have a stack trace" | `ripwire . --from-trace=FILE` | **~1.4K tok** | ~124K–298K tok — grep all 7 frame names, then open the innermost file(s) | 86.9×–208.6× |
| "I changed these files — tests? blast radius?" | `ripwire . --situ` | **~410 tok** | ~3K–132K tok — `git diff` + `grep -rn test/`, then open the candidates | 7.3×–324.2× |
| "Review this PR/diff" | `ripwire . --pr-context=REF` | **~1.9K tok** | ~4.8K–51K tok — `git diff REF`, then open the touched files | 2.6×–27.5× |
Same-correct-answer verification, and the honesty line these ratios come with
**These aren't summaries that gamble with information.** Each row is scored
same-correct-answer-or-it-doesn't-count, and both sides were checked, not assumed: orient surfaces
this repo's own pipeline files (`ingest.cpp`, `graph.h`, `serialize.h`) in the first screen, the same
three `docs/ARCHITECTURE.md` names as central; the `--for` row lands `mcpStale`
(`src/mcpindex.h:633`), the actual staleness check, 5th-ranked; `--recall` lands the container-rule
doc (`AGENTS.md`) that states, verbatim, the same "no `std::map`" rule `CONTRIBUTING.md` explains in
full; `--pack-task` names the same three touch points a human would — `cachelint.h`, `mergeCachePack`
(`src/main.cpp:1787`), the `lintrules.h` helpers it reuses; `--expand --top-k=0` hands back the
requested function's complete, unmodified body — the ranked-neighborhood addition costs the same
~22.6 KB regardless of which function you ask for, confirmed on two (a fixed floor, not per-function
variance); `--callers` on `langOfPath` names its 2 real callers, the same ones a `grep` hit-list
buries under 5 files of comment-only mentions; `--impact`+`--uses` on `coversOrEquals` names the same
2 direct call sites `--uses` alone would, plus (disclosed) a transitive reach `--uses` doesn't cov