Model or dataset
redhat-et/ripwire avatar
redhat-et/ripwire

ripwire: a zero-dependency C++23 CLI and MCP server that gives coding agents a call graph before they read the repo

The ripgrep of AI context: a zero-dependency C++23 CLI + MCP server for coding agents. Find what you want without reading the repo, then check you built what you meant — blast radius, tests-to-run, quality deltas. Signatures at 74.7% fewer bytes than bodies; every guess labelled, every loss published. Paddle out with a map.

2,174 stars132 forksC++Apache-2.0

At a glance

What is it?
ripwire indexes a repository into a ranked call graph and answers navigation questions from a single binary, with no API key, embeddings, index server or daemon. The design bet is terminality: one question, one complete answer, with every truncation disclosed.
Who is it for?
Adopt ripwire if your agent currently greps around a repository and reads whole files to answer navigation questions, and you want that answer priced and bounded before it is produced. Do not adopt it if you need whole-body semantics, cross-repository resolution, or a hosted service with a support contract; the single-binary, no-daemon model is the point, not an oversight.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem ripwire targets: agent navigation without whole-file reads

A coding agent asked to change a function has no cheap way to learn what that function touches. The common workaround is grep plus whole-file reads, and the README describes the cost directly: "A call followed by three greps is the same search paid for twice." The agent spends context on text it did not need, and the answer it eventually assembles is neither ranked nor bounded. ripwire's stated goal is terminality, meaning one question returns one complete answer with no follow-on grep. The audience is anyone running a shell-capable coding agent (Claude Code, Codex, Cursor, Windsurf, Gemini, opencode, aider are the ones the README names) against a repository large enough that reading files to find call sites is the slow path. The output is not a diff or a fix. It is a map: what to touch, what it breaks, which tests to run.

How the call graph is produced and what the ranked output contains

ripwire is a single compiled binary that indexes a repository in place, with no index server and no daemon. The README reports indexing this repository in 0.25 s using 6.6 MB, and across django, webpack and ripwire itself, 0.25 to 0.45 s and 6.6 to 16.5 MB. Those numbers come from the project's own evaluation document, docs/EVALS.md, not from independent measurement, and the README states the method and the losses are published there. The mechanism is call-graph construction over the supported languages, with results ranked and deterministic. The README's description of signature output is specific: signatures at 74.7% fewer bytes than bodies. That is the compression claim, and it is the reason a signature-level map fits in a budget where whole files do not. Alongside navigation, the tool reports blast radius, tests to run and quality deltas. The quality lens is built on named prior work: McCabe on complexity, Halstead on volume, Spärck Jones on term specificity, Nagappan and Ball on churn. Those are cited in docs/LINEAGE.md with the file each lesson lives in, and test/readmedriftcheck.sh re-derives the counts from that document's tables on every run, failing if the README and the tables disagree. That check is the most interesting engineering decision in the repository: the documentation is treated as a build artifact that can break the build.

Installing ripwire and choosing between the CLI and the MCP server

The README gives a one-line install that also activates task-shaped skills for every agent it detects on the machine. The command sets RIPWIRE_REPO and pipes scripts/install.sh through 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" cd your-repo ripwire . --for="<the change you are about to make, in words>"

The third argument pattern is the interesting one. --for takes a natural-language description of the change, and the tool returns a ranked answer scoped to that intent rather than a generic dump. The README is explicit that the CLI is the cheaper interface and the MCP server is the optional second way in. The stated reason is a context cost that the shell pipe does not carry: the MCP server's verb schemas sit in the agent's context every session whether or not the agent calls them. That is a real and often overlooked tax. An MCP tool that is never invoked still consumes context in every session, and ripwire's documentation treats that as a reason to prefer the pipe. The language list is broad (Rust, C++, Objective-C/C++, C, Metal, CUDA, Python, Go, Swift, TypeScript, JavaScript, Java, Ruby, PHP, Lua, Elixir, Bash, C#, JSON, TOML, YAML, Markdown), but the README points to a separate language support and limits section rather than claiming uniform depth. Treat that section as required reading before assuming your language is handled at the same fidelity as the ones used in the project's own evaluation.

The honesty machinery: floors, zero semantics and disclosed truncation

The most defensible part of ripwire's design is what it does when it cannot answer completely. A count that cannot be a total is labelled a floor. A zero means "none found" and never "none exists". Every truncation is disclosed. An answer can be given a token budget, so the cost of a query is something you set rather than discover, and where a complete answer will not fit, the tool says it went over instead of silently dropping rows. This is a different posture from most code-context tools, which return whatever fits and leave the agent to assume it saw everything. The trade-off is real: an answer that admits it is a floor is less satisfying than one that looks complete, and an agent consuming it has to be written to handle the caveat. If your agent treats any returned list as exhaustive, the labelling will not save you. The README frames these two properties (honest about what is missing, priced in what it spends) as stair-steps toward terminality rather than the destination, and concedes that a fully answered question in one call is not always reachable. That concession is worth taking at face value.

Where ripwire is the wrong tool, and what the graph-database alternative does differently

ripwire is a static, per-repository index. It will not resolve calls across repository boundaries, and it does not build a persistent graph you can query incrementally as the code changes; the model is index-and-answer, not a standing database. If your work is cross-repo dependency analysis, or you need a graph that survives restarts and accumulates history, this is the wrong shape. The README names the comparison itself: a leading graph-database code-context MCP server, which the project measured at 46.8 s and 391 MB for indexing this repository against ripwire's 0.25 s and 6.6 MB, and 1,082 ms warm queries against 197 ms. Across django, webpack and ripwire, the README reports the other server at 23 to 52 s and 391 to 623 MB. The architectural difference is the whole story: a graph database keeps a server, a schema and a persistent store, which buys incremental updates and richer query surfaces at the cost of a running process and a much larger footprint. ripwire keeps nothing running and pays for it by re-indexing. If your repository is enormous, or your queries need graph traversal the call graph does not precompute, the persistent server is the better fit and the footprint is the price of that fit. The README also states the comparison includes losses, not only wins, and points to docs/EVALS.md for the full method. Read that document before treating the numbers as a verdict on your workload.

Maintenance cost, the Apache-2.0 licence, and what the release cadence signals

The project is Apache-2.0, which permits commercial use, modification and redistribution with the usual conditions around notices and patent grant. Nothing here is legal advice; if you are shipping ripwire inside a product, read LICENSE and THIRD_PARTY.md, the latter being where the repository records its third-party position. The runtime dependency claim is the maintenance-relevant one: the README badges "runtime dependencies: none", and the tool is a single self-contained binary installed by a shell script. That means no Python environment to keep in sync, no Node version drift, no embedding model to re-download, and no server to patch. The cost you do carry is the re-index on each invocation and the C++23 toolchain if you build from source. Release cadence is fast and recent: v0.5.0 on 2026-09-08, v0.4.0 the day before, v0.3.8 about a month earlier, with the last push to main on 2026-09-10. Two releases in two days suggests active iteration rather than a settled interface, and the README's own note that the newest folded research row is a result that failed when tested here points the same way. Pin a version if you are wiring this into an agent's default path, and check the changelog between releases rather than tracking main.

The lineage claim and why it is checkable rather than atmospheric

ripwire's README devotes unusual space to provenance. It claims 46 repositories and 69 papers folded into the design, from McCabe (1976) through to seven papers published in the two months before the 2026-09-08 release date, with seventeen of the folded papers from 2026 and three from the last thirty days. Each row in docs/LINEAGE.md names the lesson taken and the file it lives in, and every row carries an arXiv id. Beside that sits a labelled survey of 237 tools that the project says contributed nothing, kept deliberately disjoint from the folded set so the two add rather than double-count. The counts are re-derived from that document's own tables by test/readmedriftcheck.sh on every run. You do not have to accept the lineage argument to use the tool, and a long citation list is not evidence that the resulting rankings are good on your code. But the mechanism is falsifiable: the arXiv ids are there, the file mapping is there, and the build fails if the README and the tables diverge. That is more than most projects offer, and it is the part of ripwire worth copying regardless of whether you adopt the tool.

Editorial conclusion

Adopt ripwire if your agent currently greps around a repository and reads whole files to answer navigation questions, and you want that answer priced and bounded before it is produced. Do not adopt it if you need whole-body semantics, cross-repository resolution, or a hosted service with a support contract; the single-binary, no-daemon model is the point, not an oversight. Verify three things first: that your language appears in the supported list, that ripwire . --for="<change>" returns a call graph you trust on your own repository, and that the token budget you set actually changes the output rather than only the notice. Check docs/EVALS.md and docs/LINEAGE.md against your own code before you wire it into an agent's default path.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. README
  4. redhat-et/ripwire on GitHub
  5. Releases
Community notes

Community notes