On this page
On this page
Automation
Heartbeat migration
A scheduled check belongs to an automation job. Its schedule, prompt, scratch, model, session, and delivery settings live with that job. Background-command, task, hook, and restart follow-ups use normal session execution; they do not require a periodic monitor or an enabled cron scheduler.
Upgrade an existing monitor
Use the upgraded CLI to run Doctor:
Then inspect all jobs, including disabled ones:
Doctor converts each existing monitor into an ordinary editable job. It keeps
its identity, run history, scratch bytes and revisions (including deletion
tombstones), disabled or auto-disabled state, scheduling anchor, and pending
scheduling slots. It also converts legacy
heartbeat-task:* jobs and imports supported HEARTBEAT.md content and task
blocks before retiring their old inputs.
Doctor removes legacy agents.defaults.heartbeat and
agents.entries.*.heartbeat settings and special channel heartbeat visibility
configuration only after their canonical jobs have been persisted and verified.
If conversion is blocked, the diagnostic names the
remaining input; resolve that problem and rerun Doctor rather than deleting the
configuration or scratch manually.
After migration, edit the ordinary job. Repeated Doctor runs, config reloads, and Gateway restarts do not overwrite your job edits or recreate a deleted monitor. A one-time provisioning receipt survives job deletion, so deleting a default monitor is a lasting choice.
Imported HEARTBEAT.md bytes are archived under the state directory at
backups/heartbeat-migration/ before the original file is removed. If the
workspace and state directory are on different filesystems, Doctor also keeps
the original in a private HEARTBEAT.md.doctor-archived.* directory beside its
former location. Writes through an already-open file descriptor remain
recoverable there. A file recreated after completed migration is retained and
reported by path without reading its contents or following a symlink, even when
it could not safely be imported. It does not block Doctor or update admission
and does not overwrite the operator-owned job.
If existing scratch differs from HEARTBEAT.md and was not imported from that
file, Doctor preserves the scratch and original file, prints a notice, and
completes the conversion. Explicitly unset scratch stays unset. The automation
uses its existing scratch; review the retained file before copying any wanted
instructions into the job. Repeating Doctor keeps both originals and succeeds.
Doctor prints this one-time note when migration completes:
Migrated heartbeats now use standard Automations delivery. Heartbeat-specific duplicate suppression and no-route skipping were removed: repeated updates can be delivered, and a missing route no longer skips the run before execution. Delivery failures follow ordinary automation handling. Review the migrated jobs' delivery settings if you relied on either behavior.
When an alert includes an edge HEARTBEAT_OK acknowledgement, delivery removes
the token without flattening the alert's line breaks or indentation. Paragraphs,
lists, and fenced code blocks retain their formatting.
Migrated model overrides follow the agent's existing model policy. If a heartbeat
model is outside that policy, Doctor drops the job's model override and reports
the affected agent, job, dropped model, and configured default. The job then uses
normal automation model selection. Doctor does not expand the allowlist. To use
a different model, choose an allowed model for the job or add the desired model
to the agent's modelPolicy.allow before selecting it. Allowed overrides are
preserved.
Heartbeat migration adds no per-agent schema change. The current agent schema is
31; its old heartbeat_outcomes table
is retained for migration. Meaningful pending results that still belong to the
current session move into ordinary session context without sending a notification.
Facts from before the current session or from an expired session are not promoted
into a new conversation.
Doctor supports the heartbeat configuration and task shapes shipped from July 2026 onward. Older shapes are outside this migration. If an input cannot be converted faithfully, Doctor retains it and reports the problem instead of silently discarding its scheduling or delivery settings.
A bare tasks: line followed by ordinary checklist bullets stays unchanged in
the monitor's scratch, including scratch imported by an earlier Doctor. It does
not create scheduled jobs or block retirement. Incomplete task declarations still
require repair; update admission and Doctor use the same task validation, and
Doctor leaves an incomplete HEARTBEAT.md in place before importing it.
First setup
Explicit setup provisions one enabled Proactive check job for the ambient owner agent. It runs every 30 minutes unless the provider supplies a different initial cadence, uses the agent's main conversation, waits for idle execution, and delivers to a resolved owner DM. The job skips an explicitly empty scratch checklist; missing scratch still runs. Edit its schedule, prompt, model, or delivery like any other automation.
Provisioning happens once. Gateway startup and config reload do not create the job, and deleting it remains a lasting choice. Other agents need their own explicitly created jobs.
Configure scheduled checks
Each former heartbeat monitor remains associated with its agent, not every chat session. You can change, disable, or remove it like any other automation:
A shared-context check uses a named session target. An isolated check starts with
a fresh run context. current is different: it runs detached with bounded
context from the conversation captured when the job was created. See
Execution styles.
Optional job policies preserve the useful monitoring behavior:
activeHoursrestricts execution to a timezone-aware window.idleOnlygives foreground work priority through normal scheduler and session admission.delivery.target: "owner"resolves an explicitly identified owner DM. It does not follow a group conversation aschannel: "last"can.delivery.directPolicypermits or blocks DM delivery.payload.includeReasoningcontrols whether an ordinary job includes available model reasoning in delivery.payload.skipIfScratchEmptyskips a check with explicitly empty scratch; missing scratch is different from an empty checklist.
These are per-job settings, not a replacement global heartbeat configuration. See Automations for the canonical job reference.
Monitor scratch
Scratch is private context attached to any automation job, stored in the shared state database. Keep it short and task-specific; a job's present scratch is included in its bounded run context.
Do not put secrets in scratch: private storage does not keep it out of the model prompt. See Job scratch and quiet results for empty-checklist behavior and revision conflicts.
Scratch writes are revision-guarded. Use --expected-revision <n> to pin a known
revision. During an automation run, the agent can read or update its own scratch
through the automations tool without gaining access to other jobs.
Scratch is not a scheduler. Put recurring work in separate automation jobs,
not a tasks: block. Doctor imports supported legacy blocks once; runtime does
not parse them as schedules or read HEARTBEAT.md.
Quiet results and run history
Return NO_REPLY when a check has no visible update. During an automation run,
use the self-scoped record_result action to record a meaningful outcome without
sending a message. no_change suppresses automatic delivery; execution errors
remain failures. See Job scratch and quiet results.
Scheduled checks can finish silently in a saved internal session too. A completed
check that returns NO_REPLY does not need an extra final-answer model request.
Immediate follow-ups
A background process completing, a task becoming blocked, or a restart finishing uses ordinary session execution. It does not require an enabled recurring monitor. Session admission keeps the follow-up with its original conversation and current authority. An exec completion waits behind the turn that started it, allowing that turn to finish and acknowledge its automation reminders without being superseded by its own command. For a manual event, request immediate processing explicitly:
The legacy set-heartbeats control enables or disables the corresponding
migrated/default jobs, never all automations. last-heartbeat keeps its
compatibility event response. An untargeted next-heartbeat request attaches to
an eligible scheduled automation for the session; without one, it reports the
problem instead of waiting for an unspecified future user message. Prefer
explicit automation schedules for delayed work.
Transport keepalives, presence checks, and other infrastructure health signals are separate from agent monitoring and keep their existing configuration.
Related
- Automation — choose scheduled jobs or event-driven work
- Automations — job configuration, delivery, and history
- Automations CLI — inspect and edit jobs and scratch
- System CLI — manual events and compatibility controls
- Database schemas — upgrade and rollback safety