Docs & demo: https://sfrangulov.github.io/skill-graveyard/ · built by @sfrangulov
Audit which Claude Code skills you actually use. Parses your local session logs and sorts every skill name that appears into one of four buckets:
- Active — installed AND invoked successfully. Keep.
- Dead — installed but zero invocations in the window. Removal candidates.
- Missing — invoked successfully, but no SKILL.md was found in any scanned path. Project-scoped skills, skills registered by an external framework injecting into Claude Code, or skills installed somewhere this tool doesn't yet look.
- Hallucinated — invoked and the runtime returned an error. Mostly Claude confusing tool/command names with skill names; surfaced for telemetry but not directly actionable.
Same parser, multiple signals: it's not just a graveyard, it's an audit of where your skill setup is over- and under-provisioned.
The same four-bucket model (active / dead / missing / hallucinated), applied to MCP servers instead of skills. Which configured servers does Claude actually invoke? Which tool names is it hallucinating?
npx mcp-graveyardFour subcommands:
audit(default) — server-first table sorted by call volume.--days N,--only active|dead|missing|hallucinated,--tools(expand per-server tool breakdown),--json.prune— prints a removal plan.--applywrites a 0o600-permissioned backup of~/.claude.jsonthen runsclaude mcp removefor each dead server.projects— re-aggregates by thecwdrecorded in your session logs. Surfaces globally-configured servers that only appear in one project — candidates for project-scoping.suggest— classifies missing and hallucinated tool names into TYPO, TOOL_CONFUSION, and UNCLASSIFIED buckets with recommendations.
Reads ~/.claude.json (mcpServers block) for the configured-server list and ~/.claude/projects/**/*.jsonl for invocation history. All analysis is local; no network calls.
See packages/mcp-graveyard/README.md for full docs.
Same four-bucket model (active / dead / missing / hallucinated), applied to per-project file-based memory: the MEMORY.md index + memory/*.md entries that auto-load into the system prompt at session start.
npx memory-graveyard@latest # audit current project's memory
npx memory-graveyard@latest lint # static checks (broken pointers, orphans,
# truncation budget, index size, stale dates)
npx memory-graveyard@latest prune # plan removal; --apply executes with snapshot
npx memory-graveyard@latest projects # cross-project sweep — find cold memory dirsSample CLI output (anonymized — clientco/web-platform stands in for a real project):
memory-graveyard — 30 days · 14 entries indexed · 16 on disk · 53 reads · 47 succeeded · 6 errored
ACTIVE (4)
entry reads errors last line
feedback_release_flow.md 18 0 2026-05-02 12
...
DEAD (8) — candidates for removal
...
HALLUCINATED (2)
...
→ run: memory-graveyard prune to clear DEAD entries and broken pointers
lint is the unique-to-memory check: it surfaces entries below the system-prompt truncation cutoff (default 200 lines) — the entries Claude can't see until you ask for them by name. All analysis is local; no network calls.
I had 65 skills installed across user, plugin, and agent paths. After parsing 30 days of my own session logs, I found Claude had actually invoked 14 of them. The other 51 were still loading their description strings into every API request — about 500K skill-metadata tokens over the window covering skills that were never called once. I built this so I could see the gap, and to surface a second signal I didn't expect: Claude regularly invokes built-in tool names (Bash, Read, Edit) as if they were skills, which the runtime then errors on. Same parser, both answers.
npx skill-graveyardOr globally:
npm i -g skill-graveyard
skill-graveyardOr as a Claude Code Agent Skill (auto-discovered by Claude in any session, via skills.sh):
npx skills add sfrangulov/skill-graveyardThe skills.sh install adds a SKILL.md to your Claude Code skills directory; Claude picks it up automatically when you ask audit-shaped questions ("which skills don't I use?", "clean up my skills") and runs the same npx skill-graveyard binary under the hood. The same command also installs the sister mcp-graveyard skill from this repo. Compatible with the npm install — they don't conflict.
Requires Node 18+.
Six subcommands. audit is the default and is what you usually run.
skill-graveyard # 30-day audit, pretty table
skill-graveyard --days 14 # narrower window
skill-graveyard --only dead # filter to removal candidates
skill-graveyard --json # machine-readable
skill-graveyard prune # plan: print every command that would disable a dead skill
skill-graveyard prune --apply # execute the unlinks (plugin removals always print only)
skill-graveyard suggest # classify hallucinated/missing into actionable buckets
skill-graveyard projects # break down skill usage per project (from session cwds)
skill-graveyard cost # estimate token cost of installed skill metadata
skill-graveyard outdated # check installed plugins / git-tracked skills for upstream updates (network)Sorts every skill name that appears in your sessions into four buckets, plus rolls up plugin groups where every skill is dead. Filter to one bucket with --only active|dead|missing|hallucinated.
Pipe to jq for custom queries:
skill-graveyard --json | jq '.rows[] | select(.category=="dead") | .invokeName'Reads the audit and emits a removal plan, source-aware:
| source | dry-run output | with --apply |
|---|---|---|
user (symlink in ~/.claude/skills/) |
unlink <path> |
executes |
agents (symlink in ~/.agents/skills/) |
unlink <path> |
executes |
plugin (every skill of the plugin is dead) |
claude /plugin remove <name>@<scope> |
prints only — run inside Claude Code |
plugin (partially dead) |
nothing | nothing |
project (<cwd>/.claude/skills/) |
nothing — out of scope | nothing |
--apply only executes unlinks (fully reversible: re-creating the symlink restores the skill). Plugin removals are always print-only because invoking /plugin remove from outside Claude Code is fragile. --only user|agents|plugin narrows the scope.
Classifies the MISSING and HALLUCINATED rows into actionable buckets:
- EXTERNAL FRAMEWORK — skill is invoked from
~/.<framework>/...cwd and resolves successfully, so it's registered by another framework Claude Code runs inside (paperclip, custom orchestrators, etc.). Recommendation: document these in yourCLAUDE.mdso future Claude knows the names are valid. - TOOL/SKILL CONFUSION — Claude invoked a built-in CC tool name (
Bash,Read,Write,Edit, etc.) as a skill. Known model failure mode, not actionable on your side. - LIKELY TYPO — invoke name is within Levenshtein distance 2 of an installed skill. Worth reviewing the call sites.
- UNCLASSIFIED — no pattern matched. Manual review.
Groups every skill invocation by the cwd recorded in your session logs. Surfaces which projects use which skills heavily, which projects pull in hallucinated names, and which skills are project-scoped vs. globally used.
~/projects/api-server 17 ses, 39 calls, 6 skills
superpowers:brainstorming 13×
superpowers:writing-plans 11×
? update-config 2×
~/projects/dotfiles 2 ses, 2 calls, 2 skills
frontend-design 1×
superpowers:brainstorming 1×
✗ marks errored (hallucinated) calls; ? marks invoked names that aren't installed but didn't error (likely external-framework skills).
Estimates how many tokens your skill metadata consumes per session vs. how many of those tokens cover skills Claude actually invokes. Each installed skill's description field (from SKILL.md frontmatter) is loaded into the Skill tool definition on every API request, even if the skill is never invoked.
TOP WASTERS desc tokens × sessions where never invoked
playwright-best-practices user 246 t × 0/159 39.1K
ai-sdk user 151 t × 0/159 24.0K
...
Also surfaces hook injections (text auto-added to every session by SessionStart hooks) — these can dwarf skill metadata costs.
Token counts use the cl100k_base BPE tokenizer (a proxy for Claude's tokenizer, which Anthropic doesn't ship publicly for Claude 3+). Expect 5–15% drift from the real tokenizer. Anthropic prompt caching reduces dollar cost significantly, but loaded tokens still consume your context window and rate-limit budget.
Checks installed plugins and git-tracked user/agent skills against their upstream sources, prints what's behind, and gives the exact command to update each. Network-bound — the only subcommand that calls out. Results are 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
For each plugin it follows the marketplace's marketplace.json to pick the right comparison: explicit version, pinned commit SHA, or upstream HEAD via git ls-remote. Plugins installed without a recorded version (installedVersion: "unknown") are flagged with a reinstall hint instead of an update one — Claude Code's plugin manager records SHAs only on fresh installs.
skill-graveyard outdated --no-cache # force refetch
skill-graveyard outdated --ttl 0 # equivalent: zero TTL = always miss
skill-graveyard outdated --ttl 1440 # cache for 24h
skill-graveyard outdated --json | jq '.rows[] | select(.status=="outdated")'~/.claude/projects/**/*.jsonl— session logs (skill invocations andcwdper session live intool_useevents)~/.claude/plugins/installed_plugins.json— registered plugins~/.claude/plugins/known_marketplaces.json— marketplace → repo mapping (foroutdated)~/.claude/skills/,~/.agents/skills/— user-level skills<plugin-install-path>/skills/— plugin-bundled skills<cwd-and-ancestors>/.claude/skills/— project-scoped skills, walking up from each session's cwd to your home directory- Network — only when
outdatedruns:https://raw.githubusercontent.com/<repo>/HEAD/.claude-plugin/marketplace.jsonfor each registered marketplace, plusgit ls-remoteagainst marketplace and skill-repo origins. Results cached at~/.cache/skill-graveyard/outdated/.
Pass --claude-dir to override the Claude home location.
- Does not auto-disable plugin skills. Plugin removal is a Claude Code slash command (
/plugin remove) and invoking it from outside the runtime is fragile, sopruneonly prints the command. Run it inside Claude Code yourself. - Does not touch project-scoped skills. Skills under
<project>/.claude/skills/are intentional per-project artifacts;pruneignores them. - Does not phone home except when running
outdated. Five of the six subcommands are entirely local.outdatedis the explicit exception — it fetches each registered marketplace'smarketplace.jsonand runsgit ls-remoteagainst marketplace and skill-repo origins. Results are cached locally; everything else stays local.
MIT
