plugin-pin-rot
Pin freshness leaderboard for the official Anthropic Claude Code plugin marketplace.
When you install a Claude Code plugin from anthropics/claude-plugins-official, the marketplace hands you a specific commit SHA that was pinned at the moment the listing PR was merged. Once it's merged, the upstream repo keeps moving — bug fixes, dependency bumps, even security patches — but the marketplace pin stays frozen.
plugin-pin-rot is the missing freshness signal: a live, public dashboard that opens every plugin's upstream repo and quantifies how far the pinned SHA has drifted behind HEAD, whether the upstream has been archived, whether a git-subdir plugin's path has been deleted, and whether there are commits with security-flavoured messages the marketplace hasn't picked up.
Live URL: https://holyai.me/plugin-pin-rot/
Real public data only
Every value in the database is traceable to one of these endpoints:
| Source | URL | Refresh | Notes |
|---|---|---|---|
| Official marketplace JSON | https://raw.githubusercontent.com/anthropics/claude-plugins-official/main/.claude-plugin/marketplace.json | every 6 h | unauth, no rate limit problem |
| Upstream repo metadata | GET https://api.github.com/repos/{owner}/{repo} | every 6 h | 60 req/h unauth, 5000 req/h with GITHUB_TOKEN |
| Pinned commit info | GET https://api.github.com/repos/{owner}/{repo}/commits/{pinned_sha} | every 6 h | gives us pinned_committed_at |
| Compare pinned..HEAD | GET https://api.github.com/repos/{owner}/{repo}/compare/{base}...{head} | every 6 h | yields ahead_by (commits behind) + the commit list we scan for security keywords |
| Path-exists check | GET https://api.github.com/repos/{owner}/{repo}/contents/{path}?ref={default_branch} | every 6 h | git-subdir plugins only |
| Local-path plugin history | GET https://api.github.com/repos/anthropics/claude-plugins-official/commits?path=plugins/{name} | every 6 h | for Anthropic's bundled plugins |
If a fetch fails (rate-limit, 404, network) the row's last_status is updated and the previous good value is kept. No mock arrays, no Math.random(), no seed data.
Tech stack
Node.js 20+, Express, better-sqlite3 (WAL), node-cron, helmet, compression. Vanilla JS SPA — no React, no Tailwind, no build step. Dark theme, English labels.
BASE_PATH=/plugin-pin-rot, default PORT=4871.
Endpoints (all public, no auth)
| Method | Path | Description |
|---|---|---|
| GET | /plugin-pin-rot/ | SPA |
| GET | /plugin-pin-rot/health | smoke-check JSON |
| GET | /plugin-pin-rot/api/leaderboard | sortable, filterable plugin list |
| GET | /plugin-pin-rot/api/plugin/:name | full per-plugin detail |
| GET | /plugin-pin-rot/api/feed.json | recent rot events |
| GET | /plugin-pin-rot/api/stats | aggregate stats |
| GET | /plugin-pin-rot/api/categories | category counts |
| GET | /plugin-pin-rot/p/:name/card.svg | shareable scorecard SVG |
| POST | /plugin-pin-rot/api/refresh | manual trigger (rate-limited to 1/5min) |
Local development
cp .env.example .env # set GITHUB_TOKEN if you have one
npm install
node server.js # boots, listens, runs cold bootstrap if empty
curl http://localhost:4871/plugin-pin-rot/health
Without GITHUB_TOKEN the anonymous GitHub limit (60 req/h) is too small for a single full refresh of all ~200 plugins. The product still boots and serves cached data; the UI shows a banner explaining the limit.
Why this product exists
The marketplace launched May 23, 2026. As of writing, ~200 plugins are listed, ~150 of which point at external upstream repos. There is no public dashboard showing which of those pins are stale. plugin-deck (sibling product) aggregates and dedupes across multiple marketplaces but doesn't open the upstream repos. plugin-tax measures token cost; this is freshness.
Scoring
rot_score (0–100, higher = worse) is computed from real numbers only:
rot_score = 100 if archived OR path_missing OR upstream_404
= 0 if commits_behind ≤ 3 AND days_behind ≤ 14 AND no security commits
= 25·sigmoid(commits_behind/20)
+ 25·sigmoid(days_behind/60)
+ 30·(security_commits_behind > 0)
+ 20·(upstream_default_branch_renamed)
Letter grade: A 0–14, B 15–29, C 30–49, D 50–74, F 75–100.