Dream Cycle
Dream Cycle is the bundled extension that runs background reflection while an agent is idle. When an agent goes quiet (or a schedule window opens), the cycle runs an ordered series of sleep stages that review recent task outcomes, optionally consult a contemplation model, adapt per-agent success weights, and record repeated-work candidates for the learning loop. Everything is off until you turn it on. The cycle never talks to a model endpoint, the filesystem, or the network directly - each capability is behind a guarded facade (see Safety guardrails).Enable the engine
The plugin is disabled by default, and its engine has a second, inner switch:enabled activates the plugin; the inner config.enabled activates the engine. With the inner flag unset or false the plugin registers nothing: no passes, no triggers, no gateway methods.
This change takes effect after a gateway restart (Linux: systemctl --user restart openclaw-gateway; macOS: wednesdayai gateway restart --deep).
Sleep stages
Three stages ship by default:
A stage runs only when its cadence has elapsed since its last run; otherwise the cycle skips it.
maxPassRuns caps how many passes one stage run may execute.
Supplying stages replaces the default list outright, so list every stage you want:
order and ignores the rest. A stage entry without a name is dropped; duplicate names keep only the first. Missing fields fall back to order by position, cadenceHours: 24, enabled: true, and maxPassRuns: 10.
Contemplation backend
Contemplation has no default model. Bothprovider and model must be set, or the contemplation pass returns unconfigured and emits a dream.contemplation_unconfigured diagnostic once per cycle. Nothing else in the cycle is blocked by this.
Inference runs through the analysis runtime at the provider layer, so the configured provider and model use the same credentials, routing, and accounting as any other analysis run.
Triggers
The cycle is started by core, not by the plugin. Two top-leveltasks keys control when - both are off/empty by default, and both require the task pipeline to be running (tasks.enabled: true, the default).
Idle trigger
Core watches for agents that have gone quiet and emits anagent_idle event, which the plugin turns into queued task work:
An agent counts as idle only when its newest run has not been updated inside the threshold and the command queues are quiet. One idle-triggered cycle is enqueued per agent per UTC day - a second idle stretch the same day collides on the same work id and is deduplicated.
Schedule windows
Pin cycles to fixed windows instead of, or alongside, idle watching:- Local time range
HH:MM-HH:MM(no space). A range whose close is at or before its open crosses midnight, so22:00-02:00is valid and covers four hours. - Cron expression (always contains a space), evaluated with croner.
0 3 * * 0fires at 03:00 every Sunday.
Setting
tasks.idle.enabled or a non-empty tasks.schedule.windows starts the monitor only when the task pipeline is running. If durable run storage is unavailable, the monitor is not started and a task.idle_monitor_disabled diagnostic is emitted rather than failing silently.Safety guardrails
Passes never touch the filesystem, the network, or a model directly - every capability is a narrow facade inside the ordinary task governance rails:- Writes go through a file facade scoped to a private
dream-cycledirectory under the state directory (owner-only permissions). Absolute paths, parent-relative segments, and symlink escapes are rejected before any write and emit a boundary-violation diagnostic. - Fetches go through a guarded fetch facade applying the strict SSRF policy (private and loopback destinations stay blocked). Responses are size-limited, defaulting to 5 MiB (
fetch.maxBytesoverrides); an oversized body is rejected, not buffered. - Inference stays at the provider layer via the analysis runtime - no endpoint, key, or transport detail lives in the plugin.
- Rate caps are enforced before the call:
contemplation.maxCallsPerCyclebounds calls per cycle, and each stage is separately bounded bymaxPassRuns. - Task governance applies unchanged - every pass run is a task run with budgets, concurrency limits, retry policy, and preemption by live user turns.
Observability
Task runs, including dream passes, are visible from the CLI:
Diagnostic events cover the lifecycle:
dream.cycle_started, dream.cycle_completed, dream.stage_skipped, dream.pass_completed, dream.contemplation_unconfigured, dream.contemplation_skipped, dream.contemplation_failed, dream.rate_capped, dream.jsonl_parse_skipped, dream.crystallisation_candidate, dream.fetch_failed, task.boundary_violation, and task.idle_monitor_disabled. With diagnostics-otel enabled these export as openclaw.dream.* / openclaw.task.* spans; failed contemplation and fetch set OTel error status.
Where dreams stop
The dream cycle stops at candidates. It records that a piece of work has recurred and writes a candidate record - it never writesSKILL.md, queues skill proposals, or touches the skills directory. Turning a candidate into a proposal is owned exclusively by Learning Core, so the review and approval path for new skills stays in one place.
Troubleshooting
No cycles ever run. Check all three switches: the outer pluginenabled, the inner config.enabled, and a trigger (tasks.idle.enabled or non-empty tasks.schedule.windows) with tasks.enabled: true. Confirm the monitor was not disabled by missing durable run storage (task.idle_monitor_disabled).
dream.contemplation_unconfigured fires every cycle. Both contemplation.provider and contemplation.model must be set. The rest of the cycle is unaffected.
dream.rate_capped in logs. The per-cycle contemplation cap was hit. Raise contemplation.maxCallsPerCycle if the cap is too tight - it exists to bound spend per cycle.
Cycles fire less often than the cadence suggests. A stage runs only when its cadence has elapsed and a cycle was triggered. With no idle or schedule trigger configured, no cycle starts regardless of cadence.
Related
- Learning Core - owns the candidate-to-proposal path dreams stop short of
- Learning - what your users see
- Configuration - top-level config file basics