{"id":50703881,"url":"https://github.com/doramirdor/janitor","last_synced_at":"2026-06-09T10:01:57.453Z","repository":{"id":357458573,"uuid":"1236944245","full_name":"doramirdor/janitor","owner":"doramirdor","description":"Sweep your ~/.claude/skills graveyard. Scans installed skills, MCP servers, and sub-agents, cross-references session logs, and shows what's actually used.","archived":false,"fork":false,"pushed_at":"2026-05-12T20:59:30.000Z","size":42,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-12T22:29:12.338Z","etag":null,"topics":["anthropic","claude-code","cleanup","cli","mcp","skills"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/doramirdor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-12T18:14:20.000Z","updated_at":"2026-05-12T20:59:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/doramirdor/janitor","commit_stats":null,"previous_names":["doramirdor/janitor"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/doramirdor/janitor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doramirdor%2Fjanitor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doramirdor%2Fjanitor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doramirdor%2Fjanitor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doramirdor%2Fjanitor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/doramirdor","download_url":"https://codeload.github.com/doramirdor/janitor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doramirdor%2Fjanitor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34101070,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anthropic","claude-code","cleanup","cli","mcp","skills"],"created_at":"2026-06-09T10:01:54.379Z","updated_at":"2026-06-09T10:01:57.403Z","avatar_url":"https://github.com/doramirdor.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/logo.svg\" alt=\"claude-janitor\" width=\"480\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  Your \u003ccode\u003e~/.claude/skills/\u003c/code\u003e folder is a graveyard. Janitor sweeps.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/claude-janitor\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/claude-janitor.svg?color=cb3837\" alt=\"npm\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/doramirdor/janitor/actions/workflows/test.yml\"\u003e\u003cimg src=\"https://github.com/doramirdor/janitor/actions/workflows/test.yml/badge.svg\" alt=\"test status\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"MIT\"\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/tests-95%20passing-green.svg\" alt=\"95 tests\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/node-%E2%89%A518-43853d.svg\" alt=\"node ≥18\"\u003e\n\u003c/p\u003e\n\n```\nnpx claude-janitor\n```\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/demo-animated.svg\" alt=\"claude-janitor terminal demo\" width=\"760\"\u003e\n\u003c/p\u003e\n\n\u003csup align=\"center\"\u003e\n\n[▶ watch the full MP4](https://github.com/doramirdor/janitor/releases/download/v0.1.0/demo.mp4) · [static screenshot](docs/demo.svg)\n\n\u003c/sup\u003e\n\n- **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.\n- **Covers skills, sub-agents, and MCP servers.** One scan across everything in `~/.claude/` — and it flags MCP configs that carry a plaintext credential.\n- **Reversible by default.** `sweep` moves dust to an archive with a manifest; `restore` puts it back. `purge` is opt-in and requires `--yes`.\n- **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 \u003cname\u003e` instead.\n\n\u003e **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.\n\n## Commands\n\n```\njanitor                    scan and print report (default, read-only)\njanitor sweep              archive dust skills + sub-agents, remove dust MCP entries\njanitor restore [id]       restore the most recent (or named) archive\njanitor archives           list past sweeps\njanitor purge [id]         delete archive(s) — requires --yes\njanitor --json             machine-readable scan output\n```\n\nAdd `--yes` to skip confirmation prompts (useful in scripts).\n\n## Why\n\nSkills 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.\n\nOn the author's own install: **97 skills installed, 3 used in the last 30 days.** Yours is probably similar.\n\n## How it classifies\n\nApplies to skills and sub-agents alike:\n\n- **USED** — invoked in the last 30 days\n- **DUST — user-installed, sweepable** — never invoked, older than the 14-day grace period, lives in `~/.claude/skills/` or `~/.claude/agents/`. Safe to sweep.\n- **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 \u003cname\u003e` command instead.\n- **NEW** — installed less than 14 days ago. Grace period.\n\nFor 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.\n\n## FAQ\n\n**Will it delete my stuff?**\nNo. `janitor sweep` moves dust skills to `~/.claude/janitor/archive/\u003ctimestamp\u003e/` 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`.\n\n**Why won't it sweep plugin skills?**\nPlugin 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 \u003cname\u003e` for those. Same applies to plugin-bundled sub-agents.\n\n**What about sub-agents?**\nJanitor 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.\n\n**What about MCP servers?**\nThe 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).\n\n**Does it work with Claude.ai or Claude Desktop?**\nNo — 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.\n\n**`--json` mode?**\n`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.\n\n## Install\n\n```\nnpx claude-janitor              # one-shot\nnpm install -g claude-janitor   # persistent\n```\n\nRequires Node 18+. Works on macOS and Linux. Not yet tested on Windows.\n\n## Contributing\n\nIssues and PRs welcome. The code is ~2,000 lines of zero-dependency Node split into single-purpose modules under [`src/`](src/) — `scan-skills`, `scan-agents`, `scan-mcp`, `parse-logs`, `resolve-mcp`, `report`, `sweep`. Tests live in [`test/`](test/) and run with `node --test test/*.test.js`.\n\n## License\n\n[MIT](LICENSE) © Dor Amir\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoramirdor%2Fjanitor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdoramirdor%2Fjanitor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoramirdor%2Fjanitor/lists"}