subagent-driven-development
OBobra/superpowers298k2,631 new stars in the last 7 days
Wire ripwire into an agent as an MCP server — `ripwire wrap AGENT` (Claude Code, Cursor, Codex, Gemini…) — and choose the server verb mid-task. Also tool HEALTH: a symbol you expected is missing from the ranked output, the index feels stale after a rebase, 'is my ripwire setup broken?'
Auditing somebody's
.mcp.jsonfor safety instead → ripwire-security-scan.
Trigger: "wire ripwire into my agent", "set up the ripwire MCP server", or "which ripwire MCP verb answers this?".
The 33 verbs, at a glance: 17 read verbs (analyze, rank_by — the same map, ranked by
authority/hub/rrf instead of plain PageRank — for, find_symbol,
find_referencing_symbols, grep, cochange, memory_recall, situational_awareness, mentions,
owners, lego, batch — N read sub-queries in ONE call — fetch_body, and flags — what is BUILT but
DARK here: every compile / CMake option() / getenv gate with its default and the size of the code it
guards, the answer to "why don't I see feature X?", and doc_drift — which of the repo's markdown claims
are now FALSE: dead file:line anchors, deleted symbols, = N constants and [N] extents the code has
since changed; call it before trusting a design doc or audit you did not just write, and slice — per-line
def-use rows of ONE variable inside ONE definition, flow=back|fwd|both for the transitive data-flow
slice, @FILE:LINE seeds by location and pre-picks the variable the seed line names) + 13 flagship-reflex verbs
(exemplar, quality_delta, quality_baseline, impact, uses, affected — which tests transitively
reach a changed file/symbol, the pre-PR "what do I run?" reflex — path_between, connect — the
minimal joining subgraph over N task symbols — the L4 one-call/B11-parity trio explore, from_trace,
edit_check — so an MCP-only agent gets the same write & done reflexes as the CLI — and the CROSS-BRANCH
pair whereis / stray_content, which answer "where does this content live?" across every branch: the
question git cherry cannot, since it compares commit ancestry and every other verb indexes one worktree.
stray_content marks a branch superseded when the live line re-implemented its work, which is exactly
the case git cherry calls unmerged forever; whereis lists the definitions and counts the references
(listing="defs" on the root) when that page lists MORE definitions than the whole list would under the same row
cap, or the same ones in strictly fewer bytes — listing:"all" asks for every row) + the 3 span-addressed
edit verbs (replace_symbol_body, insert_before_symbol, insert_after_symbol). Only find_symbol and
find_referencing_symbols attach a stable handle= instead of the body (fetch it only when you need it,
via fetch_body); the edit verbs enforce a safety contract (staleness refusal, ambiguity refusal, atomic
writes) detailed below and in full in mcp-reference.md.
The server exposes 33 MCP verbs: 17 read verbs (incl. rank_by/fetch_body/flags/slice), 13 flagship-reflex
verbs (affected/connect/explore/from_trace/edit_check and the cross-branch pair whereis/stray_content) and
3 edit verbs — ripwire wrap codex --force prints the live count.
ripwire wrap <agent> prints the reciperipwire wrap claude # → claude mcp add ripwire -- ripwire --mcp
ripwire wrap cursor # → JSON mcpServers stanza for .cursor/mcp.json (also: windsurf, gemini)
ripwire wrap codex # → TOML stanza for ~/.codex/config.toml
ripwire wrap opencode # → CLI first (AGENTS.md is read automatically); its config key is "mcp", NOT mcpServers
ripwire wrap aider # → no MCP: ripwire . --for="<task>" > .ripwire-map.txt; aider --read .ripwire-map.txt
ripwire wrap --all # → auto-detect installed agents, emit each one's config in one run
wrap never edits config itself — it prints; you review and run. Before printing it security-scans
./skills and .agents/skills: a CRITICAL finding blocks the recipe (exit 1) unless you pass
--force; WARNs print and continue. Bare ripwire wrap lists the supported agents.
Run ripwire <repo> --doctor --agent=codex after install/update or when Codex appears to be using a stale
binary, missing a skill, skipping the advisory CLI-first hooks, or starting the wrong MCP executable. This
extends the ordinary six-check doctor with four read-only checks over the LIVE environment: PATH binary
agreement, exact parity between the installed skills and .ripwire-manifest-v1, executability of all three
Codex hook roles, and the configured mcp_servers.ripwire command plus --mcp argument. Failing rows give
the exact installer/wrap repair command. The report deliberately emits no config contents or full shell
commands, so it is safe to paste for diagnosis; --agent=codex alone refuses because it modifies doctor.
_memory_stop$HOME, / and system directories are never a project root over MCP — not as the launch directory and not as
path=: pass the project directory itself (a server started as ripwire ~ --mcp still answers about ~). A tool call refused with "memory limit reached", or an answer carrying _memory_stop
in its envelope, means the memory guard cut or refused the work on a tree too large for the machine: point
path= at a smaller root, or raise the limit with --max-memory=<N>[K|M|G] (or RIPWIRE_MAX_MEMORY) on the
server's command line. The default (65% of RAM) is silent on real projects.
Every verb takes path (the repo root; memory_recall takes the docs/memory dir). For a split
service+client checkout, pass paths: [dir1, dir2, ...] instead — the additive multi-root array (path and
paths together is a usage error; the 3 edit verbs accept it too, and land a write in the correct root's
real file via its label). The server keeps ONE cached workspace per canonical root set: a paths list is
deduped and ordered before it's used as the cache key, so calling with the same roots in a different order
still hits the warm cache instead of re-parsing; a genuinely different root set gets its own cache entry, not
a shared/stale one.
Line-seeded addressing — @FILE:LINE in any resolver-backed selector. Holding a LOCATION (a diff hunk,
a compiler error, a stack frame) instead of a name? Pass @src/foo.cpp:120 (1-based line) as the selector
and it resolves to the innermost definition enclosing that line — accepted by find_symbol /
find_referencing_symbols / impact / edit_check / path_between (from/to) / connect (each entry) /
lego (type) / fetch_body (handle), and by uses (which serves the enclosing definition's NAME —
its sites stay name-matched, of= echoes the seed as typed). A bad seed — malformed spec, unmatched or
ambiguous path, line past EOF, a line no definition spans, two definitions sharing the line — is refused
with the same specific diagnosis the CLI's --at/selector arms speak, never guessed. The NAME-matching
scan verbs (owners, mentions) do not resolve seeds; a resolvable seed there refuses by naming the
definition it resolves to, so the retry is in the message. CLI twin: --at=FILE:LINE (the bare
enclosing-chain report) and @FILE:LINE in any SYM selector; contract gate: test/atcheck.sh +
test/mcpverbscheck.sh §7.
| Verb | CLI twin | Ask it for |
|---|---|---|
analyze | ripwire <dir> | the ranked XML map |
for (task) | --for=TASK | the task lens: signatures + cx/in metrics framed for reuse. Auto-routes the ranker — pass a symbol NAME verbatim as task to get name-exact retrieval (recall@1 ~99%); a conceptual phrase uses subtoken+body. Root carries route= as a code (name-exact(X) / subtoken+body[:broad|:declined]). |
find_symbol (symbol) | --callers + --callees | locate a symbol with its callers AND callees in one call — each symbol carries a handle |
find_referencing_symbols (symbol) | --callers=SYM | just who references/calls it — also handle-bearing |
grep (pattern) | --grep=STR | parallel literal scan + enclosing symbol + matched line |
cochange (file) | --cochange=FILE | the lockstep git partners of one file |
memory_recall (task, top_k + budget_tokens optional) | --recall=TASK [--top-k=N] [--max-tokens=N] | full bodies of the few relevant docs/memory notes, bounded by the SAME default 8000-token body ceiling as the CLI (the header discloses max_tokens= and every cut). budget_tokens raises the ceiling explicitly when you want everything; top_k (default 8) shapes how many docs |
situational_awareness (diff/files optional) | --situ | blast radius, tests_to_run, forgotten co-change partners (the Shotgun Surgery check), hotspot alert — as JSON; defaults to git diff HEAD. In tests_to_run, situational_awareness uses test; explore and edit receipts use p. The field is a path string OR an array of paths beside n — several runner-less tests sharing their attributes, served as one row — and every row carries run or run_unknown: true |
mentions (symbol) | --mentions=SYM | which markdown plans/designs discuss a symbol |
owners (symbol optional) | --owners[=SYM] | bus-factor: recency-weighted author ownership |
lego (type) | --lego=TYPE | an interface's method contract + every implementor (own-language) |
fetch_body (handle) | --expand=SYM | the FULL source of one symbol's definition, addressed by a handle from a prior read verb |
batch (queries) | --batch=FILE | a one-turn context sweep: up to 16 heterogeneous read sub-queries (for/grep/impact/uses/callers/callees/mentions/…) answered in ONE round-trip, merged in order and deduped (<dup-of q="i"/>); a failing sub-query is an inline ok="0" entry, never a whole-batch failure. Reach for it when a task needs several lookups at once. |
The flagship-reflex verbs (added 2026-07 so an MCP-only agent gets the same reflexes as the CLI) — these are the moments an agent most often skips the tool for; reach for the verb, not a grep:
| Verb | CLI twin | The moment |
|---|---|---|
exemplar (kind or task) | --exemplar | BEFORE you write a fn/class/… — the repo's best-in-class instance to imitate, chosen by ROLE (fan-in / cognitive-cx / tested), with its body |
quality_delta (path) | --quality-delta | BEFORE you call it DONE — only what the working tree made WORSE vs the baseline (auto-compares vs git-HEAD; a non-empty regressions array is the exit-2-equivalent) |
quality_baseline (path) | --quality-baseline | pin the quality floor (writes the HEAD-stamped .ripwire_quality_baseline) — a side-effect verb |
impact (symbol, limit/offset optional) | --impact=SYM [--limit=N --offset=M] | "is it safe to change X" — the TRANSITIVE blast radius (beats find_referencing_symbols, which is 1-hop). reaches= is the true radius; the listing shows 40 by rank unless you raise it, and a paged answer carries has_more/next_offset so a loop can terminate |
uses (symbol) | --uses=SYM | the resolvable USE-SITES — call/read/write/import/extends, not just calls (count=0 is a real answer; counts_floor="1" — a floor, never a total) |
path_between (from, to) | --path=A,B | does A reach B, and the shortest call path (named path_between — path is the root-arg key) |
connect (symbols) | --connect=A,B,C | the minimal subgraph joining N (>2) task symbols — the shared-caller join a directed path_between can't see |
explore (task, budget_tokens + partition optional) | --pack-task=TASK [--partition=N] | ONE-call task orientation — routed ranking + full bodies + 1-hop callers + field notes + tests_to_run, ALL under one deterministic byte budget (default 6000 tokens). Replaces the for → fetch_body → find_referencing_symbols → memory_recall dance. Also dispatchable as pack_task (same handler; explore is the one advertised in tools/list — the discovery-friendly name). partition: 2..16 turns it into the FAN-OUT form for a multi-agent orchestrator: a shared common core plus N minimally-overlapping per-agent slices carved along the call graph's communities, so N sub-agents stop re-deriving one map — budget_tokens then means ONE agent's budget (core + its slice). Read overlap_max / split / partitions vs requested on the wrapper before trusting the slices |
from_trace (trace, budget_tokens optional) | --from-trace=FILE | paste a stack trace / sanitizer report / compiler error → the frames mapped onto indexed symbols, ranked INNERMOST-first, with the innermost in-corpus symbol's FULL body. trace = the raw trace TEXT (no stdin/file arg over MCP — paste it, don't hand-translate it into a query) |
edit_check (symbol) | --edit-check=SYM | just edited a symbol? did its CONTRACT (params/publicness) change vs git HEAD, and which 1-hop callers are now PROVABLY incompatible? Fast targeted check — for the same question over a whole diff use quality_delta instead |
MCP beats the CLI when you're mid-task and will ask more than once: the server keeps the parsed
{ingest, graph, rank} in memory, so after the first parse every verb answers warm (~ms, no shell
round-trip). The CLI still wins for what no verb exposes — --expand/--outline, --around,
--deps/--hotspots/--clones, --graph-query, --arch, --pr-context, --scip, --lint-rules,
--export, and the two remaining B11 verbs with no MCP twin — --merge-scout (multi-ref UX doesn't map
cleanly onto a single JSON-RPC call) and --note-add/--notes (a write verb; adding it needs the same
safety-contract thinking the 3 edit verbs got) — shell out for all of these even with the server running;
the on-disk warm cache keeps them fast too.
Team/CI: commit the warm cache as an index artifact. ripwire <dir> --index-out=BASE cold-parses once,
writes BASE.lean.ripwirecache + BASE.rich.ripwirecache (--for/--exemplar/--metrics need RICH), then
exits with no map. Generate on main, commit or CI-cache it, restore with --cache=BASE.lean.ripwirecache (or
.rich.) in PR jobs so only changed files re-parse — a same-arch SPEED cache that self-heals to a cold parse
if stale or cross-arch (correct, slower). See README "The committable index artifact".
--listen (Streamable HTTP) — opt-in, security posture is the featureBy default --mcp speaks JSON-RPC over stdio (one co-located agent). For a team sharing one warm
index, --listen=HOST:PORT serves the same verbs over Streamable HTTP (protocol 2025-11-25)
instead — byte-identical JSON-RPC, only the transport differs, single-threaded against one warm index.
The security posture is the whole point (a 2026 survey found ~200K MCP servers naively bridged to the
open internet with no auth — ripwire is built so it cannot become one by default): loopback-only by
default; a routable host needs both the explicit host flag and a bearer token or the server refuses
to start; no TLS built in (reverse-proxy it); one listener pins to ONE workspace at startup; and the 3
edit verbs are refused over remote unless you pass --allow-remote-edits (which also forces the token).
Full flag/env reference, the curl recipe, and each refusal's exact wire behavior →
mcp-reference.md.
--lsp (navigation LSP server) — read-only, Phase 1--mcp answers agents and --listen serves a team; --lsp answers editors: a read-only,
navigation-focused LSP 3.x server over stdio — lifecycle (initialize/shutdown/exit) plus
definition, references, documentSymbol (member variables merged into the outline), workspace
symbol, and hover. Same warm index as --mcp — no second parser, no second process. Saved-state
answers only: an unsaved buffer is absent from the index, not mispositioned, and every count is a
floor, not a total (the hover text says so in place, since JSON-RPC results have no metadata channel).
UTF-8 positions; refuses to combine with --mcp/--listen — one protocol per stdin. The PoC plan and
its locked decisions live in docs/LSP.md.
find_symbol and find_referencing_symbols attach a stable handle to every symbol object they return
(the focus symbol, each caller, each callee) — but not the body. Call fetch_body{path, handle} only
when you actually need to read the source, instead of the server sending bodies you didn't ask for. This is
the kit-style default-lean posture (measured ~90% cut on comparable extract-symbol calls) and matches the
2025-11-25 MCP spec's move to stateless HANDLE semantics.
sym#<idHash>@<contentHash>, both 16 lowercase hex (FNV-1a-64) — idHash from the
symbol's STABLE canonical id (path::scope::name, never the per-run NodeId), contentHash pinning the
file's bytes at mint time.fetch_body
refuse rather than serve a body against shifted byte offsets — call a read verb again for a fresh handle.
A malformed/unresolvable handle refuses the same way, never a silent wrong-symbol body.find_symbol/
find_referencing_symbols fresh each session and read the handle it hands back.On the stdio server the legend session opens with the first answer that carries a legend (served inline) or
with a read of the MCP resource ripwire://legend-dict (initialize names it). After that, the verbs that take
legend (and for) answer rows first and end with <about … legend="ref" dict= dictv=/>, which carries the
root attributes; a definition arrives once per session, in a comment after the rows of the first answer that
needs it (an answer whose ref form would be longer stays inline). Lost the definitions (a compacted context)?
Read ripwire://legend-dict/full for all of them, or print them with ripwire --legend-dict.
legend:"compact" on one call keeps that answer's legend inline; a server started with
--mcp --mcp-legend=inline keeps every answer's legend inline. The HTTP transport (--listen) keeps every
legend inline.
replace_symbol_body, insert_before_symbol, insert_after_symbol — the last 3 of the 30 (see above),
ripwire's MCP WRITE verbs. The preferred shell front door is
ripwire ROOT --replace-symbol-body=SYM --edit-payload=FILE|- (or the matching insert flag); use MCP when
the server is already warm or a client has no shell. Both fronts call the same safety engine. Each locates
a symbol's definition in the parsed index and splices text at its byte span: replace_symbol_body
swaps signature-through-closing-brace verbatim, insert_before_symbol/insert_after_symbol splice text at
the def's first/final byte (auto-adding the separating newline so you don't have to guess).
The receipt already answers "what now?" — it carries lines={start,end} for the applied text,
edit_check (status / callers / incompatible / each broken caller's call lines) and tests_to_run with the
run recipe: the same answers a separate edit_check verb and --affected would give, computed on the index
the edit just refreshed. Do not spend two more calls on them. post_check:false (CLI --no-post-check)
opts out — reach for it only when the next thing you do is another edit to the same tree.
Read mcp-reference.md before calling one of these 3 (full args table + the exact
newline rule + the safety contract for not-found / ambiguous / stale-index / insane-span failures + the
atomic-write guarantee) or when you need server internals (--mcp implies --stable, _index staleness
stamps, warm content-hash rebuilds, working-set PageRank personalization, the background qsnap HEAD-warm on
large workspaces). Short version: every edit-verb failure leaves the file byte-for-byte unchanged, writes are
atomic (tmp + rename(2)), and the server never goes stale silently — it rebuilds warm from mtime checks
before every verb call. Lead with this MCP form when the body already came from fetch_body this
session; after a CLI --expand, keep the zero-standing-schema CLI path and use --edit-payload=-.
Several harnesses' native Edit tool
needs a fresh Read of the file immediately before the edit, even when you already have the body from
elsewhere in the session — these verbs check their own staleness hash instead of requiring one, so under any
harness the file gets read at most once, never twice.
Workspace pin (stdio, D3/D4): when the server was started ripwire <root> --mcp, an omitted
path on ANY verb (read or edit) defaults to that startup root; the 3 edit verbs above additionally
REFUSE (file byte-identical, same contract as every other refusal above) if an explicit path resolves
outside it — path outside workspace; start the server on that root or pass an absolute in-root path.
Read verbs stay unrestricted at any path. A bare ripwire --mcp with no startup root is unchanged: every
verb still requires its own path.
OBobra/superpowers298k2,631 new stars in the last 7 days
MAmattpocock/skills288k10,178 new stars in the last 7 days
MAmattpocock/skills288k10,178 new stars in the last 7 days
MAmattpocock/skills288k10,178 new stars in the last 7 days
AFaffaan-m/ECC278k4,046 new stars in the last 7 days
AFaffaan-m/ECC278k4,046 new stars in the last 7 days