← back to gallery

Skill Mirror

Same AI agent skill across every library — one side-by-side comparison view

dev-toolsai-agentsclaude-codeskillsgithubcomparisonopenclawcursor
Open product ↗

skill-mirror

Same skill, every library, one comparison view.

A live, public, side-by-side mirror of SKILL.md files across the major AI-agent
skill libraries on GitHub. For every popular skill name (tdd, code-review,
debug-loop, security-audit, ...), see exactly how Matt Pocock, Addy Osmani,
Anthropic and other trending skill repositories implement it — content diffed,
freshness tracked, all from real public GitHub data.

Watched libraries

Every entry below is a real, public GitHub repository. The seed list lives in
fetchers/skills.js and may be edited without code changes. If a repo or its
configured base_path is missing at ingest time, the library is shown as
"unavailable, last synced never" in the UI — no fake skills are ever inserted.

| Library | Path filter | Why we track it |
|---|---|---|
| anthropics/skills | _(root)_ | Official Anthropic skills |
| addyosmani/agent-skills | _(root)_ | Addy Osmani's curated set (40k+ stars as of May 2026) |
| mattpocock/skills | _(root)_ | Matt Pocock's TypeScript / TDD / guardrail skills |
| ananddtyagi/cc-marketplace | skills/ | Community Claude Code marketplace |
| ComposioHQ/awesome-claude-plugins | skills/ | Composio curated set |
| jeremylongshore/claude-code-plugins-plus-skills | skills/ | Community list |
| quemsah/awesome-claude-plugins | skills/ | Awesome list |

Refresh schedule

All HTTP responses are conditionally fetched with If-None-Match / If-Modified-Since
so we never re-parse content that hasn't changed.

API

All routes are mounted under BASE_PATH (default /skill-mirror).

| Method | Path | Description |
|---|---|---|
| GET | /health | Liveness — auth-free, returns 200 { status: "ok", ... } |
| GET | / | HTML index |
| GET | /skill/:slug | HTML comparison view (server-rendered for SEO) |
| GET | /library/:owner/:repo | HTML library detail |
| GET | /diff/:libA/:libB/:slug | HTML unified diff (libA/libB encoded as owner~repo) |
| GET | /about | Methodology |
| GET | /card/skill/:slug.svg | 1200×630 dark SVG card |
| GET | /card/library/:owner/:repo.svg | 1200×630 dark SVG card |
| GET | /api/stats | Counters + last full ingest timestamp |
| GET | /api/libraries | All watched libraries + skill counts |
| GET | /api/library/:owner/:repo | One library + its skills |
| GET | /api/skills?slug=&library=&q=&page= | Paginated skills search |
| GET | /api/skill/:slug | Every implementation of one slug |
| GET | /api/skill/:slug/diff?a=&b= | Unified diff between two implementations |
| GET | /api/universal?min=3 | Skills present in ≥ N libraries |
| GET | /api/orphans | Skills present in exactly one library |
| GET | /api/recent?limit=10 | Newest skill rows |
| GET | /api/ingest-log?level=error&limit=50 | Recent ingest log |

There is no POST / PUT / DELETE endpoint anywhere in this service.
The data flow is strictly GitHub → SQLite → HTML/JSON.

Real-data invariants (no mocks)

Running locally

cp .env.example .env
# optional: paste a GitHub PAT into .env for 5000 req/h instead of 60.
npm install
npm start
# → skill-mirror listening on :4840/skill-mirror

The first ingest fires on boot in the background; the UI renders immediately
with "syncing…" placeholders until rows land in the DB.

Architecture

                ┌──────────────────────────────────┐
   cron 6h  →   │ fetchers/skills.js (ingest)      │   raw.githubusercontent.com
                │  ↳ fetchers/github.js (etag,     │   ──────────────────────────►
                │     rate-limit pacing)           │   api.github.com
                └──────────────┬───────────────────┘
                               │ upsert
                               ▼
                ┌──────────────────────────────────┐
                │ db.js · better-sqlite3 WAL       │
                │  - libraries, skills,            │
                │    skill_versions, ingest_log    │
                └──────────────┬───────────────────┘
                               │ prepared statements
                               ▼
   browser  ◄── express ──┐   routes/index.js (HTML)
                          └── routes/api.js   (JSON)
                              + public/{index,skill,library,diff,about}.html
                              + public/app.js (vanilla JS)
                              + public/style.css (dark theme)

Deployment

DEPLOY_MANIFEST.json matches the RNDLAB orchestrator schema. The Mac Mini
watcher (in cowork-deploy-bridge/) picks this directory up via
queue.jsonl, rsyncs it to /var/www/projects/skill-mirror, installs a
systemd unit, points nginx at port 4840, and posts the showcase entry.

The optional GITHUB_TOKEN env var is injected from the RNDLAB key vault via
the __INJECT_FROM_VAULT__ placeholder. The service runs without it (60 req/h),
but with it the every-6-hour full ingest costs ~30 requests against a 5000/h
budget — plenty of headroom.

Differentiation vs. existing products

| Existing | What it does | What skill-mirror adds |
|---|---|---|
| skill-pulse | Flat searchable index across GitHub | Cross-library side-by-side comparison |
| skill-clash | Conflicts within a single library | Inter-library content view |
| skill-portability | A→F harness compat scorecard | Rendered Markdown side-by-side |
| skill-shield | Security scan | Content + diff view |
| plugin-deck | Marketplace aggregator | Granular per-skill view |
| agents-md-radar | Whole-repo AGENTS.md / CLAUDE.md | Per-skill SKILL.md |

License

MIT.