Skip to content

Heartbeat isolated mode: cadence stalls, 'heartbeat last' mislabels exec-events, lightContext stays heavy, heartbeat-state writer appears missing #65161

Description

@A1fred-AI

Summary

OpenClaw 2026.4.10 appears to have multiple heartbeat-related regressions in isolated mode:

  1. scheduled heartbeat cadence does not continue after an initial post-reload pulse
  2. openclaw system heartbeat last reports in-memory heartbeat events that can be triggered by exec-event, so it can mislabel async exec completions as heartbeats
  3. lightContext: true is wired through isolated cron/heartbeat paths but does not produce light behavior in practice
  4. memory/heartbeat-state.json does not appear to be written by the shipped runtime at all

These combine to make isolated cheap heartbeat mode appear enabled while leaving no trustworthy receipt trail that cadence, cheapness, or state writing are actually working.

Environment

  • OpenClaw: 2026.4.10
  • Install: Homebrew / /opt/homebrew/lib/node_modules/openclaw
  • Host: macOS arm64
  • Observed locally in a live install with heartbeat config on disk:
    • heartbeat.session: "heartbeat"
    • heartbeat.isolatedSession: true
    • heartbeat.lightContext: true
    • heartbeat.target: "none"
    • agents.defaults.embeddedPi.executionContract: "strict-agentic"

Verified behavior

1) Scheduled heartbeat cadence appears broken in isolated mode

After config reload, gateway log shows one heartbeat pulse but no follow-up 15-minute cadence ticks in the next windows.

Observed log lines in ~/.openclaw/logs/gateway.log:

2026-04-11T21:50:27.905-05:00 [reload] config change detected; evaluating reload (agents.defaults.heartbeat.session, agents.defaults.heartbeat.isolatedSession, agents.defaults.embeddedPi)
2026-04-11T21:50:27.951-05:00 [reload] config hot reload applied (agents.defaults.heartbeat.session, agents.defaults.heartbeat.isolatedSession)
2026-04-11T21:50:38.627-05:00 [heartbeat] started
2026-04-11T22:11:27.640-05:00 [gateway] cron: job created
2026-04-11T22:59:42.804-05:00 [gateway] cron: job created

No 22:05, 22:20, 22:35, or 22:50 heartbeat start appears in that window.

Expected:

  • once enabled, heartbeat should continue on its configured interval and leave explicit start/skip/fail evidence for each due window

Actual:

  • only the initial post-reload pulse appears
  • no later cadence evidence is emitted

2) openclaw system heartbeat last is reading a misleading in-memory event surface

I traced this in the shipped dist/ build:

  • server.impl-95X_lxU6.js exposes last-heartbeat by returning getLastHeartbeatEvent()
  • heartbeat-visibility-vJxEaSRp.js stores a single in-memory singleton event
  • heartbeat-wake-D_DqW-eD.js explicitly recognizes exec-event as a heartbeat wake reason

Relevant code path:

  • server.impl-95X_lxU6.js
    • "last-heartbeat": ({ respond }) => { respond(true, getLastHeartbeatEvent(), void 0); }
  • heartbeat-visibility-vJxEaSRp.js
    • singleton lastHeartbeat
  • heartbeat-wake-D_DqW-eD.js
    • resolveHeartbeatReasonKind(reason) includes exec-event

In practice, openclaw system heartbeat last returned JSON like:

{
  "ts": 1775963228786,
  "status": "ok-empty",
  "reason": "exec-event",
  "durationMs": 6445,
  "silent": true,
  "indicatorType": "ok"
}

That was then easy to misread as a real scheduled heartbeat tick, even though it was not trustworthy evidence of cadence.

Expected:

  • system heartbeat last should report durable heartbeat receipts for actual scheduled/manual heartbeat runs, clearly separated from generic exec-completion-triggered wakeups

Actual:

  • the command returns the last in-memory heartbeat event object, which can carry reason: "exec-event"

3) lightContext: true is wired but not behaviorally light

I verified that lightContext is threaded through both cron and heartbeat code paths:

  • cron normalization preserves payload.lightContext
  • cron execution maps it to bootstrapContextMode: "lightweight"
  • heartbeat runner also maps heartbeat.lightContext === true to bootstrapContextMode: "lightweight"

Relevant files:

  • openclaw-tools-Co0S582U.js
  • server.impl-95X_lxU6.js
  • heartbeat-runner-CUN7Cvbo.js

However, actual isolated verification runs configured with lightContext: true were still heavy:

Verification cron run (~/.openclaw/cron/runs/1e67e3f4-f3d7-48e8-9ed4-f7926a8ea9ec.jsonl):

  • input_tokens: 37375
  • output_tokens: 2535
  • total_tokens: 31308
  • durationMs: 87775

A tiny ping / Pong. session near the same window also showed unexpectedly high usage inside its transcript:

  • input: 12280
  • output: 39
  • cacheRead: 2560
  • totalTokens: 14879
  • cost about $0.0319

So while the flag is passed through, the observed runtime behavior is not remotely “cheap”.

Expected:

  • lightContext: true on isolated cron/heartbeat paths should materially reduce bootstrap/context cost

Actual:

  • lightweight mode appears wired but not effective enough to support cheap watchdog use cases

4) memory/heartbeat-state.json appears unwired in the shipped runtime

The workspace file remained stale during multiple heartbeat-adjacent tests:

  • memory/heartbeat-state.json mtime stayed at 2026-04-11 12:21:42

I also searched the shipped dist/ build for:

  • heartbeat-state.json
  • lastHeartbeatAt

and found no runtime references.

Expected:

  • runtime should write/update a durable heartbeat state file if that file is part of the intended heartbeat workflow

Actual:

  • I could not find any shipped runtime reference that writes memory/heartbeat-state.json
  • this suggests the writer path may be absent from 2026.4.10, not merely failing at runtime

Impact

  • cheap isolated heartbeat mode cannot currently be trusted as working
  • cadence may silently stop after reload/startup
  • the verification CLI can mislead operators by surfacing exec-event wake objects as “last heartbeat”
  • the state file contract appears unimplemented in the shipped build
  • lightContext may give false confidence that cron/heartbeat probes are cheap when they are not

Suggested fixes

  1. Add a durable heartbeat receipt record for every actual heartbeat run with:
    • trigger reason
    • sessionKey
    • session id
    • isolated true/false
    • start/end timestamps
    • model
    • token usage
    • final outcome
  2. Make openclaw system heartbeat last read that durable receipt surface, not a generic in-memory singleton event
  3. Separate exec-event wakeups from true scheduled heartbeat receipts in the CLI/UI
  4. Emit explicit scheduler decision logs for each due window:
    • started / skipped / suppressed / failed, with reason
  5. Audit why bootstrapContextMode: "lightweight" still produces large token loads in isolated cron runs
  6. Either wire memory/heartbeat-state.json in runtime or remove/document the expectation if it is not meant to be runtime-owned

Acceptance criteria

  • after enabling isolated heartbeat, at least two consecutive due windows produce explicit start/skip/fail evidence in logs or receipts
  • openclaw system heartbeat last cannot report an exec-event as the canonical “last heartbeat” result
  • isolated cron/heartbeat runs with lightContext: true show materially reduced input/bootstrap tokens versus current behavior
  • memory/heartbeat-state.json is either written by runtime on real heartbeat runs or officially removed from the expected workflow/docs

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:needs-live-reproClawSweeper needs live local, crabbox, or manual validation to confirm this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🐚 platinum hermitGood issue quality with a plausible reproduction path needing some confirmation.staleMarked as stale due to inactivity

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions