beat-tracker
**beat-tracker** This Claude Code skill maintains a persistent counter of news story developments across active storylines, automatically detecting when a story accumulates three distinct beats (new sources, statements, or policy moves) within 30 days and triggers an alert. Use it to avoid manually tracking evolving news threads across scattered daily logs and to fire alerts only when stories reach article-readiness without manual intervention.
git clone --depth 1 https://github.com/aaronjmars/aeon /tmp/beat-tracker && cp -r /tmp/beat-tracker/skills/beat-tracker ~/.claude/skills/beat-trackerSKILL.md
Today is ${today}. Read memory/MEMORY.md (and soul/SOUL.md if present) before starting.
## Why this skill exists
tweet-roundup and reflect note when a storyline gets a new beat — but that state lives in daily logs, not in a persistent counter. By the time a thread hits 3 beats (article-ready), the signal is buried across 3 different log entries and nobody fires the alert. This skill fixes that: persistent beat counts per storyline, automated threshold detection, no manual tracking required.
A **beat** is a distinct new development in an ongoing news story: a new source weighing in, a new actor making a statement, a new policy move, a price/volume reaction. Three beats in <30 days = the story has enough material to write about.
This fills the gap between:
- **topic-momentum** (scores what to write based on signal frequency) — broad, pattern-based
- **narrative-tracker** (EMERGING/RISING/PEAK/FADING phases) — narrative-level, not event-level
- **beat-tracker** (THIS) — event-level, specific stories, fires when threshold is crossed
## Steps
### 1. Load beat state
Read `memory/topics/beat-tracker.md`.
If the file doesn't exist, initialize it as an empty Active Threads list:
```
# Beat Tracker
Last updated: ${today}
## Active Threads
(none — will populate from memory on first inject pass)
## Closed Threads
(none yet)
```
Parse all threads under `## Active Threads`. For each thread, extract:
- Thread name
- Search query
- Status (active / article-ready / stale)
- Beat count
- Last checked date
- List of existing beats (date + source + summary)
### 2. Inject new threads from memory
Scan these sources for threads NOT already in beat-tracker.md:
**a) MEMORY.md content signals:**
Read `memory/MEMORY.md`. Look for content-signal notes that mention multi-beat storylines with at least 2 beats. Extract them.
Pattern to detect: "N beats" or "beat count: N" or "2 parallel threads" near a topic name.
**b) Recent logs (last 7 days):**
Use Glob on `memory/logs/*.md`. Take the 7 most recent by filename. Scan each for lines mentioning "beat" next to a number ≥ 2, or "thread" with a beat count. Extract thread name and any dated beat events listed.
For each newly discovered thread:
- Infer a **search query** from the topic name (2–5 keywords, specific enough to find news, not so broad it matches noise)
- Pull any historical beats already mentioned in the logs (date + source)
- Add to Active Threads with those historical beats pre-loaded
- Set `last_checked: ${today}`
If zero new threads are discovered and Active Threads is empty: log `BEAT_TRACKER_SKIP: no threads to track — check memory injection` and stop.
### 3. Search for new beats
For each thread in Active Threads where `status != stale`:
Run a **WebSearch** using the thread's search query. Focus on results from the past 7 days (mention the date window in your query, e.g. "after:{date 7 days ago}").
Evaluate results for **new beats** not already listed in the beats array:
- Different source/actor than existing beats
- New factual development (not a repost/recap of old news)
- Occurred AFTER the most recent beat date in the list
If a new beat is found:
- Add: `- ${today}: {Source/Handle} — {one-line factual summary}`
- Increment beat_count by 1
- Update last_checked: ${today}
If no new beat: update last_checked only (no increment).
### 4. Flag thresholds
After updating all threads:
**Article-ready (≥3 beats):**
Set `status: article-ready`. Prepare a hook line in the operator's voice (soul files):
- Observe what the 3-beat pattern reveals (not just what happened)
- Diagnose why it keeps getting a new beat
- End on the implication — punchy, no hedge
**Warming up (2 beats, most recent beat within 5 days):**
Note these as "watch closely" — one beat from article-ready.
**Stale (0 new beats for 14+ days AND beat_count < 3):**
Set `status: stale`. Will be moved to Closed Threads in step 6.
### 5. Cross-check articles
Use Glob on `articles/*.md`. For any article-ready thread, check if an article was already published on this topic (scan article filenames and H1s from the past 30 days).
If yes: mark thread as `status: converted` with the article date. Move to Closed Threads.
### 6. Write updated state
Overwrite `memory/topics/beat-tracker.md`:
```markdown
# Beat Tracker
Last updated: {today}
## Active Threads
### {Thread Name}
- **Query:** {search terms used to find new beats}
- **Topic:** {one-line description of the storyline}
- **Status:** active | article-ready | stale
- **Article ready:** YES ({N} beats) | NO ({N} beats, need 3+)
- **Last checked:** {today}
- **Beats:**
- {date}: {Source} — {one-line summary}
- {date}: {Source} — {one-line summary}
- **Beat count:** {N}
(repeat for each active thread)
## Closed Threads
### {Thread Name}
- **Status:** stale | converted
- **Reason:** {14d no new beat | article published {date}}
- **Final beat count:** {N}
- **Closed:** {today}
```
### 7. Send notification
Write the notification to a temp file, then run `./notify -f`.
Only notify if:
- At least one thread is `article-ready` (≥3 beats), OR
- At least one thread jumped to beat count 2 this run (warming up), OR
- At least one new thread was injected this run
Notification content:
```
beat tracker — {today}
{if article-ready threads:}
ARTICLE READY — {beat_count} beats:
→ {thread name}: {hook line in the operator's voice}
{if warming-up (beat 2 newly):}
one beat away:
→ {thread name}: {latest beat summary}
{if new threads injected:}
tracking {N} new threads
{if quiet run — no alerts:}
{N} threads tracked. highest: {beat_count} beats on {thread name}. nothing article-ready yet.
```
Write to `.pending-notify-temp/beat-tracker-${today}.md`. Create the dir if missing. Then:
```bash
./notify -f .pending-notify-temp/beat-tracker-${today}.md
```
Keep under 500 chars. Do NOT use `./notify "$(cat ...)"` — the sandbox trips on long multi-line argv; the `-f` flag reads the file inside the script.
If `BEAT_TRACKER_SKMention/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.