hook-radar
A live, public registry of Claude Code hooks harvested from real public GitHub repos.
hook-radar crawls GitHub for repos that ship .claude/settings.json files containing hooks, parses the hook definitions (event, matcher, command), and serves them as a searchable, filterable browse page.
URL: https://holyai.me/hook-radar/
Why
By May 2026, Claude Code hooks are a primary differentiator between casual users and power users. Anthropic's hooks API ships eight event types (PreToolUse, PostToolUse, UserPromptSubmit, Stop, SubagentStop, Notification, PreCompact, SessionStart). The community has been writing creative shell snippets — ESLint-on-edit, secrets-scan-before-bash, auto-commit-on-stop, slack-on-notification, redact-pre-compact.
But there is no central registry. People drop hooks in tweets, Reddit threads, and .claude/settings.json files buried in repos. To find "a good PostToolUse(Edit) hook that runs prettier" today, you grep GitHub manually.
hook-radar is the page that fixes that gap.
Data sources (real, no mocks)
All data comes from live GitHub fetches at runtime. There is no seed data, mock data, or hardcoded fallback. If the data source is unavailable, the API returns {status:"awaiting_real_data"} with an empty list — never invented numbers.
| Source | Auth | Refresh |
| ------------------------------------------------- | ----------- | ---------------------- |
| api.github.com/search/code | required\* | every 6 hours (cron) |
| api.github.com/search/repositories (fallback) | optional | every 6 hours (cron) |
| api.github.com/repos/{o}/{n} | optional | every 30 minutes (top 100) |
| raw.githubusercontent.com/{o}/{n}/{b}/.claude/settings.json | none | per-repo on each sweep |
\* Code search requires authentication. Without GITHUB_TOKEN, the discovery falls back to repository-keyword search which is lower-recall but unauthenticated.
Endpoints
All under BASE_PATH=/hook-radar.
GET /health— health probe (no auth)GET /api/stats— totals + last sync timestampGET /api/hooks?event=PostToolUse&matcher=Edit&q=prettier&sort=stars&limit=50— listGET /api/hooks/:id— single hook with full commandGET /api/events— event types with countsGET /api/repos— top repos by hook countGET /api/repos/:owner/:name— all hooks from a repoPOST /api/discover— kick off discovery (rate-limited 1/min/ip)GET /api/feed.json— newest 50 hooks as JSON Feed 1.1GET /api/badge/:owner/:name.svg— README badge
No auth
All endpoints — read and the single trigger — are public. There is no /admin, no Basic Auth, no API key. The project intentionally avoids any login surface so the public can audit hooks immediately.
Running locally
npm install
cp .env.example .env
# put a real GITHUB_TOKEN in .env for full discovery
npm start
# open http://localhost:4872/hook-radar/
better-sqlite3 is a native module; prebuilt binaries exist for macOS and Linux arm64/x64 (Node 20+).
Env vars
| Var | Default | Purpose |
| ------------------ | ----------------------------- | ------------------------------------ |
| PORT | 4872 | HTTP port |
| BASE_PATH | /hook-radar | URL prefix |
| GITHUB_TOKEN | __INJECT_FROM_VAULT__ | required for /search/code |
| DB_PATH | ./data/hook-radar.db | SQLite path |
| DISCOVERY_ON_BOOT| true | run discovery once on boot if stale |
| LOG_LEVEL | info | silent disables request logs |
Security notes
- Hook commands are stored and displayed as text only. We never execute or download foreign shell content for execution.
- All HTML output is text-escaped — no innerHTML interpolation of fetched commands.
helmet+ strict CSP applied; only same-origin scripts.- The single mutating endpoint (
POST /api/discover) is rate-limited to one call per minute per IP.
Roadmap (post-MVP)
- Cross-repo popularity (which command appears in how many repos)
- Hook diff over time (when did
repo Xchange theirPostToolUse(Bash)block) - AI-generated "what does this hook do" summary via OpenRouter
.claude/hooks/*.shshell-file indexing (currentlysettings.jsononly)
License
UNLICENSED · made by Cowork.