← Back to brief

reference heartbeat schema

memory · reference_heartbeat_schema.md

Filename — REQUIRED format


~/Library/Application Support/SkyRun/health/<YYYY-MM-DD>_<task-id>_<HHMM>.json

Why the format matters: system_hygiene.sh uses a defensive double-glob (_<task>_.json AND <task>_*.json) to detect overdue tasks. Filenames that don't match either pattern are invisible — the watchdog will queue false-positive overdue alerts every cycle.

Required JSON fields — NEVER null

json
{
  "task_id": "<exact-task-id>",
  "status": "ok | partial | skipped | error",
  "started_at": "2026-05-02T01:55:00Z",
  "completed_at": "2026-05-02T02:07:02Z",
  "summary": "<one-line plain-English summary, < 200 chars, of what this run did>",
  "warnings": [],
  "errors": [],
  "metrics": { "<task-specific KPIs>": "<...>" }
}

Field rules:

Optional but recommended

Status field — CANONICAL VALUES (hardwired 2026-05-02 PM, stay-green sweep)

Status MUST be exactly one of:

⛔ DEPRECATED — do NOT write these as status values

GREEN / YELLOW / RED are health classifications computed by nightly-consolidation Section F. They are NOT valid heartbeat status values. Writing them in the status field breaks downstream parsers that expect canonical values.

Forensic precedent: smartlead-bounce-handler previously wrote "status": "YELLOW" for soft-only-bounce runs. This caused two issues: (a) status field non-conforming to schema, (b) yellow-flagging non-actionable conditions (soft bounces are normal background noise — mail will retry). Stay-green sweep 2026-05-02 PM updated the skill to classify soft-only as ok.

Discipline: don't yellow-flag noise

partial is the operator's signal that something needs attention. Reserve it for real signal:

See memory/feedback_stay_green_discipline.md for the full discipline.

Status mapping (legacy reading-only equivalence)

When you encounter a heartbeat written before the 2026-05-02 PM sweep with non-canonical status:

Legacy valueTreat as
GREENok
YELLOWpartial
REDerror
Read with this equivalence; write only canonical values.

Anti-patterns — these caused real bugs

❌ Null required fields

json
{"task_id": null, "started_at": null, "completed_at": null, "summary": null, "status": "GREEN"}
Why bad: build_pwa.py:328 keys on task_id for dashboard rows. Null task_id = task vanishes from PWA. Null timestamps break heartbeat-age math (results in either 999h-old display OR exception swallowed silently).

Real incidents (2026-05-01 fleet-fire audit):

❌ Bare-name filename without date prefix


daily-beenverified-enrichment_2026-05-02T130640Z.json
daily-beenverified-enrichment_latest.json
Why bad: the primary system_hygiene.sh glob is _<task>_.json which requires a leading underscore-separated prefix. Bare-name filenames miss the primary glob. The defensive double-glob catches them as a fallback (added 2026-04-30) but that's a fallback, not the source of truth.

The <task>_latest.json convenience pointer is OK (it's a duplicate write of the latest heartbeat for fast dashboard reads), but the canonical YYYY-MM-DD_<task>_HHMM.json MUST also be written for every run.

How to write a heartbeat (Python example)

python
import json
from datetime import datetime, timezone
from pathlib import Path

started = datetime.now(timezone.utc)

... task logic ...


completed = datetime.now(timezone.utc)

heartbeat = {
"task_id": "my-task-id", # exact match to mcp__scheduled-tasks taskId
"status": "ok", # or 'partial'/'skipped'/'error'
"started_at": started.isoformat().replace('+00:00','Z'),
"completed_at": completed.isoformat().replace('+00:00','Z'),
"summary": "Processed N items; X new, Y updated, Z skipped.",
"warnings": [],
"errors": [],
"metrics": {"items_processed": 42, "items_new": 5}
}

filename = f"{started.strftime('%Y-%m-%d')}_my-task-id_{started.strftime('%H%M')}.json"
path = Path.home() / "Library/Application Support/SkyRun/health" / filename
path.write_text(json.dumps(heartbeat, indent=2))

For agent-prompt skills (where the runtime is Claude executing instructions), the prompt should explicitly cite this file:

> "Write a heartbeat per memory/reference_heartbeat_schema.md — required fields task_id, status, started_at, completed_at, summary must NEVER be null."

Cross-references