Agent Skillsaaronjmars/aeon › Heartbeat

Heartbeat

GitHub

执行舰队健康检查,默认每日自动运行以监控技能状态、失败及API降级;支持按需生成优先级简报,列出当日重点事项及变动。通过解析变量var控制检查范围或触发简报模式。

skills/heartbeat/SKILL.md aaronjmars/aeon

Trigger Scenarios

用户请求舰队整体健康状况检查 需要获取当前需关注的3个优先事项及原因 指定特定领域(如crypto)进行聚焦检查 Cron定时任务每日08:00 UTC触发

Install

npx skills add aaronjmars/aeon --skill Heartbeat -g -y
More Options

Use without installing

npx skills use aaronjmars/aeon@Heartbeat

指定 Agent (Claude Code)

npx skills add aaronjmars/aeon --skill Heartbeat -a claude-code -g -y

安装 repo 全部 skill

npx skills add aaronjmars/aeon --all -g -y

预览 repo 内 skill

npx skills add aaronjmars/aeon --list

SKILL.md

Frontmatter
{
    "var": "",
    "name": "Heartbeat",
    "tags": [
        "meta"
    ],
    "type": "Skill",
    "category": "meta",
    "requires": [
        "RESEND_API_KEY?"
    ],
    "description": "Ambient fleet-health check that surfaces anything worth attention (default), or an on-demand priority brief — the 3 things to focus on, why now, and what moved (var=brief)"
}

${var} — selector. Empty (default) = the ambient fleet check — the live path a cron runs once a day; leave it empty for the scheduled run. brief = the priority brief. See the grammar below.

Selector / ${var} grammar

  • `` (empty)Ambient check across all skills / PRs / issues, and regenerate the public status page. This is the live, scheduled path (08:00 UTC daily); its behaviour is unchanged. Leave ${var} empty for the cron.
  • <area> (any non-empty value that is not brief, e.g. crypto, prs) — Ambient check, with the checks focused on that area (original heartbeat focus-area behaviour).
  • briefPriority brief: rank the 3 things to focus on today, why now, and what moved since yesterday; send via ./notify + email.
  • brief:<area> (e.g. brief:crypto) — Priority brief biased toward <area>.

Shared setup (every run)

Read memory/MEMORY.md and the last 2 days of memory/logs/ for context.

Parse ${var} to pick the branch:

  • starts with brief (i.e. brief or brief:<area>) → run the Priority brief branch. Any text after brief: is the emphasis area.
  • otherwise (empty, or any other value) → run the Ambient check branch. A non-empty value is the focus area; empty runs all checks.

The two branches are mutually exclusive — run exactly one per invocation.


Ambient check (default — empty ${var}; the LIVE scheduled path)

If ${var} is set to a focus area, focus checks on that specific area.

Checks (in priority order)

P0 — Failed & stuck skills (check first)

Read memory/cron-state.json. If the file is missing or empty (e.g. a fresh fork whose scheduler hasn't written it yet), treat state as empty: report no cron-state yet for the P0 tier, skip the failure/degradation checks below, and still render the status page (every enabled skill shows not yet run). This file tracks every scheduled skill's state and quality metrics:

{
  "skill-name": {
    "last_dispatch": "2026-04-06T12:00:00Z",
    "last_status": "dispatched|success|failed",
    "last_success": "2026-04-06T12:05:00Z",
    "last_failed": "2026-04-05T12:03:00Z",
    "total_runs": 10,
    "total_successes": 8,
    "total_failures": 2,
    "consecutive_failures": 0,
    "success_rate": 0.80,
    "last_quality_score": 4,
    "last_error": "error signature text"
  }
}

Flag these conditions:

  • Failed skills: any entry with last_status: "failed". Report the skill name and when it failed.
  • Stuck skills: any entry with last_status: "dispatched" where last_dispatch is >45 minutes ago. The skill was dispatched but never reported back — likely hung or crashed before the state update step ran.
  • API degradation: any skill with consecutive_failures >= 3. This likely indicates an external API is down or rate-limiting. Report the skill, failure count, and last_error. If multiple skills share similar error signatures, flag the shared dependency.
  • Chronic failures: any skill with success_rate < 0.5 (and total_runs >= 5). The skill is failing more than it succeeds.
  • Self-check: if heartbeat's own entry shows last_success is >36 hours ago (or missing), note that heartbeat itself may be unreliable.

P1 — Stalled PRs & urgent issues

  • Any open PRs stalled > 24h? (use gh pr list)
  • Any GitHub issues labeled urgent? (use gh issue list)

P2 — Flagged memory items

  • Anything flagged in memory/MEMORY.md that needs follow-up?

P3 — Missing scheduled skills

Read aeon.yml for enabled skills with schedules. Cross-reference with memory/cron-state.json:

  • If an enabled skill has no entry at all in the state file, it has never been dispatched by the scheduler.
  • If a skill's last_success is >2x its schedule interval old (e.g., a daily skill hasn't succeeded in >48h), flag it.

Do NOT use gh run list for this — the state file is authoritative.

Dedup & notification

Before sending any notification, grep memory/logs/ for the same item. If it appears in the last 48h of logs, skip it. Never notify about the same item twice.

Batch all findings into a single notification, grouped by priority tier:

🔴 FAILED: skill-a (failed 2h ago), skill-b (stuck 1h ago)
🟡 STALLED: PR #42 open 3 days
🔵 MEMORY: follow-up on X flagged 2 days ago

Public status page

After the priority checks (even when everything is green — this step always runs), regenerate docs/status.md so it reflects current fleet health.

Data sources

  • memory/cron-state.json — per-skill run state (authoritative)
  • memory/issues/INDEX.md — open issue table
  • aeon.yml — enabled skill list with schedules
  • Latest output/articles/token-report-*.md (most recent by filename date) — optional; powers the Token Pulse section. Skipped silently when no file exists.

Overall status

Compute one of three overall states from the same signals used above. This verdict drives the public, fork-facing status page, so reserve 🔴 for skills that are currently broken — a single transient failure a skill has already recovered from must not flip the whole page red:

  • 🔴 DEGRADED — a skill is currently and persistently broken: a stuck skill; consecutive_failures ≥ 3; chronic failures (success_rate < 0.5 with total_runs ≥ 5); heartbeat self-check >36h stale; or a last_status: "failed" skill that has not recovered since (last_failedlast_success) and consecutive_failures ≥ 2.
  • 🟡 WATCH — a transient blip or watch-item: a last_status: "failed" skill that already recovered (last_success > last_failed); or any other last_status: "failed" skill that does not meet the 🔴 bar above (e.g. a first or isolated failure, consecutive_failures ≤ 1, including a skill whose only run so far failed) — a non-recovered failure must never read 🟢 OK; or any P1/P2/P3 flag (stalled PRs, urgent issues, flagged memory items, skills >2x their schedule interval old); or any open issue with severity critical or high.
  • 🟢 OK — no flags at all.

This refines only the public status-page colour. It does not change the P0 notification rules above — a fresh last_status: "failed" still fires its notification (deduped per the rules above) so the operator is always told; the page just won't read 🔴 for a blip the fleet has already shrugged off.

Format

Write docs/status.md with frontmatter so it renders as a status page:

---
layout: default
title: "Status"
permalink: /status/
---

# Agent Status

**Overall:** 🟢 OK
**Updated:** 2026-04-24 19:06 UTC
**Open issues:** 0
**Next scheduled run:** heartbeat at 08:00 UTC

Auto-generated by the `heartbeat` skill on every run (daily at 08:00 UTC). If the Updated timestamp is more than ~26h stale, the agent is not running.

## Token pulse

| Token | Price | 24h | Liquidity | Volume (24h) | FDV |
|-------|-------|-----|-----------|--------------|-----|
| <TOKEN> | $0.0000032626 | -11.16% | $223.4K | $41.3K | $326.3K |

_Source: `output/articles/token-report-YYYY-MM-DD.md` · verdict: SLIDING_ (illustrative — symbol/figures come from the latest token-report)

## Skill health (last 7 days)

| Skill | Last run | Status | Success rate | Consecutive failures |
|-------|----------|--------|-------------:|---------------------:|
| token-report | 2026-04-24 12:30 UTC | ✅ success | 100% | 0 |
| fetch-tweets | 2026-04-24 06:53 UTC | ✅ success | 95% | 0 |
| …           | …                    | …         | …    | … |

## Open issues

_(if INDEX.md has any open rows, render them here; otherwise: "No open issues.")_

| ID | Title | Severity | Category | Detected |
|----|-------|----------|----------|----------|
| ISS-001 | … | medium | rate-limit | 2026-04-22 |

---
*Fork this repo and your copy inherits this page automatically — [how it works](/memory/).*

Rules

  • Include all enabled skills from aeon.yml (not only those with recent runs). For skills with no entry in cron-state.json, show for timestamp and not yet run in status.
  • Sort the skill table by last-run timestamp descending (most recent first); skills that have never run sink to the bottom.
  • Format timestamps as YYYY-MM-DD HH:MM UTC (strip seconds and the Z).
  • Success rate shows total_successes / total_runs × 100 rounded to whole percent; display when total_runs == 0.
  • Status column icons: ✅ success, ❌ failed, ⏳ dispatched (if last_dispatch within 45min), 🕸 stuck (if last_dispatch > 45min and last_status still dispatched), (never run).
  • For the Next scheduled run: line, pick the enabled skill with the soonest upcoming cron time relative to now.
  • Dedup state: re-running heartbeat overwrites docs/status.md wholesale each time — do not append.
  • Never expose values from .env, secrets, or anything outside cron-state.json + issues/INDEX.md + aeon.yml + output/articles/token-report-*.md. This file is public.

Token pulse rules

  • Pick the latest output/articles/token-report-*.md by filename date (sort descending, take the first match).
  • Staleness: if the picked file's date is older than 24h relative to the heartbeat run timestamp, render _No recent token data (latest report YYYY-MM-DD)._ in place of the table — do not lift stale figures into the table.
  • No file at all: omit the ## Token pulse section entirely. The status page must still render cleanly with no token row.
  • Token symbol: read from memory/MEMORY.md "Tracked Token" table (first row, Token column). If the table is missing, render the heading as ## Token pulse with the symbol column blank.
  • Field extraction (regex, tolerant of both old Value | 24h Change and new Now | 24h Δ table layouts):
    • Price: first | Price | row → first $ value in the row → strip whitespace.
    • 24h: same Price row → first ±?\d+(\.\d+)?% token in the row (typically the second cell). Render as written, preserving sign. If absent, render .
    • Liquidity: first | Liquidity | row → first $ value.
    • Volume (24h): first row whose first cell matches Volume\b.*24h or 24h Volume → first $ value.
    • FDV: first | FDV | row → first $ value.
    • For any field whose row or $ value cannot be located, render for that cell only — do not skip the section.
  • Verdict line: if the source article contains a **Verdict:** LABEL line, append · verdict: LABEL to the source line. If no Verdict line is present (older format), omit the suffix.
  • Source link: the trailing _Source: ..._ line names the exact article file used so a reader can verify the numbers.

The file lands on main through the workflow's auto-commit step — no explicit git commands needed in this skill.

Output (ambient)

If nothing needs attention, log "HEARTBEAT_OK" (plus the overall status page verdict, e.g. HEARTBEAT_OK · STATUS_PAGE=OK) and end your response.

If something needs attention:

  1. Send a single concise notification via ./notify (grouped by priority as above)
  2. Log the findings and actions taken to memory/logs/${today}.md (under the shared ### heartbeat heading — see Log — with a mode: ambient discriminator line)
  3. Log one line with the status-page verdict, e.g. STATUS_PAGE=DEGRADED — wrote docs/status.md

Priority brief (${var} = brief or brief:<area>)

Runs instead of the ambient check. Any text after brief: (e.g. brief:crypto) is the area to emphasize; a bare brief covers all areas.

A good brief is a priming document, not a news dump. Every line must answer "so what?".

Today is ${today}. Read memory/MEMORY.md, memory/logs/${yesterday}.md (and today's if it exists), and memory/cron-state.json (if present).

1. Rank, don't aggregate

Collect candidate items from:

  • MEMORY.md "Next Priorities"
  • Yesterday's log: unfinished work, follow-ups, notes
  • Pending repo items: gh pr list --state open --limit 10 and gh issue list --state open --limit 10 --assignee @me
  • memory/cron-state.json: skills with consecutive_failures >= 2 or success_rate < 0.8
  • aeon.yml: skills whose cron matches today

Score each candidate on leverage × urgency:

  • Leverage = does progressing this change the next 7 days?
  • Urgency = does delay today make it worse?

Keep at most 3 focus items. Everything else either goes in "Since yesterday" or is dropped. If the emphasis area is set (brief:<area>), bias ranking toward that area but do not force a focus item if nothing qualifies.

2. Headlines — only if they change priorities

Use WebSearch for 2 headlines in the user's tracked areas (AI and crypto by default; emphasize the brief:<area> value if set). Include a headline only if it meaningfully updates one of the 3 focus items, flags a new risk, or implies an action (a deadline, a market move, a shipped competitor, a disclosed exploit). If nothing qualifies, omit the Watch section entirely. No filler.

3. Format — terse, scannable, opinionated

*Priority Brief — ${today}*

*Focus today*
1. [item] — why now: [≤12 words]
2. [item] — why now: [≤12 words]
3. [item] — why now: [≤12 words]

*Since yesterday*
- [moved]: what changed (link if relevant)
- [stuck]: what's blocked, on whom

*Watch* (omit entirely if nothing qualifies)
- [headline] — implication for focus #N

*Running today*
- skill @ HH:MM UTC

Style rules:

  • Every focus item should state why now in ≤12 words. If you can't, demote it.
  • "Since yesterday" is ≤5 bullets; merge duplicates across PR/issue/log sources.
  • No throat-clearing ("here's your briefing…"). Lead with Focus.
  • No empty sections — omit rather than print "(none)".
  • If fewer than 3 candidates survive the why-now bar, allow up to 1 background item (tagged background: instead of why now:) so the brief still surfaces something worth knowing on quiet days. Never invent items, and never include more than 1 background item.
  • If soul files under soul/ are populated, match that voice; otherwise keep it direct and neutral (per CLAUDE.md).

4. Send via ./notify and email

  • Send the formatted brief with ./notify "...".
  • Send email via Resend (optional — skip cleanly when unconfigured):
    • Preflight: if $RESEND_API_KEY is empty/unset or $BRIEF_RECIPIENTS has no addresses, skip the email step entirely — the ./notify send above already delivered the brief. Note the skip in the log (email: skipped (no RESEND_API_KEY)) and continue; do not fail the run. RESEND_API_KEY is an optional dependency.
    • When configured:
      • Build the brief as HTML (wrap each section in <h2> headers, <ul>/<li> bullets)
      • Also keep a plain-text copy (the ./notify content above, as-is)
      • Parse $BRIEF_RECIPIENTS as a comma-separated list of addresses
      • POST to https://api.resend.com/emails:
        Authorization: Bearer $RESEND_API_KEY
        Content-Type: application/json
        
        {
          "from": "Aeon Briefings <onboarding@resend.dev>",
          "to": ["<each recipient>"],
          "subject": "[Aeon] Priority Brief — ${today}",
          "html": "<html version>",
          "text": "<plain-text version>"
        }
        
      • Log the id field from the Resend response to memory/logs/${today}.md for traceability
      • If the key is set and Resend returns an error, log the full error body and fail loudly (do not silently continue) — a real send failure is a signal, an absent optional key is not
  • Append to memory/logs/${today}.md under the shared ### heartbeat heading (see Log) with a mode: brief discriminator line: timestamp, the 3 focus items (one line each), headline count, and any skills flagged from cron-state. This becomes tomorrow's "since yesterday" input.

Log

Both branches append to memory/logs/${today}.md under a single ### heartbeat heading (the health loop parses this shape). Begin the entry with a discriminator line naming the branch that ran:

  • mode: ambient — the default fleet check. Log the status-page verdict, e.g. STATUS_PAGE=OK, or HEARTBEAT_OK · STATUS_PAGE=OK when nothing needed attention; on findings, log the findings and actions taken plus the STATUS_PAGE=… line.
  • mode: brief — the priority brief. Log the timestamp, the 3 focus items (one line each), the headline count, and any skills flagged from cron-state.

Sandbox note

Applies to both branches. The sandbox may block outbound curl. Use WebFetch as a fallback for any URL fetch. For GitHub queries (both branches use gh pr list / gh issue list), use the gh CLI (handles auth internally) rather than curl. The priority-brief Resend POST carries $RESEND_API_KEY; if curl is blocked, retry the same request via WebFetch.

Version History

  • fb16753 Current 2026-07-05 12:06

Same Skill Collection

skills/action-converter/SKILL.md
skills/article/SKILL.md
skills/auto-merge/SKILL.md
skills/auto-workflow/SKILL.md
skills/autoresearch/SKILL.md
skills/bd-radar/SKILL.md
skills/changelog/SKILL.md
skills/code-health/SKILL.md
skills/cost-report/SKILL.md
skills/create-skill/SKILL.md
skills/ctrl/SKILL.md
skills/defi-overview/SKILL.md
skills/deploy-prototype/SKILL.md
skills/digest/SKILL.md
skills/distribute-tokens/SKILL.md
skills/ecosystem-pulse/SKILL.md
skills/fear-divergence/SKILL.md
skills/feature/SKILL.md
skills/fetch-tweets/SKILL.md
skills/fleet-control/SKILL.md
skills/fork-fleet/SKILL.md
skills/github-monitor/SKILL.md
skills/github-trending/SKILL.md
skills/idea-forge/SKILL.md
skills/idea-pipeline/SKILL.md
skills/inbox-triage/SKILL.md
skills/install-skill/SKILL.md
skills/investigation-report/SKILL.md
skills/issue-triage/SKILL.md
skills/last30/SKILL.md
skills/memory-flush/SKILL.md
skills/mention-radar/SKILL.md
skills/monitor-polymarket/SKILL.md
skills/narrative-convergence/SKILL.md
skills/narrative-tracker/SKILL.md
skills/okf-export/SKILL.md
skills/okf-ingest/SKILL.md
skills/onchain-monitor/SKILL.md
skills/operator-scorecard/SKILL.md
skills/picks-tracker/SKILL.md
skills/pm-manipulation/SKILL.md
skills/pm-pulse/SKILL.md
skills/pr-review/SKILL.md
skills/pr-triage/SKILL.md
skills/price-alert/SKILL.md
skills/reply-maker/SKILL.md
skills/repo-scanner/SKILL.md
skills/schedule-ads/SKILL.md
skills/search-skill/SKILL.md
skills/self-improve/SKILL.md
skills/send-email/SKILL.md
skills/skill-health/SKILL.md
skills/skill-repair/SKILL.md
skills/soul-builder/SKILL.md
skills/spawn-instance/SKILL.md
skills/strategy-builder/SKILL.md
skills/token-movers/SKILL.md
skills/token-pick/SKILL.md
skills/treasury-info/SKILL.md
skills/tx-explain/SKILL.md
skills/unlock-monitor/SKILL.md
skills/verdikta-hunter/SKILL.md
skills/vuln-scanner/SKILL.md
skills/vuln-tracker/SKILL.md
skills/workflow-audit/SKILL.md
skills/write-tweet/SKILL.md
skills/x402-monitor/SKILL.md
skills/base-mcp/SKILL.md
skills/star-milestone/SKILL.md

Metadata

Files
0
Version
fb16753
Hash
b097bac9
Indexed
2026-07-05 12:06

Accueil - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-07-10 09:39
浙ICP备14020137号-1 $Carte des visiteurs$