ripwire — «ripgrep для AI-контекста»: карта репозитория вместо grep-и-читай
📂 Исходный код на GitHubCLI-утилита и MCP-сервер на C++23 без единой рантайм-зависимости: строит ранжированную карту репозитория (граф вызовов, blast radius, тесты) для кодинг-агентов за доли секунды и в разы дешевле по токенам, чем grep и чтение файлов целиком.
Проблема любого кодинг-агента в незнакомом репозитории: сначала grep по общему слову с сотнями совпадений, потом чтение целых файлов в поисках нужных символов, и за каждый прочитанный — даже впустую — символ платят токены. Проект ripwire из RedHat's Emerging Technologies предлагает другой подход: один бинарник без зависимостей, который отдаёт агенту ранжированную карту репозитория вместо бесконечного чтения. Слоган проекта — «the ripgrep of AI context»: укажите на любой репозиторий, и агент получит детерминированный граф вызовов — что трогать, что это ломает, какие тесты запускать.
Что это и почему быстро
ripwire — это одновременно CLI-утилита и опциональный MCP-сервер на C++23. Никаких API-ключей, эмбеддингов, индекс-серверов или демонов: один процесс, работа офлайн, ноль рантайм-зависимостей. Скорость — главный аргумент: репозиторий самого проекта индексируется за 0,25 с с использованием 6,6 МБ памяти, тогда как графово-табличный MCP-сервер, с которым сравнивали, тратит 46,8 с и 391 МБ. Тёплые запросы отвечают за 197 мс против 1082 мс у конкурента (замеры на 48 задачах по django, webpack и самому ripwire).
Под капотом — tree-sitter грамматоры для разбора кода, разрешение ссылок в граф вызовов и ранжирование через Personalized PageRank; на выходе — детерминированный минифицированный XML на stdout. Два запуска по одному дереву дают побайтово идентичный результат.
Экономия токенов в цифрах
Авторы замерили десять типовых сценариев на собственном репозитории. Все цифры — в приблизительных токенах (≈ байты/4), каждый расклад воспроизводится командой из строки таблицы:
| Вопрос | Команда | ripwire | Наивное чтение | Экономия |
|---|---|---|---|---|
| «Сориентируй меня в репо» | ripwire . |
~5.6K | ~20K–25K | 3.6×–4.5× |
| «Где обрабатывается X?» | ripwire . --for="…" |
~2.1K | ~4.9K–20K | 2.3×–9.3× |
| «Что я уже знаю?» | ripwire . --recall="…" |
~15K | ~445K | 29.2× |
| «Подготовь меня к задаче» | ripwire . --pack-task="…" |
~2.1K | ~16K–80K | 7.7×–37.7× |
| «Покажи одну функцию» | ripwire . --expand=SYM |
~260–16.5K | ~43K–174K | 2.6×–670× |
| «Кто вызывает функцию?» | ripwire . --callers=SYM |
~580 | ~40K–52K | 69×–89× |
| «Безопасно ли это менять?» | ripwire . --impact=SYM --uses=SYM |
~1.3K | ~18K | 14.4× |
| «У меня stack trace» | ripwire . --from-trace=FILE |
~1.4K | ~124K–298K | 87×–209× |
| «Что тестировать после правок?» | ripwire . --situ |
~410 | ~3K–132K | 7.3×–324× |
| «Сделай ревью диффа» | ripwire . --pr-context=REF |
~1.9K | ~4.8K–51K | 2.6×–27.5× |
Ключевая оговорка проекта: это не суммаризации, играющие с информацией. Каждый сценарий проверялся по принципу «тот же правильный ответ — или не считается», а каждая усечённая выдача помечается в заголовке ответа. Если ранжированный бандл для маленькой функции вышел бы дороже самого файла, ripwire честно отдаст файл целиком, пометив ответ как mode="whole-file".
Ответ агента выглядит так — ранжированные символы с doc-комментариями, аннотации риска на каждой строке (сложность cx, частота правок по git churn, усиление изменений amp), контекст вызовов в один хоп и самооценка уверенности confidence="high":
<ctx task="incremental cache invalidation" confidence="high"
bundle="compact" est_tokens="3995">
<sigs shown="23" total="40" capped="1">
<d l="106" n="kCacheMagic" p="src/ingest_cache.h"
cx="0" churn="11" amp="71" r="1">…</d>
…
</sigs>
<hops shown="2" total="6" capped="1">
<h n="spanTierMemoPath">
<calls total="3"><c n="shaKeyedCachePath" l="1621"/></calls>
</h>
</hops>
</ctx>
Установка и первые команды
Однострочный установщик качает готовый бинарник (macOS и Linux, arm64/x86-64), проверяет SHA-256, кладёт в ~/.local/bin и активирует навыки для всех обнаруженных агентов:
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="<опишите задачу словами>"
Сборка из исходников требует только CMake 3.24+ и компилятор с C++23 — все грамматики и зависимости вендорены в репозиторий, сборка проходит с выключенной сетью:
git clone https://github.com/redhat-et/ripwire.git
cd ripwire
cmake -S . -B build && cmake --build build -j
./build/ripwire . --max-tokens=3000
Четыре команды, которые авторы советуют выучить сразу:
ripwire . --max-tokens=3000 # ranked map — с этого начинают
ripwire . --for="incremental cache invalidation" # задачная линза: что трогать
ripwire . --callers=someFunction # кто вызывает
ripwire . --test-gate # какие тесты обязательны перед коммитом
Всего у инструмента 179 длинных флагов в семи семействах — от навигации (--callers, --impact, --connect) до качества (--quality-panel, --clones, --merge-scout) и безопасности (--scan-skill для проверки skill-файлов перед установкой). Если непонятно, какая команда нужна, — ripwire . --help-task="<задача>" порекомендует ровно одну команду и честно откажется, если данных мало.
CLI или MCP-сервер
Авторы рекомендуют CLI как основной интерфейс: он ничего не стоит, пока агент не выполнил команду — никакие схемы инструментов не висят в контексте каждой сессии. MCP-сервер (ripwire --mcp) — опциональный второй вход: 31 глагол (16 чтения, 12 «рефлексных», 3 адресных правки кода), ленивые хэндлы на тела символов и работа для клиентов без доступа к шеллу.
Регистрация через ripwire wrap <agent> — команда печатает рецепт и никогда не правит конфиг сама:
ripwire wrap claude # напечатает: claude mcp add ripwire -- ripwire --mcp
ripwire wrap --all # обнаружить все установленные агенты
Поддерживаются Claude Code, Codex, Cursor, Windsurf, Gemini, opencode и aider. Для любого другого MCP-клиента достаточно стандартного stanza:
{
"mcpServers": {
"ripwire": { "command": "ripwire", "args": ["--mcp"] }
}
}
Навыки и визуализация
Помимо бинарника поставляется 18 задачных навыков (seventeen в релизном архиве + один контрибьюторский), которые учат агента, когда какой из 31 глагола уместен — без них у агента 175 флагов и никакой карты применимости. Устанавливаются симлинками через skills/install.sh.
Для людей есть --html: один самодостаточный HTML-файл с графом — стрелки от вызывающего к вызываемому, раскраска по сложности (cyclomatic), git-churn, языку, community-структуре или покрытию тестами. Показная деталь: пунктирные рёбра помечают вызовы, которые резолвер не смог однозначно привязать — по заверению авторов, ни один другой инструмент не отмечает, в каких именно стрелках он не уверен.
Качество кода: панель и дельта
--quality-panel автоматизирует суждения хорошего ревьюера через шесть независимых семейств доказательств, каждое из которых опирается на опубликованные исследования: форма (McCabe), нейминг (Butler), атомы запутанности (Gopstein), churn (Nagappan & Ball), колокация (Beck & Diehl), поток состояния (Henry & Kafura). Максимальная корреляция между любыми двумя семействами — +0.168, то есть они действительно меряют разное: совпадение двух семейств на одной функции — это подтверждение, а не одна метрика, посчитанная дважды.
Отдельная ставка — код, написанный самим AI: по данным GitClear, маскирование ошибок пустыми catch-блоками на +47% чаще встречается в AI-авторских коммитах, а переписывание функции в течение двух недель — на +15% вероятнее. --quality-delta проверяет дифф по 10 таким шаблонам и сообщает только то, что изменение ухудшило; --exemplar показывает образец правильного паттерна в вашем же репозитории.
Бенчмарки и «контракт честности»
На held-out срезе LocBench (60 инстансов, парное сравнение) ripwire находит все gold-файлы в топ-10 на 58.3% инстансов против 40.0% у лучшего из пяти конкурентов (codebase-memory-mcp), индексируясь за 0.31 с — быстрее, чем конкуренты заканчивают индексацию. На расширенной выборке из 243 инстансов по 78 репозиториям — 60.9% против 27.6% у собственного бейзлайна. Проигрышные инстансы названы поимённо, харнесс бенчмарка закоммичен в репозиторий, любой может всё перепроверить.
Проект ведёт себя редким для README образом: публикует собственные контрпримеры (docs/EVALS.md §7), честно называет места, где проигрывает конкуренту, и разделяет «измерено» и «не запускалось, но логично». «Контракт честности» в одну строку: любой счётчик, который нельзя доказать как полный, помечается как нижняя граница, каждое усечение раскрывается в месте возникновения, а ноль означает «не найдено», а не «не существует».
Поддерживаемые языки
22 вендоренных tree-sitter-грамматики: C, C++, Objective-C/C++, Metal, CUDA, Python, TypeScript, JavaScript, Java, Ruby, PHP, Lua, Elixir, Bash, Go, Rust, Swift, C#, плюс JSON/TOML/YAML (конфиг-ключи становятся грепаемыми символами) и Markdown — заголовки которого индексируются как символы-секции, так что --for и --recall работают и по документации. Ограничения каждого парсера (динамический диспетч в PHP, метатаблицы Lua) заявлены явно, а не замалчиваются.
Итог
ripwire — это инструмент из категории «дешёвая детерминированная карта вместо дорогого вероятностного поиска». Он не претендует на семантическое понимание кода и не прячет, где именно не уверен. Максимум выгоды он даёт там, где контекст стартует с нуля: мультиагентные оркестраторы, где каждая линия начинается холодной на одном и том же дереве, и финальные проверочные проходы (--quality-delta, --test-gate, --edit-check). На вопрос, который закрывает один grep по конкретному файлу, карта, по признанию авторов, не окупается — и --help-task прямо скажет «просто сделайте grep».
Проект распространяется под Apache 2.0, репозиторий: https://github.com/redhat-et/ripwire
Источник: https://github.com/redhat-et/ripwire