milestone-tracker

$npx mdskill add aaronjmars/aeon/milestone-tracker

Today is ${today}. Read `memory/MEMORY.md` before starting.

SKILL.md

.github/skills/milestone-trackerView on GitHub ↗
---
name: milestone-tracker
description: Weekly progress tracking for key product and growth milestones — celebrates crossings, alerts on approaches, surfaces stalls
var: ""
tags: [meta, projects]
---

Today is ${today}. Read `memory/MEMORY.md` before starting.

## Goal

Track progress toward defined milestones across repos, system capabilities, and product goals. Milestones live in `memory/milestones.md`. Each run: fetch current state, compare to last recorded, classify status, notify on anything notable.

One skill, one job: are we moving?

## Steps

### 1. Load milestone config

Read `memory/milestones.md`. If it doesn't exist, create it with the seed config below and continue.

**Seed config** (write to `memory/milestones.md` if missing — replace placeholder rows with the operator's actual targets):

```markdown
# Milestones

*Last run: never*

| ID | Label | Target | Baseline | Last | Status |
|----|-------|--------|----------|------|--------|
| ms-01 | Example repo stars | stars:owner/repo:1000 | 0 | 0 | on-track |
| ms-02 | Enabled skills | skills:30 | 0 | 0 | on-track |
```

Parse the table: each row is one milestone. The `Target` field encodes the data source:
- `stars:{owner}/{repo}:{target_count}` — GitHub star count
- `skills:{target_count}` — count skills with `enabled: true` in aeon.yml
- `manual:{label}` — operator-maintained, status updated by hand

### 2. Fetch current state

For **star milestones**, use `gh api` to get current star counts:

```bash
gh api repos/${owner}/${repo} --jq '.stargazers_count'
```

If `gh api` fails on a repo (private, rate limit, etc.): fall back to the `Last` value from the config — don't fail the whole run.

For **skills milestones**, count enabled skills:

```bash
grep -c 'enabled: true' aeon.yml
```

For **manual milestones**, leave `Last` unchanged and use the operator-set status.

### 3. Classify each milestone

For each milestone, compute:
- `current` — fetched value from step 2
- `delta` — `current - last` (change since last run)
- `pct` — `(current / target) * 100`
- `weeks_stalled` — if `delta == 0`, check how many consecutive weekly runs had `delta == 0` (stored in the `Status` field as `stalled-N`)

Then classify:

| Condition | Status |
|-----------|--------|
| `current >= target` AND `last < target` | **crossed** — just hit it this run |
| `current >= target` AND `last >= target` | **done** — already crossed, skip |
| `pct >= 90` | **approaching** — within 10% of target |
| `delta == 0` AND `weeks_stalled >= 2` | **stalled** — no movement in 2+ weeks |
| otherwise | **on-track** |

Skip milestones with status `done` — don't re-celebrate or re-alert.

### 4. Decide whether to notify

- **Nothing notable** (all `on-track` or `done`): log `MILESTONE_TRACKER_OK: no alerts` and skip notification.
- **Any `crossed`, `approaching`, or `stalled`**: send notification.

### 5. Format notification

Write to `.pending-notify-temp/milestone-tracker-${today}.md` (create dir if needed), then:

```
./notify -f .pending-notify-temp/milestone-tracker-${today}.md
```

Format (if soul files are populated, match that voice; otherwise use a clear, direct, neutral tone):

```
milestone check — ${today}

{IF any crossed}
crossed:
{forEach crossed}
- {label}: {current}/{target} — done
{end}

{IF any approaching}
approaching:
{forEach approaching}
- {label}: {current}/{target} ({pct}%)
{end}

{IF any stalled}
stalled ({weeks_stalled}w no movement):
{forEach stalled}
- {label}: {current}/{target} — stuck at {pct}%
{end}

{IF any on-track with delta > 0}
moving this week:
{forEach on-track with delta > 0}
- {label}: +{delta} → {current}/{target}
{end}
```

No empty sections. If `crossed` is empty, omit it entirely. Same for the others.

### 6. Update memory/milestones.md

Rewrite the table with:
- Updated `Last` values (current state)
- Updated `Status` values (new classification)
- Updated header: `*Last run: ${today}*`

For `stalled` milestones, encode the count: `stalled-{N}` (e.g., `stalled-2` means no movement for 2 consecutive runs).

For `done` milestones (crossed and staying crossed), set status to `done:{crossed_date}` (e.g., `done:2026-05-12`).

### 7. Log to memory/logs/${today}.md

Append:

```markdown
## Milestone Tracker
- **Milestones checked:** {total}
- **Crossed:** {list or "none"}
- **Approaching:** {list or "none"}
- **Stalled:** {list or "none"}
- **On-track with movement:** {count}
- **Notification:** sent / skipped
- MILESTONE_TRACKER_OK
```

## Sandbox Note

Uses `gh api` for GitHub star counts — `gh` CLI handles auth internally, no env-var expansion needed. `grep` on `aeon.yml` is local-only. No external network beyond GitHub API.

## Required Env Vars

None — `gh` CLI uses the workflow's `GITHUB_TOKEN` automatically.

## Adding Milestones

Add rows to `memory/milestones.md`. Supported target formats:
- `stars:{owner}/{repo}:{N}` — repo star count
- `skills:{N}` — enabled skills in aeon.yml
- `manual:{label}` — operator-maintained text milestone; update status by hand in the file

More from aaronjmars/aeon

SkillDescription
[REPLACE: SKILL_NAME]Watch Vercel deploys for [REPLACE: VERCEL_PROJECT] — alert on [REPLACE: ALERT_ON] in the last [REPLACE: LOOKBACK_HOURS] hours
Action Converter5 concrete real-life actions for today, leverage-scored against open loops with specificity and anti-fluff gates
Agent BuzzCurated AI-agent tweets, clustered into narratives with insight summaries
agent-displacementWeekly tracker of AI agent substitution signals — which roles, companies, and industries show real headcount displacement. Named roles + real deployments only.
AI Framework WatchWeekly competitive-intelligence digest on the AI agent framework space — momentum, releases, breaking changes across a curated watchlist
AIXBT PulseCross-domain market pulse from AIXBT's free grounding endpoint — crypto, macro, tradfi, geopolitics. Refreshes taxonomy references (clusters, chains) as a bonus.
api-health-probeDaily pre-batch API provider health check — detects credit exhaustion or auth failure for every configured provider key before the morning batch runs, giving the operator a window to act before skills degrade
Approval AuditList 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.
article-queueWeekly article idea synthesizer — ranks signals from topic-momentum, beat-tracker, and narrative-tracker into a prioritized queue the article skill reads on next run
atrium-catalog-watcherWeekly diff of the Atrium marketplace catalog at https://atriumhermes.tech/.well-known/skills/index.json against the prior snapshot — surfaces newly-published skills, removed skills, and updated descriptions. Supply-side complement to sparkleware-catalog (curated skill-packs.json registry) and skill-update-check (version drift of installed skills).