Skip to content

[Bug]: Dreaming cron skipped by heartbeat activeHours (cannot run outside active window) #67397

Description

@MSCHKY

Version

2026.4.12 (1c0672b)

Summary

Dreaming cron is gated by agents.defaults.heartbeat.activeHours. If the configured dreaming.frequency falls outside that window (e.g. common case: nightly dreaming at 03:00 while activeHours = 08:30–22:00), every run is skipped with reason=quiet-hours and no dream runs ever complete.

This contradicts the documentation in docs/concepts/dreaming.md, which uses "0 3 * * *" as the default example — implying dreaming is intended to run overnight.

Reproduction

{
  "agents": {
    "defaults": {
      "heartbeat": {
        "every": "4h",
        "activeHours": { "start": "08:30", "end": "22:00", "timezone": "Europe/Berlin" }
      }
    }
  },
  "plugins": {
    "entries": {
      "memory-core": {
        "enabled": true,
        "config": {
          "dreaming": { "enabled": true, "frequency": "0 3 * * *" }
        }
      }
    }
  }
}

Expected

Dreaming cron fires at 03:00 regardless of heartbeat.activeHours, because dreaming is a background maintenance task, not a user-facing heartbeat.

Actual

  • openclaw cron list --json shows:
    name:              Memory Dreaming Promotion
    schedule.expr:     0 3 * * *
    enabled:           true
    lastRunStatus:     skipped
    lastError:         quiet-hours
    consecutiveErrors: 0
    
  • No dream runs ever complete. Dreaming artifacts: diary absent · 0 corpus files · ingestion state absent for all agents.
  • Code path: dist/heartbeat-runner-*.js:553: reason: \"quiet-hours\" — dreaming cron executions flow through the shared heartbeat-runner which applies the activeHours check unconditionally.
  • Secondary bug: on skipped, state.lastRunAtMs is not updated, so the state appears frozen at the first skipped run forever. Makes it hard to tell from the CLI that the cron is firing at all.

Workaround (applied)

Move dreaming.frequency to a time inside activeHours (e.g. 31 8 * * * — first tick after 08:30). Semantically awkward ("dreaming at breakfast") but works.

Suggested fix

Dreaming cron should bypass heartbeat.activeHours — it's not a user-interaction signal. Either:

  1. Skip the activeHours check for systemEvent cron payloads flagged as managed/background.
  2. Give memory-core.dreaming its own activeHours / quietHours config (defaulting to 24/7) that is independent of heartbeat.activeHours.

Possibly related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions