- name
- operator-scorecard
- description
- Three recap modes - default synthesizes agent health, community growth, and economic activity into a was-it-worth-it verdict; ops recaps what shipped and failed; push ranks push impact.
- metadata
- {"category":"productivity","var":"","tags":["meta","productivity","dev"]}
> **${var}** — Mode selector. The first token picks the branch; the remainder is branch-specific.
> - **empty** → **operator scorecard** (default): synthesize the week into agent health + community growth + economic activity with a worst-of-three OK/WATCH/DEGRADED verdict. Also accepts `dry-run` (skip the notification — article + JSON spec still write) and/or an integer `N` to override the window in hours (default 168 = 7d, cap 720). Examples: `` , `dry-run`, `336`, `dry-run 336`.
> - **`ops`** → **ops recap**: operational summary of one day — what shipped, what failed, what needs follow-up. Optional date override after the keyword (`ops 2026-06-30` or `ops:2026-06-30`); empty date = today (UTC).
> - **`push`** → **push recap**: deep-dive recap of all pushes — reads diffs, ranks impact, separates user-visible shipments from internal work, delivers a verdict. Optional repo scope after the keyword (`push aeonfun/aeon` or `push:owner/repo`); empty = all watched repos.
<!-- merged: operator-scorecard (default branch, three-pillar synthesis) + ops-recap (`ops` branch, operational day-recap) + push-recap (`push` branch, diff-reading push deep-dive). Every distinct behaviour of all three is preserved below. -->
## Overview
One skill, three recap views over Aeon's own activity. They share a preamble (read memory, compute the date, parse the selector) then branch into fully distinct logic — do not blend them:
- **scorecard** (default): a **synthesis-only** weekly rollup. Every number it prints is sourced from a file another skill already wrote (`skill-health`'s analytics view, `heartbeat`, `tweet-allocator`, `repo-pulse`). Three paragraphs — agent health / community growth / economic activity — each with its own verdict, rolled up to a worst-of-three overall verdict. Answers the operator-level question: *given everything that happened, was this week worth it?*
- **ops** (`ops`): an **operational day-recap**. Reads today's activity log + `memory/cron-state.json` + the issues index, deduplicates repeat runs, demands a URL on every shipped item, surfaces the calls that need a human, and leads with a one-sentence TL;DR verdict. Never a log dump.
- **push** (`push`): a **diff-reading push deep-dive**. Fetches push events, commits, and merged PRs per watched repo, reads the diffs, classifies each commit user-visible vs internal vs infra, ranks by impact, and leads with a one-line verdict — with significance gating so quiet days send nothing.
## Shared preamble (run for every branch)
1. Read `memory/MEMORY.md` for high-level context and scan the last ~3 days of `memory/logs/` for recent activity — drop anything already reported so you don't re-report the same signal.
2. Compute `${today}` (UTC date, `YYYY-MM-DD`).
3. **Parse `${var}` → branch + branch argument** (trim whitespace first). Let `FIRST` be the lowercase first token (split on the first whitespace or `:`), `REST` the remainder:
- `FIRST == "ops"` → `BRANCH=ops`, `ARG=REST` (a date override, or empty).
- `FIRST == "push"` → `BRANCH=push`, `ARG=REST` (an `owner/repo` scope, or empty).
- anything else (empty, `dry-run`, a bare integer, or an unrecognized token) → `BRANCH=scorecard`; pass the **whole** `${var}` through to the scorecard branch's own grammar (dry-run prefix + optional integer window).
4. Dispatch: run the matching branch below. Only that branch executes.
---
# Scorecard branch (default — empty / `dry-run` / integer window)
Today is ${today}. Synthesize the last 7 days of agent activity into a single plain-language scorecard the operator can read in 30 seconds. Three paragraphs (agent health / community growth / economic activity) plus a one-line verdict (OK / WATCH / DEGRADED). The point of this branch is to answer the question every operator quietly asks after a week of autonomous runs: **was this week worth it?**
## Why this exists
Every signal needed to answer that question already lives in the repo — `skill-health`'s analytics view ranks pass rates, `heartbeat` issues per-run verdicts, `tweet-allocator` totals weekly $AEON spend, `repo-pulse` records star/fork deltas. But each lives in its own article, on its own cadence, in its own format. A new operator (or a returning one) opens four files to assemble the weekly picture. This branch assembles it once on Monday morning and pushes it to the notification channel so the picture is delivered, not fetched.
It is deliberately a synthesis view, not a measurement view — every number it prints is sourced from a file another skill already wrote. It introduces zero new APIs, zero new secrets, zero new cron-state. If an upstream skill didn't run, the matching paragraph degrades gracefully ("no data this week") rather than fabricating numbers.
## Config
No new config. No new secrets. Reads:
- `output/articles/skill-analytics-*.md` — most recent file in window for fleet pass rate + anomaly count (written by `skill-health`'s analytics view — the former `skill-analytics` skill, now the analytics view of `skill-health`)
- `output/articles/heartbeat-*.md` (or `memory/logs/*.md` heartbeat sections) — P0–P3 verdict tally
- `output/articles/tweet-allocator-*.md` — weekly distributed totals + recipient counts
- `output/articles/repo-pulse-*.md` — daily star/fork delta entries summed across the window
- `memory/MEMORY.md` — last consolidation date + "Skills Built" recent rows for the activity-pulse line
- `memory/issues/INDEX.md` (optional) — open issue count if present
No outbound HTTP. No `gh api` calls. Pure file scanning + arithmetic.
## Steps
### 1. Parse var and resolve window
- If `${var}` matches `^dry-run` → `MODE=dry-run`. Strip the prefix; remainder treated as window override.
- Otherwise `MODE=execute`.
- If the remaining var parses as a positive integer N → `WINDOW_HOURS=N` and `WINDOW_DAYS=$((N / 24))` (round down). Cap at 720h (30 days).
- Otherwise `WINDOW_HOURS=168`, `WINDOW_DAYS=7`.
- Compute `WINDOW_START_DATE` = today minus `WINDOW_DAYS` days (UTC, ISO date).
### 2. Collect agent-health signals
a. **Latest analytics article.** `LATEST_ANALYTICS=$(ls -1t output/articles/skill-analytics-*.md 2>/dev/null | head -1)`. If found AND its date suffix is within the window → parse the metadata line `*Window: ... · N runs across M skills · X% success · Y anomalies*` for `total_runs`, `distinct_skills`, `success_pct`, `anomaly_count`. If not found (`skill-health`'s analytics view didn't run this window): set all four to `null` and mark `agent_health_source=missing`.
b. **Heartbeat verdicts.** For every heartbeat run logged in the window, scan `memory/logs/YYYY-MM-DD.md` between `WINDOW_START_DATE` and today for `## Heartbeat` sections. Count occurrences of: `P0` / `P1` / `P2` / `P3` / `OK` markers. The simplest first-match wins per heartbeat block: an `OK` block (no P-flags) increments `heartbeat_ok`; any P-flag increments the matching `heartbeat_pX` counter and skips the OK count. If no heartbeat sections found, set counts to zero and mark `agent_health_source=partial`.
c. **Open issues.** If `memory/issues/INDEX.md` exists and contains an `## Open` section with table rows, count rows. Otherwise `open_issues=0` and `issues_source=absent`.
d. **Compute health verdict (paragraph 1):**
- `OK` if `success_pct >= 90` AND `anomaly_count <= 1` AND `heartbeat_p0 == 0` AND `heartbeat_p1 == 0`
- `WATCH` if `success_pct >= 75` AND `heartbeat_p0 == 0` AND (`anomaly_count <= 3` OR `heartbeat_p1 <= 2`)
- `DEGRADED` otherwise
- If `agent_health_source=missing`: emit `INSUFFICIENT_DATA` for this paragraph's verdict (don't pretend OK)
### 3. Collect community-growth signals
a. **Stars + forks delta.** Sum every `output/articles/repo-pulse-*.md` file with date suffix in window. From each, extract the `New stars (24h)` count and `New forks (24h)` count for each watched repo. Aggregate per-repo totals across the window. The `aeonfun/aeon` row is the headline; other repos go on a continuation line.
If the file format doesn't contain the canonical fields, fall back to scanning `memory/logs/*.md` for `## Repo Pulse` blocks (older format). If both fail for a given repo: `stars_added=null`, mark `growth_source=partial`.
b. **New contributors.** Count first-time merged-PR authors in the window from the GitHub search API — `search/issues?q=repo:<repo>+is:pr+is:merged+merged:<start>..<end>` (via `gh api` in write mode, or WebFetch `https://api.github.com/search/issues?...` in read-only). For each unique non-bot author, a prior-PR check (`…+author:<login>+merged:<<start>` → `total_count == 0`) marks them new; `new_contributors` = that count. If the GitHub API is unavailable: `new_contributors=null`.
c. **Notable mentions.** Scan `output/articles/repo-article-*.md` and `output/articles/project-lens-*.md` filenames in window for any title containing milestones-language (regex `(milestone|launch|hit \d+|featured|HN|Show HN|Hacker News)`). If found, capture up to 2 titles for the `Notable` line. Otherwise omit.
d. **Compute growth verdict (paragraph 2):**
- `OK` if `total_stars_added >= 20` OR `new_contributors >= 1` (a real signal of community pull)
- `WATCH` if `total_stars_added >= 5`
- `DEGRADED` if `total_stars_added < 5` AND `new_contributors == 0` AND no notable mentions
### 4. Collect economic-activity signals
a. **$AEON distributed.** Sum every `output/articles/tweet-allocator-*.md` in the window: extract the `Total distributed: $X.XX in $AEON` line. Track the count of `Paid tweets:` recipients across the window (deduped by handle).
If `output/articles/distribute-tokens-*.md` exists in the window, also tally any explicit on-chain payouts there. Report both as `$AEON distributed: $X.XX (Y recipients via tweet-allocator + Z via distribute-tokens)`.
b. **Compute economic verdict (paragraph 3):**
- `OK` if `total_distributed > 0`
- `DEGRADED` if `total_distributed == 0` (week with $0 spend on community = silent loop)
### 5. Roll up to the overall verdict
- Take the worst of the three paragraph verdicts. `DEGRADED` > `WATCH` > `OK`.
- `INSUFFICIENT_DATA` paragraphs do **not** force the overall verdict to DEGRADED — they degrade to `WATCH` (so a partial-data week still flags as worth checking, not ignored).
- The verdict line uses the same vocabulary as `heartbeat`'s P-flags for visual continuity: `🟢 OK` / `🟡 WATCH` / `🔴 DEGRADED`.
### 6. Build the article
Path: `output/articles/operator-scorecard-${today}.md`. Overwrite if exists (idempotent same-day reruns).
```markdown
# Operator Scorecard — ${today}
**Verdict:** ${verdict_emoji} ${verdict_label} — ${one_line_summary}
*Window: last ${WINDOW_DAYS}d (${WINDOW_START_DATE} → ${today})*
## Agent health
The fleet ran ${total_runs} times across ${distinct_skills} skills with a ${success_pct}% success rate. ${anomaly_count} anomaly flag(s) raised this week. Heartbeat issued ${heartbeat_ok} clean reports and ${heartbeat_p0+p1+p2+p3} flagged reports (P0=${heartbeat_p0} P1=${heartbeat_p1} P2=${heartbeat_p2} P3=${heartbeat_p3}). ${open_issues} open issue(s) in the tracker.
**Verdict:** ${health_verdict}
## Community growth
${watched_repo_1} added ${stars_1} stars and ${forks_1} forks. ${watched_repo_2} added ${stars_2} stars and ${forks_2} forks. ${total_stars_added} stars across the fleet — averaging ${stars_per_day} per day. ${new_contributors} new contributor(s) appeared on the leaderboard. ${notable_line_or_omit}
**Verdict:** ${growth_verdict}
## Economic activity
$AEON distributed: $${total_distributed} across ${recipient_count} recipient(s) via tweet-allocator${distribute_tokens_addendum_or_omit}.
**Verdict:** ${economic_verdict}
## What was notable
${bullet list of up to 3 entries from MEMORY.md "Skills Built" rows where date is in window — keeps the week's autonomous accomplishments visible}
## Source status
- skill-health (analytics): ${article_path or "missing this window"}
- heartbeat: ${N runs found in memory/logs}
- repo-pulse: ${N daily articles in window}
- tweet-allocator: ${N daily articles in window} · total: $${total_distributed}
- new-contributors: ${new_contributors or "GitHub API unavailable"}
---
*Companion to `skill-health`'s analytics view (per-skill ranking) and heartbeat (per-run pulse). This branch answers the operator-level question those two don't: "given everything that happened, was this week worth it?" Methodology: every number is sourced from another skill's article — this branch measures nothing itself.*
```
The "What was notable" section reads `memory/MEMORY.md` for rows in the `## Skills Built` table where the `Date` column falls in the window. List up to 3, formatted as `- {Skill} — {one-line summary truncated to ~120 chars}`. If zero new skills built this week, write `- No new skills built this week — agent ran on the existing fleet.`
### 7. Write the dashboard JSON spec
Path: `apps/dashboard/outputs/operator-scorecard.json`. Use the catalog components.
```json
{
"version": "1",
"generated_at": "${ISO timestamp}",
"skill": "operator-scorecard",
"title": "Operator Scorecard — ${today}",
"spec": {
"type": "Stack",
"props": {"direction": "vertical", "gap": "md"},
"children": [
{"type": "Heading", "props": {"level": 2, "children": "Operator Scorecard — ${today}"}},
{"type": "Alert", "props": {"variant": "${alert_variant}", "children": "${verdict_label} — ${one_line_summary}"}},
{"type": "Grid", "props": {"columns": 3, "gap": "sm"}, "children": [
{"type": "Card", "props": {"children": [
{"type": "Text", "props": {"variant": "muted", "children": "Agent health"}},
{"type": "Heading", "props": {"level": 3, "children": "${success_pct}%"}},
Ver en GitHub