Ripwire Change Check logo

Ripwire Change Check

OrganizationPopular
redhat-et
ripwire-change-check

Merge-SAFETY of an existing diff — yours before you push, or a PR you review: blast radius, tests to run, a broken contract (--edit-check=SYM), branch conflicts and landing order, unmerged work stranded on old branches, which ref defines it. Code QUALITY → quality-bar. Even a one-line leaf fix runs --edit-check.

Overview

Publisherredhat-et
Repositoryripwire
Skill nameripwire-change-check
Stars
2.2K
Forks
141
Bundled files
Instructions only
LicenseApache-2.0
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by redhat-et on GitHub. Read the source before you install it.

Installation

Install the Ripwire Change Check AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/redhat-et/ripwire.git /tmp/ripwire
mkdir -p .claude/skills
cp -r /tmp/ripwire/skills/ripwire-change-check .claude/skills/ripwire-change-check
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Ripwire Change Check in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Ripwire Change Check on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Ripwire Change Check is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Change check with ripwire

Routing: • Estimating a change you have NOT written yet (feasibility/plan/sizing) → ripwire-before-you-build. • Did the code ITSELF get better or worse? (complexity/dup/dead delta) → ripwire-quality-bar — run it FIRST; this is the chain "did the code get worse" → "is it safe to merge". • Risk on an unfamiliar subsystem you did NOT write (not tied to a diff) → ripwire-fresh-eyes. • Writing a test for EXISTING untested code (not vetting a diff) → ripwire-write-tests. • Not sure which skill? → ripwire-router.

<dir> = repo root. Run from the repo with your working changes staged/unstaged, or check out the PR branch first. This works on a real diff — --situ, --map-diff, and --pr-context read git diff automatically.

The one-shot bundle — --pr-context[=BASEREF]

The flagship verb for this moment: a single no-LLM review-evidence bundle for the whole diff (working tree, or vs BASEREF). Per changed file: defined symbols, their callers, transitive blast radius, affected tests, co-change partners not in the diff, and owners — everything steps 1–5 assemble by hand, in one call:

ripwire <dir> --pr-context --legend=compact                # working-tree diff
ripwire <dir> --pr-context=main --legend=compact           # vs a base branch/ref
<pr-context base="working-tree" files="N"><file p="…" symbols="K">
  <impact dependents="…" files="…"/><tests count="…"/>
  <changed-symbols count="K"><s t="fn" n="…" p="…:L" callers="…"/> …

Use this first for the evidence dump; steps 1–5 below are the same ground as a narrated, one-pass walkthrough.

Scope guard: Do not turn a focused fix into a full merge audit merely because a diff now exists. Invoke this skill when the user is actually at the submit/review/merge-safety moment, or when the edit changes a contract or has unclear reach. But "obvious leaf-level fix with no signature/API change" is a claim, not a given — run --edit-check=SYM (the fast per-symbol sibling of step 8, ~ms warm) to confirm it before trusting it; a status="contract-change" result means the fix was not as leaf-level as it looked, and the full audit below is now warranted. Only a genuinely "unchanged" result plus the focused test plus git diff --check is enough to stop there, unless repository instructions require a broader gate. Never run --pr-context and then repeat its component steps without a specific unanswered question.

The header is stamped at="<sha>[+dirty]" — the commit the evidence was measured at (--pr-context, --test-gate, --quality-delta and --map-diff all carry it). Quote it whenever you paste findings into a PR comment or hand them to someone else: a review bundle outlives the HEAD it was taken from. A +dirty suffix means the numbers came from an uncommitted working tree — nobody else can reproduce them from that sha, so re-run after you commit before treating them as review evidence. Note --situ, --cochange and --owners carry no stamp — record the sha yourself if you quote them.

On a large diff the bundle can be huge — cap it with --max-tokens=N (e.g. ripwire <dir> --pr-context --legend=compact --max-tokens=8000): every changed file stays present with its structural counts (blast radius / tests / callers), the deep detail trims deepest-first, and truncated=/est_tokens= on the header report the fit. To feed an EXTERNAL reranker instead of reviewing directly, --query="…" --format=candidates (or --for=…) emits a flat <cand r= s= n= id= k= p= l=> top-K — identity + score + signature only, capped by --top-k.

  1. Situational awareness on the diffripwire <dir> --situ (Reads git diff against HEAD; or --situ=fileA.cpp,fileB.h to name the changed set explicitly.) One pass, plain text:

    • changed file count + the symbols they contain
    • transitive blast radius — everything that reaches the changed symbols
    • tests to run (--affected under the hood) — empty = no test cover for the changed code, flag it. Each named test carries run="<cmd>" when a runner is derivable (a test-dir script whose stem matches the harness, or whose text names it), so the obligation is pasteable; no run= means not derivable — never treat its absence as "there is no runner". Narrow the question to ONE function with --affected=SYM (or --affected=file:NAME when a path shares the name) instead of widening it to the whole file, and invert it with --exercises=test/<harness> to see what a given test actually covers. On a corpus where few harnesses have a runner, --affected serves the runner-less rows GROUPED: <g hops="2" n="17" p="a,b,c" run_unknown="1"/> is ONE row standing for 17 test files at the same hop distance (p= lists them comma-separated, a , inside a path written &#44;), with the not-derivable disclosure stated once for the group. Rows that DO have a run= stay single <t> rows. The obligation is unchanged — every path is still listed verbatim, and a row carries run= or run_unknown="1", never neither.
    • co-change partners NOT in the diff — files that historically move together (should they be in this change too? — the Shotgun Surgery check: one change that has to land in many places, and did not)
  2. Hotspot riskripwire <dir> --hotspots --legend=compact <hotspots> ranked by score = churn × ccx. Does any changed file appear in the top-10? A change that touches a high-score file deserves extra scrutiny; one that raises ccx in an already-churny file is a regression risk.

  3. Lint deltaripwire <dir> --lint --legend=compact <lint findings="N"> per-rule summary, then per-finding file + enclosing symbol. Cross against the changed-file list from step 1 — any finding in a touched file is one this change introduced or inherited.

  4. Missing-test seam check — if step 1 showed tests="0", run ripwire <dir> --seams --legend=compact to see whether the changed code crosses an integration seam with no test coverage. That's the gap to fill before merging.

  5. The diff's structural footprintripwire <dir> --map-diff --legend=compact Emits ONLY the symbols changed vs git HEAD, ranked — the change's footprint in one screen, without the rest of the map as noise. Add --rank-by=churn to order those symbols by git change-frequency instead of PageRank: what floats to the top is the code that changes all the time — a change touching it again is following (or feeding) a churn pattern worth asking about.

  6. Read the numbers on what you touchedripwire <dir> --metrics --legend=compact (also carried inline by --for/ --around --metrics). Cross these against your changed set:

    AttrMeansThreshold → action
    cbodistinct dependencies (coupling between objects)high (≳8, or rose vs neighbours) = fragile, hard to test in isolation → decouple: hide a dependency behind an interface or invert it
    lcom4class cohesion = # connected method components (class-kinds only)>1 = the class does N unrelated jobs (N disjoint method clusters) → split it into N types
    nestmax block-nesting depth>~4, or above the file's local median → deep-branch smell → guard clauses / extract the inner block into a named fn
    loclines in the symbolwell above the local median for its kind → size smell → split; a giant new fn is the #1 agent verbosity failure mode
    paramsparameter count>~5 → bundle related params into a struct rather than widening the signature
    testedis any indexed test reaching ittested="1" = a safety net is present; omission on this explicit metrics surface means no indexed test reaches it → add one before changing it further
    These are size-correlated signals (coupling is the validated one; complexity/size are heuristics) — read
    the delta against the file's own median, not an absolute bar. A number that was already high before your
    diff is not your regression (that judgment is ripwire-quality-bar's --quality-delta).
  7. Docs-sync checkripwire <dir> --mentions=SYM --legend=compact for each changed symbol from step 1. Any markdown doc that backtick-names a symbol you just changed is a staleness candidate — the design rationale it wrote down may no longer match the code. Skim the listed docs; update or flag the ones that describe behavior your diff altered.

  8. Run the test gateripwire <dir> --test-gate --legend=compact (the merge-safety moment, in one exit code). Packages step 1's blast radius + tests-to-run into a gate: NAMES the tests that reach your change and the untested blast radius (impacted symbols no test covers), exits 4 if either is non-empty. This queryable map cut agent-caused regressions −70% (6.08%→1.82%, TDAD) — prose reminders alone made agents worse. The gate can't watch a run; the loop is run the named tests, then rely on green. A non-empty untested list = the gap to close before you call it merge-safe.

  9. Landing several concurrent branches?ripwire <dir> --merge-scout=REF1,REF2,... --legend=compact (read-only; the dirty working tree joins automatically as an implicit extra arm). For each REF it diffs the ref's tree against its merge-base with HEAD (git-archive temp copies — nothing is checked out or mutated) and reports, per pair, same-symbol conflicts (both arms touched the identical symbol — a real merge will fight over it) and same-file/different-symbol risks (no content collision, still worth a glance), plus a <landing order="…"> — the fewest-conflicts-first sequence to land them in. Run this BEFORE picking a merge order for several agent branches instead of hand-diffing each pair.

9b. Is anything STRANDED on a branch — and was it already re-done?ripwire <dir> --stray-content --legend=compact (=SUBSTR filters ref names). --merge-scout above answers "which of these named branches collide"; this answers the prior question — of all my branches, which still hold work the live line does not have? Per ref it reports the lines that ref's own work AUTHORED (vs its merge-base with HEAD) that HEAD lacks, with a verdict: unmerged (genuinely absent — this is the queue to work), superseded (the live line removed the SAME base code this ref removed, i.e. it re-implemented the work), merged (omitted). superseded is the case git cherry structurally cannot see — it compares commit ancestry, so a fix the live line re-did differently stays "unmerged" forever, which is exactly how a finished fix sits on a branch for days behind a ledger that says "ported". Every row prints its raw del=/redone=/sim= evidence — read those before acting, the verdict is a summary, not an oracle. Line-granular, not semantic. Read-only, single-root.

9c. "Where does this content live?"ripwire <dir> --whereis=SYM --legend=compact. Which ref's tree defines or mentions a symbol, HEAD first; on-head="0" alongside branch hits is content that exists ONLY on a branch. Each distinct blob is read once (git is content-addressed), so 30 branches cost about one tree. kind="def" on a branch row is a lexical heuristic — branch blobs are raw text, never ingested; for HEAD's parsed answer use --expand/--callers. A tree scan only finds what some ref still carries, so hits="0" cannot by itself tell a name this repo never had from one it deleted. Add --with-history and a <fate> row says which: v="never", or v="removed" commit=… date=… p=… naming the commit that took it out. One git log pass, memoized per (repo, HEAD sha) and shared with --doc-drift --with-history.

9d. "Of all my branches, which still hold REAL work, and in what order should I land them?"ripwire <dir> --stray-content --plan. Composes 9b + 9 in one call: selects the refs 9b calls v="unmerged", DROPS the v="superseded" ones (<excluded reason="…"> names them — landing a superseded branch would re-do work the live line already did, exactly the waste 9b exists to catch), and feeds the survivors to 9's pairwise-conflict + fewest-conflicts-first landing-order machinery, unmodified. <ref scouted="0"> is real unmerged work NOT fed to merge-scout THIS run — a cost bound, not a verdict (bounded= on the root element counts it; --detail lifts the bound to scout everything). Cost: 9b is a cheap per-blob sweep, but 9 is per-ARM (git-archive + full ingest of each ref's tree) — measured ~3s/ref on a real C++ repo, so this is an EXPLICIT "before you land" call (pass both flags on purpose), not a per-question one. Bare --plan refuses loudly without --stray-content. Read-only; single-root only. 9d. Did a branch silently break a CPU/GPU struct's byte layout?ripwire <dir> --stray-content --legend=compact --abi (=SUBSTR filters ref names, same as 9b). Neither --layout=STRUCT (one index, the working tree) nor --stray-content (line-granular — "added a float field" is just a stray line to it) catches a branch that adds one field to a dual-compile uniform struct: the merge is textually clean, review sees a harmless "+1 field", and the CPU ends up writing more bytes than the GPU reads for — wrong pixels, no compiler error. This runs --layout's own field-offset arithmetic LEXICALLY on every ref that changed a path HEAD declares a struct/class in, and diffs the result against HEAD's computed fields. kind="drift" is a real byte-contract break (the only kind that exits 2); kind="spelling"/"stub" mirror --layout's own harmless cases; kind="unknown" is a ref-side copy that could not be modelled (its caveats ride along — never reported as unchanged); kind="absent" is a ref that does not define the struct there at all. Matching structs are omitted (report only differences). Read-only, single-root, exit 2 on a real drift.

  1. Mid-edit contract check, one symbol at a timeripwire <dir> --edit-check=SYM --legend=compact (file:name disambiguates a same-named symbol, like --around/--lego). The fast, targeted sibling of step 8's --test-gate/--quality-delta: right after you touch a function, ask "did I just change a contract someone depends on" without waiting for a full diff. Reports exactly one of status="unchanged" / "new-symbol" / "contract-change" (with params_was/params_now/public_was/public_now on the latter) vs git HEAD, plus SYM's 1-hop callers with any call-site whose argument count is now provably incompatible flagged incompatible="1". Warm (cache-hit) on ripwire's own tree. A .ripwire_notes entry on SYM (or its file) rides along as a <note> child, the same row --for/--expand surface.

  2. "Can I delete this?" for one symbolripwire <dir> --safe-delete=SYM --legend=compact (file:name disambiguates, same grammar as --edit-check/--around/--lego). The removal-side sibling of step 10: composes 1-hop callers=, the transitive --impact blast radius (impact_reaches=), every --uses read/write/import/call/extends site (uses=), how much of that radius the tested= lens covers (radius_tested=/radius_untested=), and --dead-code's own high-confidence shape at defs=1 (dead_code_candidate=), into ONE call. risk= NAMES what was found — none-found / uses-exist / untested-radius — never a go/no-go verdict; radius_untested= equal to impact_reaches= is the strongest signal ("nothing downstream is test-covered"). ambiguous_callers=/per-row amb="1" disclose the same call-graph resolution limit --edit-check's incompatible= and --for's amb= already carry.

Output

Impact summary: blast-radius count, test coverage (zero = blocking concern), whether any changed file is a top-10 hotspot, any lint findings in changed files, and any --metrics red flags (high/rising cbo, lcom4>1, or missing tested=1) on a touched symbol. A green change passes: radius understood, tests exist, no new lint smells, no hotspot surprise, no coupling/cohesion regression. Recommend one of: safe to merge / needs tests / review the hotspot / lint issues to fix / decouple before merge. (Ran quality-bar first? Both green = ship — see the Routing note above.)

Honesty: ripwire cedes data-flow/type checks (use-after-move, taint) to the compiler — pair this with the build's warnings and the test suite. Blast radius is name-based; a high-amb edge was guessed.

Frequently asked questions

What does the Ripwire Change Check AI skill do?

Merge-SAFETY of an existing diff — yours before you push, or a PR you review: blast radius, tests to run, a broken contract (--edit-check=SYM), branch conflicts and landing order, unmerged work stranded on old branches, which ref defines it. Code QUALITY → quality-bar. Even a one-line leaf fix runs --edit-check.

Why use Ripwire Change Check on TypingMind?

Because you install it once and use it with any model. Ripwire Change Check is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Ripwire Change Check in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/redhat-et/ripwire/tree/main/skills/ripwire-change-check. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Ripwire Change Check?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Ripwire Change Check?

As many as you like. As long as a model supports skills, you can use Ripwire Change Check with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Ripwire Change Check AI skill free?

Yes. It is published on GitHub by redhat-et under the Apache-2.0 license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇