fork-health-score
fork-health-score synthesizes push recency, enabled skill count, and 30-day PR activity into four health tiers (ACTIVE, WARM, STALE, QUIET) for each fork in a fleet, then computes the fleet health ratio and surfaces the top-10 ACTIVE forks as a ranked leaderboard. Use this weekly to answer "how many of our forks are genuinely running" with a single number and identify the healthiest instances worth highlighting to external audiences.
git clone --depth 1 https://github.com/aaronjmars/aeon /tmp/fork-health-score && cp -r /tmp/fork-health-score/skills/fork-health-score ~/.claude/skills/fork-health-scoreSKILL.md
> **${var}** — Optional. Pass `dry-run` to skip notify (state and article still write). Pass `owner/repo` to override the parent repo. Combine with a space (`dry-run owner/repo`) for both.
Today is ${today}. With the parent repo past 132 forks and the fleet-intelligence stack now answering "who's alive" (`fork-cohort`), "what's missing" (`fork-skill-gap`), "what's running" (`fleet-skill-adoption`), and "who contributes back" (`contributor-spotlight`), one synthesis question is still unanswered at the per-fork level: **how healthy is each fork**, as a single tier? `fork-cohort` buckets on workflow-run recency alone; this skill blends three independent signals (push recency, configured skill count, PR throughput) into one rank so an operator scanning the fleet can answer "X of 132 forks are ACTIVE" in one number — and surface the top-10 ACTIVE forks as a leaderboard worth pointing strangers at.
## Why this exists
A fork that pushed today but has zero enabled skills is a placeholder. A fork that enabled 30 skills but hasn't pushed in 60 days is a museum piece. A fork that's pushing AND enabling AND merging its own PRs is a real, running instance. `fork-cohort` collapses all three into "did Actions run lately?"; `fleet-skill-adoption` aggregates across the cohort, not per-fork; `contributor-spotlight` picks one named operator a week. None of them answer "give me the per-fork ranked list."
That ranked list is the missing public number. "9 of 132 forks are ACTIVE" is the kind of single-line stat that lands in a tweet, a Show HN comment, or a deck slide. This skill exists to compute it — once a week, gated to notify only when the ratio moves materially.
This is a **measurement skill**. It never opens PRs, never comments on forks, never edits any fork's files. The output is one article + one optional notification + one state file. Same pattern as `fork-cohort` / `fork-skill-gap` / `fleet-skill-adoption`.
## Scope and inputs
Reads from two places, with graceful degradation:
1. **`memory/topics/fork-cohort-state.json`** (primary) — gives the full fork list with last-run timestamps. When present and fresh (≤8 days), the cohort cache is the input source — saves one round-trip to `gh api repos/{parent}/forks --paginate`.
2. **`gh api repos/{parent}/forks --paginate`** (fallback / first run) — when cohort state is absent or stale, fetch the live forks list.
3. **Per fork: `gh api repos/{fork}`** — pulls `pushed_at`, `default_branch`, `stargazers_count`, `owner.login`, `owner.type`.
4. **Per fork: `gh api repos/{fork}/contents/aeon.yml?ref={default_branch}`** — base64-decoded, parsed for `enabled: true` slugs (same inline-object grep + Python YAML fallback as `fleet-skill-adoption`).
5. **Per fork: `gh api repos/{fork}/pulls?state=closed&base={default_branch}&per_page=100`** — count PRs merged into the fork's own default branch in the last 30 days. (Not PRs back upstream — that's `contributor-spotlight`'s territory. This measures the fork's *internal* PR throughput as a sign of active development against its own main.)
Writes:
- `memory/topics/fork-health-score-state.json` — per-fork tier, score components, rolling 8-week history
- `articles/fork-health-score-${today}.md` — leaderboard article (every non-error run, including QUIET)
- `memory/logs/${today}.md` — one log block per run
- Notification via `./notify` — only when the ACTIVE ratio drops ≥10 percentage points week-over-week, the top-10 changes, or it's the first baseline run (see step 8)
## Steps
### 0. Bootstrap
```bash
mkdir -p memory/topics articles
[ -f memory/topics/fork-health-score-state.json ] || cat > memory/topics/fork-health-score-state.json <<'EOF'
{"parent":null,"last_run":null,"last_status":null,"audited_count":null,"readable_count":null,"buckets":null,"history":[],"forks":{}}
EOF
```
If `jq empty` fails on the state file (corrupt JSON from an aborted write), back it up to `.bak`, reset to the empty template above, and tag the run `STATE_CORRUPT`. Continue — a fresh state file means no prior week to diff, which is the correct post-corruption behaviour (WoW deltas are simply omitted).
`forks` is a map keyed by `owner/repo`: `{tier, pushed_days, enabled_count, prs_30d, score, last_seen}`. `history` is a rolling list (cap 8 entries) of `{date, audited, readable, buckets:{ACTIVE,WARM,STALE,QUIET}, top10:[fork]}` used for WoW comparison.
### 1. Parse var
- Split `${var}` on whitespace. Tokens: `dry-run`, anything matching `^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$` (treated as `PARENT_OVERRIDE`), anything else.
- If any unknown token is present → log `FORK_HEALTH_SCORE_BAD_VAR: ${var}` and exit (no notify).
- `MODE=dry-run` if the `dry-run` token is present, else `execute`.
### 2. Resolve parent repo
```bash
if [ -n "$PARENT_OVERRIDE" ]; then
PARENT_REPO="$PARENT_OVERRIDE"
else
PARENT_REPO=$(gh api "repos/$(gh repo view --json nameWithOwner -q .nameWithOwner)" --jq '.parent.full_name // .full_name')
fi
```
If `state.parent` is set and differs from the resolved `PARENT_REPO` → log `FORK_HEALTH_SCORE_PARENT_CHANGED`, reset `forks` and `history` to empty, update `state.parent`. (A different parent means a different fleet; old scores are meaningless.)
### 3. Build the fork audit list
Try the cached path first (identical freshness logic to `fork-skill-gap` and `fleet-skill-adoption` so the three skills agree on the fork universe):
```bash
COHORT_STATE=memory/topics/fork-cohort-state.json
COHORT_FRESH=false
if [ -f "$COHORT_STATE" ]; then
COHORT_DATE=$(jq -r '.last_run // empty' "$COHORT_STATE")
if [ -n "$COHORT_DATE" ]; then
AGE_DAYS=$(( ($(date -u +%s) - $(date -u -d "$COHORT_DATE" +%s)) / 86400 ))
[ "$AGE_DAYS" -le 8 ] && COHORT_FRESH=true
fi
fi
```
- `COHORT_FRESH=true`: read the full fork list from `state.forks` keys. Set `fork_source=cohort`.
- `COHORT_FRESH=false`: fall back to `gh api "repos/${PARENT_REPO}/forks" --paginate --jq '.[].full_name'`. Set `fork_source=live`. Retry-once-then-skip on 403/5xMention/keyword sweep on social platforms for [REPLACE: KEYWORDS] — trends, sentiment, top posts
5 concrete real-life actions, leverage-scored against open loops with specificity and anti-fluff gates
Curated AI-agent tweets, clustered into narratives with insight summaries
Tracker of AI agent substitution signals — which roles, companies, and industries show real headcount displacement. Named roles + real deployments only.
Competitive-intelligence digest on the AI agent framework space — momentum, releases, breaking changes across a curated watchlist
Cross-domain market pulse from AIXBT's free grounding endpoint — crypto, macro, tradfi, geopolitics. Refreshes taxonomy references (clusters, chains) as a bonus.
Pre-batch API provider health check — detects credit exhaustion or auth failure for every configured provider key before the scheduled batch runs, giving the operator a window to act before skills degrade
List a wallet's live ERC-20 token approvals on Base and flag unlimited / risky spender grants. Keyless via Base RPC (eth_getLogs + eth_call) — no explorer key needed.