Default command — shown above. Sorts every skill name into the four buckets, with a plugin-rollup pass that collapses fully-dead plugins into single uninstall rows.
audit which Claude Code skills you actually use — same parser surfaces both dead installs and hallucinated invocations, so it's not just a graveyard, it's a two-sided audit of where your setup is over- and under-provisioned.
01 what it sorts
Each skill name that appears in your local ~/.claude/projects/**/*.jsonl ends up in exactly one of these.
The skill is present in ~/.claude/skills/, an ~/.agents/skills/ dir, a plugin install path, or a project-scoped .claude/skills/ — and Claude actually called it within the audit window.
Sits on disk loading its description into every session's context — but Claude never calls it. prune emits source-aware removal commands; for plugins where every skill is dead, it rolls up to a single uninstall.
The call resolved successfully but no SKILL.md matches in any scanned path. Usually a skill registered by another framework Claude Code runs inside (paperclip, custom orchestrators) or installed somewhere unconventional.
Mostly Claude confusing tool names with skill names (bash, read, edit). suggest classifies these into actionable groups: tool/skill confusion, likely typo, external framework, unclassified.
02 live audit
Below: the actual output from the author's machine. 160 sessions, 379 skill calls, 30-day window.
──────────────────────────────────────────────────────────── skill-graveyard — 30d audit 65 installed 13 active · 52 dead · 4 missing 20% used 160 sessions, 379 calls, 93 errored +29 hallucinated names (telemetry) ──────────────────────────────────────────────────────────── ACTIVE (13) installed and invoked — keep superpowers:brainstorming 83 just now plugin:superpowers superpowers:writing-plans 56 just now plugin:superpowers superpowers:subagent-driven-development 53 just now plugin:superpowers superpowers:systematic-debugging 13 16h ago plugin:superpowers frontend-design:frontend-design ▏ 3 just now plugin:frontend-design task-management ▏ 1 15h ago user … MISSING (4) resolved but source not located — project-scoped or external framework paperclip 47 calls (14d ago) para-memory-files 15 calls (14d ago) paperclip-create-agent 5 calls (14d ago) update-config 3 calls (4h ago) → skill-graveyard suggest for actionable classification HALLUCINATED (29 names, 91 calls) Claude→tool/skill confusion, mostly noise top: bash (18), read (18), batch (6), commit (6), edit (6) → skill-graveyard suggest for actionable classification DEAD (52) installed, 0 invocations in 30d — removal candidates plugin rollups (4) every skill of the plugin is dead — uninstall whole plugin plugin:figma 9 skills claude /plugin remove figma@claude-plugins-official plugin:claude-mem 6 skills claude /plugin remove claude-mem@thedotmack plugin:supabase 2 skills claude /plugin remove supabase@claude-plugins-official plugin:skill-creator 1 skill claude /plugin remove skill-creator@claude-plugins-official individual (34) user (26) adr-skill, ai-elements, ai-sdk, canvas-design, docker-expert, github-actions-docs, helm-chart-scaffolding, helm-debugging, … → skill-graveyard prune --only user
captured 2026-04-29 from sfrangulov's machine. the headline answer: 20% of installed skills carry their weight; 80% are inert metadata in every session's context.
03 five subcommands
audit is the default and is what you usually run. The other four turn its output into actions.
Default command — shown above. Sorts every skill name into the four buckets, with a plugin-rollup pass that collapses fully-dead plugins into single uninstall rows.
Reads the audit and emits a removal plan. Source-aware: user/agents get unlink (executed with --apply); plugin gets the slash command to paste into Claude Code (always print-only — invoking /plugin remove from outside the runtime is fragile); project is left alone.
skill-graveyard prune — 30d window (mode: dry-run) plan: 26 unlinks, 4 plugin removals WOULD UNLINK (26) user (26) ~/.claude/skills/adr-skill ~/.claude/skills/ai-elements ~/.claude/skills/ai-sdk ~/.claude/skills/canvas-design ~/.claude/skills/docker-expert ~/.claude/skills/github-actions-docs … PLUGIN REMOVALS (4) run inside Claude Code: claude /plugin remove figma@claude-plugins-official # 9 skills, all dead claude /plugin remove claude-mem@thedotmack # 6 skills, all dead claude /plugin remove supabase@claude-plugins-official # 2 skills claude /plugin remove skill-creator@claude-plugins-official # 1 skill re-run with --apply to execute the unlinks (plugin removals always print only)
Classifies missing and hallucinated rows into actionable buckets so the noise becomes triage-able.
skill-graveyard suggest — 30d window 33 unique names, 161 calls, 3 actionable groups EXTERNAL FRAMEWORK (3 names, 67 calls) registered by another framework Claude Code runs inside — document in CLAUDE.md ~/.paperclip/ 3 names, 67 calls paperclip, para-memory-files, paperclip-create-agent TOOL/SKILL CONFUSION (9 names, 56 calls) Claude invoked a built-in CC tool name as a skill — known model failure mode bash (18), read (18), edit (6), Read (6), Bash (3), agent (2), grep (1), write (1), Write (1) UNCLASSIFIED (21 names, 38 calls) no matching pattern — review manually batch (6), commit (6), update-config (3), pdf (3), agents (2), help (2), shell (2), code (1), …
Same parser, different cut: groups every skill invocation by the cwd recorded in the session log. Surfaces project-scoped vs. global usage and per-project hallucinations.
──────────────────────────────────────────────────────────── skill-graveyard projects — 30d 28 projects 167 sessions, 379 skill calls ──────────────────────────────────────────────────────────── ~/projects/client-analytics 53 ses, 127 calls, 11 skills superpowers:brainstorming 50× superpowers:writing-plans 32× superpowers:subagent-driven-development 31× ? update-config 3× find-skills 1× frontend-design:frontend-design 1× …and 3 more ~/.claude-mem/observer-sessions 33 ses, 93 calls, 30 skills · 93 errored ✗ bash 18× ✗ read 18× ✗ batch 6× ✗ commit 6× …and 26 more ~/projects/clientco/web-platform 18 ses, 52 calls, 8 skills superpowers:brainstorming 18× superpowers:writing-plans 12× … sorted by total skill calls. ✗ = hallucinated (errored). ? = invoked but not installed.
Estimates how many tokens your skill metadata consumes per session vs. how many of those tokens cover skills Claude actually invokes. Each SKILL.md description is loaded into the Skill tool definition on every API request — even if the skill is never invoked.
──────────────────────────────────────────────────────────── skill-graveyard cost — 30d window 65 skills × avg 48 desc tokens = ~3.1K loaded per session × 160 sessions ≈ 501.4K of skill-metadata loaded over window of which ~497.2K (99%) loaded for skills never invoked (52 dead) ──────────────────────────────────────────────────────────── HOOK INJECTIONS per-session text from SessionStart hooks SessionStart 2541 t/sess × 72 sessions = 182.9K TOP WASTERS (15 of 64) desc tokens × sessions where never invoked playwright-best-practices user 207 t × 0/160 33.1K figma:figma-generate-design plugin:figma 185 t × 0/160 29.6K ai-sdk user 152 t × 0/160 24.3K supabase:supabase plugin:supabase 125 t × 0/160 20.0K figma:figma-use plugin:figma 108 t × 0/160 17.3K … EARNING THEIR KEEP top by invocation rate superpowers:brainstorming plugin:superpowers 34 t × 62/160 3.3K superpowers:writing-plans plugin:superpowers 17 t × 49/160 1.9K superpowers:subagent… plugin:superpowers 12 t × 49/160 1.3K note: token counts via cl100k_base (proxy for Claude tokenization; off by 5–15% in practice).
Checks every installed plugin (against its marketplace's marketplace.json) and every git-tracked user/agent skill (against git ls-remote) for newer versions upstream. Network-bound — the only subcommand that calls out. Results cached at ~/.cache/skill-graveyard/outdated/ with a 60-minute TTL by default.
skill-graveyard outdated — checked just now (3 cache hits) plan: 12 plugins, 1 skill repo · 2 outdated · 9 up-to-date · 2 unknown OUTDATED (2) plugins (1) superpowers@claude-plugins-official b7a8f76 → 6efe32c → claude plugin update superpowers@claude-plugins-official affects: brainstorming, executing-plans, writing-plans (and 11 more) skill repos (1) ~/projects/my-skills abc1234 → def5678 → git -C ~/projects/my-skills pull --ff-only affects: foo, bar UNKNOWN (2) claude-mem@thedotmack unknown → 1abc234 → claude plugin remove claude-mem@thedotmack → claude plugin install claude-mem@thedotmack reason: installed without version metadata; reinstall to refresh
Each plugin is matched against its marketplace entry shape: explicit version, pinned commit SHA, or upstream HEAD via git ls-remote. Plugins recorded as installedVersion: "unknown" get a reinstall hint instead of an update one — Claude Code only stamps the SHA on fresh installs.
all output above is real — captured locally with npx skill-graveyard <cmd> --days 30 --no-color.
04 install
No install. Just run it. Best for the first try.
Installs the binary on your PATH.
Install as an Agent Skill — Claude auto-discovers it in any session. Same command also installs the sister mcp-graveyard skill.
05 notes
~/.claude/projects/**/*.jsonl for invocations and cwd; installed_plugins.json for plugin paths; ~/.claude/skills/, ~/.agents/skills/, plugin install dirs, and <cwd>/.claude/skills/ walking up to $HOME for project-scoped skills.
Anthropic doesn't ship a public tokenizer for Claude 3+. cl100k_base (gpt-tokenizer) is the closest defensible proxy — expect 5–15% drift. Anthropic prompt caching reduces dollar cost; loaded tokens still consume your context window and rate-limit budget.
Plugin removal is a Claude Code slash command and invoking it from outside the runtime is fragile, so prune only prints the command. Run it inside Claude Code yourself.
Skills under <project>/.claude/skills/ are intentional per-project artifacts; prune ignores them.
outdatedFive of the six subcommands are entirely local. outdated is the explicit exception: it fetches each registered marketplace's marketplace.json and runs git ls-remote against marketplace and skill-repo origins. Results are cached at ~/.cache/skill-graveyard/outdated/. Everything else stays local. No telemetry, no hidden uploads.
Every subcommand accepts --json for machine-readable output. Custom queries like --json | jq '.rows[] | select(.category=="dead") | .invokeName' just work.
06 companion
A single MCP server can advertise 50 tools — full JSON schemas — adding hundreds of tokens to every API request whether or not Claude calls them. mcp-graveyard surfaces the same dual signal as skill-graveyard: dead servers (configured in ~/.claude.json, never invoked) and hallucinated calls (InputValidationError on tool names that don't exist on the connected server).
Same install pattern as skill-graveyard.
Installs the binary on your PATH.
Install as an Agent Skill — Claude auto-discovers it in any session. Same command also installs skill-graveyard.
Default command. Sorts every MCP server into the four buckets — active (configured and called successfully), dead (configured but never called), missing (called but not in ~/.claude.json), hallucinated (called and rejected with InputValidationError). Server-first; --tools <server> drills down per-tool.
mcp-graveyard — 30 days · 8 servers configured · 143 calls · 112 succeeded · 31 errored ACTIVE (3) configured and invoked — keep plugin_supabase_supabase 47 tools, 5 invoked, 89 calls last 2026-04-28 plugin_playwright_playwright 3 tools, 3 invoked, 34 calls last 2026-04-27 plugin_claude-mem_mcp-search 4 tools, 4 invoked, 12 calls last 2026-04-29 DEAD (3) configured, 0 invocations in 30d — removal candidates pencil 0 tools, 0 invoked, 0 calls — plugin_figma_figma 0 tools, 0 invoked, 0 calls — claude_ai_Gmail 0 tools, 0 invoked, 0 calls — HALLUCINATED (1) tool name returned InputValidationError — server registered but call failed plugin_supabase_supabase 0 tools, 0 invoked, 2 calls last 2026-04-22 → mcp-graveyard suggest for actionable classification MISSING (1) invoked but not found in ~/.claude.json — external registration or stale log old-analytics-server 1 tools, 1 invoked, 3 calls last 2026-04-16 → mcp-graveyard suggest for actionable classification → run: mcp-graveyard prune to clear DEAD servers
Reads the audit and emits a removal plan for DEAD servers. Print-only by default. --apply writes a 0o600 backup of the full mcpServers entry (command, args, env — env may contain API keys) to ~/.claude/mcp-graveyard-backup/<ISO>.json, then runs claude mcp remove sequentially per server. Continues on individual failures. Pre-flight checks claude --version before any I/O.
mcp-graveyard prune — plan: 3 servers to remove (0 successful calls in 30 days) pencil claude mcp remove pencil plugin_figma_figma claude mcp remove plugin_figma_figma claude_ai_Gmail claude mcp remove claude_ai_Gmail re-run with --apply to execute (backup is automatic)
Same parser, different cut: groups every MCP call by the cwd recorded in the session log. Surfaces servers that are configured globally but only used in one project — a signal to consider moving them to <project>/.mcp.json. Inline (N hallucinated) tags flag projects where Claude is calling tool names that don't exist.
~/projects/client-analytics 17 ses, 39 calls, 2 servers plugin_supabase_supabase 31× plugin_claude-mem_mcp-search 8× ~/projects/clientco/web-platform 2 ses, 2 calls, 1 server ✗ plugin_supabase_supabase 2× (2 hallucinated) ~/projects/landing 5 ses, 8 calls, 1 server pencil 8×
Classifies missing and hallucinated server names into actionable buckets — TYPO (closest configured server within Levenshtein 2), TOOL_CONFUSION (Claude called a built-in CC tool name as if it were an MCP server), UNCLASSIFIED (no pattern matched). Each row carries the reason inline so triage is one-pass.
TOOL_CONFUSION (2) "Bash" — "Bash" is a built-in CC tool name, not an MCP server "Read" — "Read" is a built-in CC tool name, not an MCP server TYPO (1) supbase — ≈ "supabase" (distance 1) UNCLASSIFIED (3) — no pattern matched, manual review old-analytics-server legacy-pdf-tool some-fork-of-thing
07 companion
Same four-bucket model, applied to per-project file-based memory — the MEMORY.md index + memory/*.md entries that auto-load into Claude's system prompt. Surfaces dead entries, broken pointers, and (uniquely) entries below the truncation cutoff that Claude can't see until you ask for them.
Same install pattern as skill-graveyard.
Installs the binary on your PATH.
Install as an Agent Skill — Claude auto-discovers it in any session. Same command also installs skill-graveyard and mcp-graveyard.
Four subcommands mirror the mcp-graveyard surface.
Default command. Reads the project's MEMORY.md index and cross-references every memory/*.md file against session logs to sort entries into the four buckets — active (indexed and read successfully), dead (indexed but never read), missing (read but not indexed), hallucinated (read and errored). Includes per-entry line numbers for pinpoint triage.
memory-graveyard — 30 days · 14 entries indexed · 16 on disk · 53 reads · 47 succeeded · 6 errored ACTIVE (4) indexed and read — keep entry reads errors last line feedback_release_flow.md 18 0 2026-05-02 12 project_clientco_platform.md 9 0 2026-05-01 10 feedback_subagent_models.md 8 0 2026-04-30 8 project_skill_graveyard.md 12 0 2026-04-29 6 DEAD (8) indexed, 0 reads in 30d — removal candidates arch_decisions_2025.md 0 0 — 3 onboarding_notes.md 0 0 — 14 retro_q1.md 0 0 — 20 HALLUCINATED (2) entry read but errored — file missing or pointer broken feedback_doesnotexist.md 0 2 2026-04-15 34 → memory-graveyard lint for static checks including broken pointers MISSING (2) on disk but not indexed in MEMORY.md — orphan files scratch_20260410.md 1 0 2026-04-10 — → memory-graveyard lint for actionable classification → run: memory-graveyard prune to clear DEAD entries and broken pointers
Five static checks: broken pointers (indexed entries whose files are missing), orphan files (on-disk entries not in the index), truncation budget (entries that fall below Claude's context window cutoff and are invisible until explicitly requested), index size (total token weight of all indexed entries), and stale dated entries (entries with an embedded date header older than 90 days). Exit code 1 if any check fails.
memory-graveyard lint BROKEN_POINTER (1) feedback_doesnotexist.md — indexed at line 34 but file not found on disk TRUNCATION_BUDGET (3) arch_decisions_2025.md — 4 312 tok, starts at token 94 208 of 100 000 limit onboarding_notes.md — 2 107 tok, starts at token 96 320 of 100 000 limit retro_q1.md — 1 844 tok, starts at token 98 427 of 100 000 limit INDEX_SIZE total 98 271 tok — within budget (limit 100 000) OK ORPHAN (0) STALE_DATE (0) → run: memory-graveyard prune to fix broken pointers and remove dead entries
Reads the audit and emits a removal plan for DEAD entries and broken pointers. Print-only by default. --apply writes a snapshot backup of the full memory/ directory to ~/.claude/memory-graveyard-backup/<ISO>/, then removes the dead entries from MEMORY.md and deletes the corresponding .md files. Continues on individual failures.
memory-graveyard prune — plan: 8 entries to remove (0 reads in 30 days) arch_decisions_2025.md remove from MEMORY.md + delete file onboarding_notes.md remove from MEMORY.md + delete file retro_q1.md remove from MEMORY.md + delete file feedback_doesnotexist.md remove broken pointer from MEMORY.md re-run with --apply to execute (snapshot backup is automatic)
Cross-project sweep. Groups every memory read by the cwd recorded in the session log and surfaces the per-project memory health — active entries, dead weight, and truncation pressure — across all projects in ~/.claude/projects/.
~/projects/client-analytics 12 entries indexed · 39 reads · 4 dead · 0 hallucinated feedback_release_flow.md 18× project_skill_graveyard.md 12× ~/projects/clientco/web-platform 8 entries indexed · 4 reads · 6 dead · 2 hallucinated ✗ feedback_doesnotexist.md 2× (2 hallucinated) ~/projects/landing 3 entries indexed · 0 reads · 3 dead · 0 hallucinated all 3 entries dead — consider clearing this project's memory