skillreaper
CLI that scans AI agent session transcripts to identify and safely quarantine unused skills, MCP servers, and agents across Claude Code, Codex CLI, Hermes, OpenCode, Cursor, and OpenClaw
About skillreaper
This large README is shown as a plain-text preview. Read the full README at the source
<!-- readme-numbers:start --> ``` S K I L L ###### ####### ### ###### ####### ###### ## ## ## ## ## ## ## ## ## ## ###### ##### ####### ###### ##### ###### ## ## ## ## ## ## ## ## ## ## ## ####### ## ## ## ####### ## ## a generated sample stack, not a real install - run reap for your own numbers skillreaper · last 30d · 34 sessions 7/378 items fired · 1% utilization 371 never fired · 371 marked REAP · ~22720 dead tokens/session TOKENS CATEGORY NAME VERDICT REASON 185 skill import-timesheet REAP unused 185 skill render-playlist REAP unused 177 skill review-sitemap REAP unused 163 skill deploy-dataset REAP unused 159 skill validate-manifest REAP unused 157 skill parse-contract REAP unused 149 skill extract-receipt REAP unused 145 skill sync-changelog REAP unused 111 skill summarise-timesheet REAP unused 110 skill export-timesheet REAP unused (361 more marked REAP not shown — use --json for all) To prune: reap prune (interactive, reversible via reap restore --all) 1 warning — some evidence was incomplete; those items were held back from a REAP verdict. measured by skillreaper · github.com/thousandflowers/skillreaper ``` <!-- readme-numbers:end --> <p align="center"> <sub>Real <code>reap --agent</code> output, run against a generated sample stack (<a href="docs/gif-helpers/hero-fixture.sh">hero-fixture.sh</a>) - not anyone's install. The numbers further down are measured on mine.</sub> </p> <h1 align="center"> Most of what your AI agent loads, it never uses. </h1> <p align="center"> skillreaper finds the <b>unused skills, MCP servers, subagents, hooks and always-loaded prose</b> quietly filling your <b>context window</b> - proven from your own session transcripts - and prunes them reversibly.<br> Runs locally against transcripts you already have. Nothing is ever uploaded. </p> <p align="center"> <a href="https://github.com/thousandflowers/skillreaper/actions/workflows/ci.yml"><img src="https://github.com/thousandflowers/skillreaper/actions/workflows/ci.yml/badge.svg" alt="CI"></a> <a href="https://github.com/thousandflowers/skillreaper/issues"><img src="https://badgen.net/github/open-issues/thousandflowers/skillreaper" alt="Issues"></a> <a href="https://github.com/thousandflowers/skillreaper/releases"><img src="https://img.shields.io/github/downloads/thousandflowers/skillreaper/total?cacheSeconds=6400&color=success" alt="Downloads"></a> <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT"></a> <a href="https://github.com/avelino/awesome-go#artificial-intelligence"><img src="https://awesome.re/mentioned-badge.svg" alt="Mentioned in Awesome Go"></a> <a href="https://github.com/VoltAgent/awesome-agent-skills#community-skills"><img src="https://awesome.re/mentioned-badge.svg" alt="Mentioned in Awesome Agent Skills"></a> </p> <br> ```bash npx skillreaper ``` <!-- readme-mine-headline:start --> On my own installation, measured 2026-08-23: **382 items loaded, 13 ever fired - 3% utilization.** That's ~19,755 dead tokens re-sent in every single session, ~1087k a month of pure token waste, paid for on every request before you type anything. <!-- readme-mine-headline:end --> <sub>Measured 2026-08-23 on my own installation; raw output in <a href="docs/measurements/">docs/measurements/</a>. Every "on my own installation" figure on this page comes from that one run.</sub> **One command. Zero config.** It reads your real session transcripts, finds every skill / MCP / agent your AI loads but never fires, and shows you exactly what it costs you. <br> ## What it does skillreaper is a **measuring instrument** for your agent's context window. Pruning is one of the things you do with the measurement, not the point of it. The whole surface, in the order you use it: | Stage | Command | What it answers | |---|---|---| | **Measure** | `reap` | What do I load, what actually fires, what does the dead part cost per session? | | | `reap gap` | What share of each category is ever used, and which MCP tools fire but return noise? | | | `reap by-project` | Which project is actually firing each skill? | | **Decide** | `reap why <name>` | Why did *this* item get *this* verdict, on what evidence? | | **Act** | `reap prune` | Quarantine the dead items, reversibly | | | `reap mute <name>` | Strip a heavy rarely-used description, keep the skill callable | | **Engineer** | `reap route` | Propose a lazy-load routing plan for a library too big to prune flat | | | `reap apm` | Emit a proposed APM `apm.yml`, so a team reproduces one lean set | | **Compare** | `reap snapshot` | Keep this run, so a later one has something to be measured against | | | `reap diff` | What appeared, left, changed verdict, and did anything come back after a prune | Everything above the **Act** row is read-only. You can run the entire measurement side without changing a single file. <br> ## What it reads, what it writes | Read-only, changes nothing | Writes, always reversible | |---|---| | `reap` <sup>1</sup> | `reap prune` ↔ `reap restore --all` | | `reap gap` | `reap mute <name>` ↔ `reap unmute <name>` | | `reap by-project` | `reap keep <name>` ↔ `reap keep --remove <name>` | | `reap why <name>` | `reap install-hook` ↔ `reap uninstall-hook` | | `reap route` | | | `reap apm` | | | `reap manifest <name>` | | | `reap share` | | | `reap snapshot` <sup>1</sup> | | | `reap diff` | | **Nothing is ever deleted.** `reap prune` moves files into a `reaped/` directory with a versioned manifest, `reap mute` keeps a backup of the description it strips, and `reap uninstall-hook` removes only skillreaper's own entry, leaving your other hooks alone. Every write is **atomic** (temp file + rename) and **confined** to your Claude directory, so an interrupted prune, mute, or hook edit leaves the original file intact, never a half-written mix. <sub><sup>1</sup> The only files a read-only command writes are skillreaper's own: <code>~/.claude/reaped/nudge-state.json</code>, which the default report touches so a hint it already showed you does not repeat, and the snapshot <code>reap snapshot</code> exists to write. Neither touches your stack. Pass <code>--no-nudge</code> (or set <code>SKILLREAPER_NO_NUDGE=1</code>) and not even that happens. No command in either column sends anything over the network.</sub> <br> ## First 60 seconds Three commands, in this order. Only the third one writes anything, and it prints its own undo line. ```bash reap # 1. measure: what you load, what fires, what it costs reap why <name> # 2. decide: the evidence behind one verdict reap prune # 3. act: quarantine the dead ones, interactive ``` **1. `reap`** prints the report at the top of this page. Every row carries a verdict: | Label | Meaning | |---|---| | **`REAP(broken)`** | Invoked but errored - broken, not just cold | | **`REAP`** | Zero uses - safe to quarantine | | **`MUTE`** | Used rarely + heavy - description stripped, skill stays available | | **`KEEP`** | Used, tiny, or manually protected | | **`REVIEW`** | Too new or not enough sessions | Every verdict includes a reason suffix explaining *why*, and an item whose evidence was incomplete stays `REVIEW` rather than being flagged. **2. `reap why <name>`** is how you argue with a verdict before acting on it. It shows the whole case for one item, so you are not trusting a label: ``` skill:import-timesheet verdict REAP(unused) reason zero uses in the evidence window token weight ~185 tok (description: 684 chars) sessions 34 total in window uses 0 last seen never installed unknown keep-list no claude-md not referenced → safe to prune. run: reap prune ``` **3. `reap prune`** asks before it moves anything, quarantines what you confirm into `reaped/`, and ends by printing `reap restore --all`. If a verdict looks wrong, `reap keep <name>` protects the item permanently instead. <p align="center"><sub>The <code>why</code> output above is real, produced against the same generated sample stack as the report at the top of this page (<a href="docs/gif-helpers/hero-fixture.sh">hero-fixture.sh</a>) - so the item names are the fixture's, not anyone's install.</sub></p> <br> ## Why this exists ### Why I built this I was running out of context budget on every session. I had accumulated skills, MCP servers, and agents over months most of them experiments I'd forgotten about or be too busy to change it. Every new session loaded all of them, burning tokens before I'd typed a single message. I needed to know which ones were actually firing and which were just dead weight. Nothing existing told me that from transcript evidence. So I built it. It now supports every platform in the table below, and ships on Homebrew, npm, and as a static binary for every major OS. <br> ### Two costs of context bloat **Wrong-tool picks.** Buried in a wall of irrelevant options, your agent wastes turns reaching for the wrong tool. More turns = slower, costlier, sloppier runs. This isn't about pennies - it's about work quality. **Wasted tokens.** Dead instructions eat context every session and hurt prompt-cache hit rate. A typical setup: <!-- readme-mine-costs:start --> - 382 items loaded - 369 never fired (96 %), of which 367 marked REAP - 19 755 tok/session dead - ~1 087 000 tok/month burned on irrelevant instructions - ~$3.26/month, ~$39/year - the same waste priced instead of counted <p align="center"><sub>The money line is one measurement of one stack, n=1, and the weakest number here: <code>19 755 × 55 × $3.00 ÷ 1e6</code> - input tokens only, at <code>claude-sonnet-4-6</code>'s $3.00/MTok default, with tokens estimated as <code>ceil(chars / 3.7)</code> and the monthly session count extrapolated from a 30-day window. Change the model, the price, or how much you work and it moves; the item and token counts do not. See <a href="#limitations-transparency">Limitations</a>.</sub></p> <p align="center"><em>Measured on my own setup - 55 sessions over 30 days, 2026-08-23. Run <code>reap</code> to see yours.</em></p> <!-- readme-mine-costs:end --> skillreaper measures both, from evidence - no guessing. > `reap` points at the waste. You decide what goes. <br> ### Privacy **100 % local.** Zero telemetry, zero network, zero uploads. Reads config files and session transcripts on disk - your data never leaves your machine. <br> ### Before → After: what removing token waste buys <!-- readme-mine-table:start --> | Before skillreaper | After skillreaper | |---|---| | 382 items loaded every session | 15 kept · 13 actually fire | | 19 755 tok/session dead | Full context budget for real work | | ≈ 73 000 dead chars ≈ 29 pages every session (at 500 words/pg) | Zero | | Lower cache hit rate = higher latency | Smaller prompt fits in cache | <sub>My own installation, measured 2026-08-23.</sub> <!-- readme-mine-table:end --> <br> <p align="center">If this looks useful → <a href="https://github.com/thousandflowers/skillreaper">⭐ star the repo</a></p> ## Getting started ### Install **Inside Claude Code** - adds `/skillreaper:reap` and `/skillreaper:gap`, so the report renders in the conversation instead of a scrollback you have to re-read: ``` /plugin marketplace add thousandflowers/skillreaper /plugin install skillreaper@skillreaper ``` The plugin is a thin wrapper: it drives the same binary, so install that too with any line below. The skills fall back to `npx skillreaper` and tell you how to install permanently if they can't find it. **Install permanently** - Homebrew and npm install both names, `reap` and `skillreaper`, so either one works. `go install` gives you `reap`: ```bash # macOS — Homebrew brew install thousandflowers/tap/skillreaper # Any platform — npm (downloads the matching prebuilt, checksum-verified) npm install -g skillreaper # Any platform — Go (Go ≥ 1.24) go install github.com/thousandflowers/skillreaper/cmd/reap@latest ``` > Already installed it with Homebrew? You don't need the npm package - > both put `reap` and `skillreaper` in the same prefix, so `npm install -g` > stops at an EEXIST link error rather than overwriting brew's copy. > Pick one route: to switch to npm, run `brew uninstall skillreaper` first. > Neither affects `npx skillreaper`, which runs from a cache and never > links a global command. **Binary downloads** - macOS (Intel + Apple Silicon), Linux (amd64 + arm64), Windows (amd64 + arm64) - all on the [releases page](https://github.com/thousandflowers/skillreaper/releases). Single static binary, no dependencies. Upgrading, uninstalling, and platform-specific tips → [INSTALL.md](INSTALL.md). <br> ### Usage 💬 **Curious what `reap` finds in other setups?** [Share your output →](https://github.com/thousandflowers/skillreaper/discussions) ```bash reap # scan + report (read-only) reap gap # loaded-vs-fired utilization + MCP payload quality reap prune # quarantine REAP items (reversible) reap mute <name> # strip description, keep skill available reap unmute <name> # restore description from backup reap unmute --all # restore all muted skills reap keep <name> # protect an item from pruning reap restore --all # undo every prune reap why <name> # explain in detail why an item got its verdict reap by-project # skills bucketed by the project that fired them reap route # propose a usage-informed lazy-load routing plan (opt-in) reap apm # emit a proposed APM apm.yml from this repo's firing reap apm --diff apm.yml # reconcile: what to add (fired, undeclared) / drop (declared, cold) reap share # print a ready-to-paste line about what you reclaimed reap snapshot # save this run's --json payload for later comparison reap diff # compare the newest two snapshots reap diff <a> <b> # compare two named snapshots reap manifest <name> # emit a release manifest for one skill reap install-hook # install weekly nudge (SessionStart hook) reap install-hook --dry-run # preview without writing reap uninstall-hook # remove hook, other hooks untouched reap --json # structured JSON output reap --md # markdown report reap --days 7 # shorter evidence window reap --mute-threshold 0.20 # firing rate below which MUTE triggers (default 20%) reap version # print version ``` <br> ### Demo <p align="center"> <img src="docs/reap-demo.gif" alt="reap in action" width="800"><br> <sub>Recorded against a small sample fixture (<a href="docs/gif-helpers/demo-fixture.sh">demo-fixture.sh</a>), so the numbers are the fixture's, not a real stack's.</sub> </p> <br> ### share - the number, ready to paste `reap share` prints one line about what you reclaimed, with the install command under it. Read-only: it measures and prints, nothing else. `--json` and `--md` are there for anything that wants to post it automatically. ``` Just cut ~22.8k tokens/session of dead context from my AI agent with skillreaper. One read-only command, 100% local: brew install thousandflowers/tap/skillreaper github.com/thousandflowers/skillreaper ``` <p align="center"><sub>Same generated sample stack as the report at the top of this page - the figure is the fixture's, not mine.</sub></p> <br> ## Reading the report ### Loaded vs fired: measuring context-window utilization Beyond the prune verdicts, `reap gap` shows your **utilization rate** - how much of what you load you actually use. <!-- readme-gap:start --> ``` ── loaded vs fired · last 30 days · 34 sessions ────────────────────────────── CATEGORY LOADED FIRED UTIL TOK LOADED TOK USED skills 298 6 2% ▏▱▱▱▱▱▱▱▱▱ ~21,693 278 mcp 12 1 8% ▏▱▱▱▱▱▱▱▱▱ ? ? agents 68 0 0% ▱▱▱▱▱▱▱▱▱▱ ~1,305 0 ─────────────────────────────────────────────────────────────── total 378 7 1% ▏▱▱▱▱▱▱▱▱▱ ~22,998 278 ~ MUTE — 2 heavy low-use skills, ~102 tok/session recoverable with reap mute ``` <!-- readme-gap:end --> <p align="center"><sub>Same generated sample stack as the report at the top of this page, so the two agree. The numbers further up the page are measured on mine.</sub></p> Each row breaks down by category (skill, MCP, agent) with item count, token weight, and a 10-segment utilization bar. The token column reads *loaded → actually used*: the left number loads every session, the right is all that is ever touched - the gap between them is dead weight that reloads each time. Low utilization (<10 %) is red, medium (<50 %) yellow, high (≥50 %) green. The default `reap` report also includes a compact utilization summary line: <!-- readme-utilization:start --> ``` utilization 1% 7/378 items fired · ~278/22998 tok touched (30d) ``` <!-- readme-utilization:end --> <p align="center"><sub>Same generated sample stack, not my install - as with the two blocks above it.</sub></p> This is the **real** gap between what your agent carries and what it fires - complementary to the shock box (which only counts items that are safe to prune right now). <pre>reap gap # text breakdown reap gap --json # JSON output reap gap --md # markdown table</pre> The gap view also scores **payload quality** for MCP tools: when a tool fires, is the result signal or noise? A fetch/screenshot tool can fire 80× and return mostly base64 or boilerplate every call - green under load utilization, but context burned on each call. Tools that fire often *and* return mostly noise are flagged `⚑ noisy`. This is the second utilization axis (load is the first), and mute does not catch it. <br> ### by-project - which project actually fires each skill A skill that looks cold across the whole window is often a skill that is alive in exactly one repo. `reap by-project` buckets each fired skill by the project that fired it, one row per skill-and-project pair, and marks a skill that fired in exactly one project as `repo-local` - the case this view exists for, since a per-repo tool should not be read as global dead weight. ``` ── skills by project · last 30 days · 34 sessions ──────────────────────────── SKILL PROJECT FIRINGS NOTE audit-backlog acme-platform 17 repo-local audit-catalog acme-platform 11 repo-local audit-changelog acme-platform 8 repo-local audit-contract acme-platform 6 repo-local audit-dataset acme-platform 5 repo-local audit-invoice acme-platform 4 repo-local ``` <p align="center"><sub>Same generated sample stack as the blocks above. This capture is one of the files <code>make renders-check</code> verifies, so it cannot drift from what the binary prints.</sub></p> <pre>reap by-project # text table reap by-project --json # JSON output</pre> <br> ## Beyond pruning ### route - context engineering for large tool libraries After pruning, a library of hundreds of legit skills still grows resident context linearly. `reap route` proposes a category-router organization driven by **real firing evidence**, not text similarity: frequently-fired skills stay exposed; the rare long tail is pushed behind leaf routers (grouped by namespace, else dominant firing project) loaded on demand. It is strictly opt-in and
Frequently Asked Questions
What is skillreaper?
skillreaper is a Artificial Intelligence library for the Go programming language. CLI that scans AI agent session transcripts to identify and safely quarantine unused skills, MCP servers, and agents across Claude Code, Codex CLI, Hermes, OpenCode, Cursor, and OpenClaw
How do I install skillreaper?
Install skillreaper with the Go module system using `go get thousandflowers/skillreaper`. Check the repository for the current installation instructions.
What category does skillreaper belong to?
skillreaper is listed under Artificial Intelligence, specifically Artificial Intelligence.