Your ~/.claude/skills/ folder is a graveyard. Janitor sweeps.
npx claude-janitor
▶ watch the full MP4 · static screenshot
- Evidence-based. Reads your session logs (
~/.claude/projects/) for invocation counts and last-used dates — so you see what you actually use, not what you installed. - Covers skills, sub-agents, and MCP servers. One scan across everything in
~/.claude/— and it flags MCP configs that carry a plaintext credential. - Reversible by default.
sweepmoves dust to an archive with a manifest;restoreputs it back.purgeis opt-in and requires--yes. - Plugin-aware. Skills and sub-agents owned by a plugin are off-limits — Janitor won't desync your plugin manager, and points you at
/plugin uninstall <name>instead.
Local-only. Reads files in
~/.claude. The only thing it writes is~/.claude/janitor/archive/(when you sweep). No network calls. No telemetry. Zero runtime dependencies.
janitor scan and print report (default, read-only)
janitor sweep archive dust skills + sub-agents, remove dust MCP entries
janitor restore [id] restore the most recent (or named) archive
janitor archives list past sweeps
janitor purge [id] delete archive(s) — requires --yes
janitor --json machine-readable scan output
Add --yes to skip confirmation prompts (useful in scripts).
Skills install in seconds. Plugins install in bulk. Six months in, your ~/.claude/skills/ is a museum of things you tried once. Janitor reads your session logs to tell you what you actually use — and gives you one command to clean up the rest, reversibly.
On the author's own install: 97 skills installed, 3 used in the last 30 days. Yours is probably similar.
Applies to skills and sub-agents alike:
- USED — invoked in the last 30 days
- DUST — user-installed, sweepable — never invoked, older than the 14-day grace period, lives in
~/.claude/skills/or~/.claude/agents/. Safe to sweep. - PLUGIN DUST — never invoked, but owned by a plugin. Janitor will not touch these (the plugin manager would re-install them); it shows the
/plugin uninstall <name>command instead. - NEW — installed less than 14 days ago. Grace period.
For symlinked skills, install age is computed from the symlink's own birthtime, not the target file — so re-linking doesn't reset the grace period.
Will it delete my stuff?
No. janitor sweep moves dust skills to ~/.claude/janitor/archive/<timestamp>/ and removes dust MCP entries from config (stashing the original key + a .bak of the full config in that same archive). janitor restore puts everything back. janitor purge is opt-in and requires --yes.
Why won't it sweep plugin skills?
Plugin skills live in the plugin cache, owned by Claude Code's plugin manager. Sweeping them would desync installed_plugins.json and they'd come back on the next plugin update. Use /plugin uninstall <name> for those. Same applies to plugin-bundled sub-agents.
What about sub-agents?
Janitor scans sub-agents from ~/.claude/agents/*.md and plugin-bundled agents/ directories, cross-references them against Agent tool invocations in your session logs, and classifies them USED/DUST/NEW exactly like skills. janitor sweep archives dust user-installed sub-agents (the .md file moves into the archive; restore puts it back). Plugin-bundled agents are reported but not swept.
What about MCP servers?
The report shows which MCP servers are installed, invoked, or orphaned. It reads MCP config from every source: ~/.claude.json (user-level + project-scoped), ~/.claude/settings.json, project-root .mcp.json files, skill-bundled mcp.json, and plugin-bundled plugin.json declarations. UUID-named connectors (Supabase, Gmail, Calendar, Vercel, Stripe, Drive) are fingerprinted by their method calls and labeled. Runtime-registered servers (Claude_Preview, Claude_in_Chrome, the session MCP) are detected and listed separately — they're not user-configurable, so they're not cleanup candidates. Servers that failed auth (per mcp-needs-auth-cache.json) are flagged ⚠ needs-auth, and configs carrying an inline credential — a token in env, an Authorization header, a URL with embedded auth — are flagged 🔑 plaintext secret with the offending location. janitor sweep removes dust MCP entries from ~/.claude.json and ~/.claude/settings.json — the entry's JSON is stashed in the archive manifest with a .bak of the full pre-edit config, and janitor restore re-inserts the key. Project-scoped and skill-bundled MCPs are intentionally left untouched by sweep (different lifecycles).
Does it work with Claude.ai or Claude Desktop?
No — Janitor reads Claude Code's local files (~/.claude/) and session logs (~/.claude/projects/). Claude.ai and the desktop apps don't expose equivalent local state.
--json mode?
janitor --json emits the full scan as JSON for dashboards, CI checks, or downstream tooling. Each usage.mcpServers[] entry carries runtime and connector fields (the same resolution the human report does) so consumers can tell a runtime-registered server or a known connector apart from a genuine unknown.
npx claude-janitor # one-shot
npm install -g claude-janitor # persistent
Requires Node 18+. Works on macOS and Linux. Not yet tested on Windows.
Issues and PRs welcome. The code is ~2,000 lines of zero-dependency Node split into single-purpose modules under src/ — scan-skills, scan-agents, scan-mcp, parse-logs, resolve-mcp, report, sweep. Tests live in test/ and run with node --test test/*.test.js.
MIT © Dor Amir