feat(cron): convert heartbeat tasks: entries into independent cron jobs (#113165)

Each legacy heartbeat tasks: entry becomes an editable system-created cron
job (declaration key heartbeat-task:<agentId>:<hash>, per-occurrence
identity for duplicate names) that fires a guarded heartbeat wake carrying
the task prompt plus current monitor scratch context. Task cadence is now
independent of the base heartbeat interval; active-hours, busy-retry,
min-spacing, and flood guards are preserved, deferred payload-carrying
wakes are retained and retried after the spacing floor, and colliding
task/event wakes cannot starve each other.

openclaw doctor --fix migrates existing blocks: async parse/plan, then one
synchronous SQLite transaction that rereads the pinned scratch revision,
upserts job rows, and strips the tasks: block atomically — concurrent
doctors serialize on the database and a losing run aborts untouched.
Orphan fields, invalid intervals, and incomplete entries block migration
of their block with a clear finding instead of silent text loss. The
runtime tasks: parser is deleted; leftover text is ordinary scratch prose.

Nine Codex gpt-5.6-sol xhigh autoreview cycles; final verdict clean.
This commit is contained in:
Peter Steinberger
2026-07-23 16:13:08 -07:00
committed by GitHub
parent b3b9e691bd
commit b23c7bd0f8
45 changed files with 2786 additions and 526 deletions
+2 -4
View File
@@ -57,12 +57,10 @@ and troubleshooting see the main [FAQ](/help/faq).
| Skip reason | Meaning |
| --- | --- |
| `quiet-hours` | Outside the configured active-hours window |
| `empty-heartbeat-file` | `HEARTBEAT.md` exists but only has blank, comment, header, fence, or empty-checklist scaffolding |
| `no-tasks-due` | Task mode is active but no task interval is due yet |
| `empty-heartbeat-file` | Heartbeat monitor scratch exists but only has blank, comment, header, fence, or empty-checklist scaffolding |
| `alerts-disabled` | All heartbeat visibility is off (`showOk`, `showAlerts`, and `useIndicator` all disabled) |
In task mode, due timestamps advance only after a real heartbeat run completes.
Skipped runs do not mark tasks as completed.
Older heartbeat `tasks:` blocks migrate to independently scheduled cron jobs with `openclaw doctor --fix`.
Docs: [Heartbeat](/gateway/heartbeat), [Automation](/automation).
+1 -2
View File
@@ -330,8 +330,7 @@ flowchart TD
- `cron: scheduler disabled; jobs will not run automatically` → cron is disabled.
- `heartbeat skipped` reason `quiet-hours` → outside configured active hours.
- `heartbeat skipped` reason `empty-heartbeat-file` → `HEARTBEAT.md` exists but contains only blank, comment, header, fence, or empty-checklist scaffolding.
- `heartbeat skipped` reason `no-tasks-due` → task mode is active but no task interval is due yet.
- `heartbeat skipped` reason `empty-heartbeat-file` → heartbeat monitor scratch contains only blank, comment, header, fence, or empty-checklist scaffolding.
- `heartbeat skipped` reason `alerts-disabled` → `showOk`, `showAlerts`, and `useIndicator` are all off.
- `requests-in-flight` → main lane busy; heartbeat wake deferred.
- `unknown accountId` → heartbeat delivery target account does not exist.