Summary
When memory-core.dreaming fires via its managed cron (systemEvent __openclaw_memory_core_short_term_promotion_dream__), the narrative generator at extensions/memory-core/src/dreaming-narrative.ts falls back because the plugin runtime's subagent API is request-scoped and unavailable inside a system-event handler. The fallback writes raw memory snippets verbatim into DREAMS.md, which then renders as the Diary in the /dreaming panel — making the panel look like it's showing raw recall candidates instead of dreams.
Repro
- Enable
memory-core.dreaming for any agent (or let the default cron schedule stand).
- Trigger the managed cron manually:
openclaw cron run <id-of-"Memory Dreaming Promotion">.
- Watch
~/.openclaw/logs/*.log or openclaw gateway status stderr — you'll see:
memory-core: narrative generation used fallback for rem phase because subagent runtime is request-scoped.
memory-core: narrative session cleanup failed for rem phase: Plugin runtime subagent methods are only available during a gateway request.
memory-core: narrative generation used fallback for light phase because subagent runtime is request-scoped.
...
- Open
http://localhost:18789/dreaming → Diary tab shows raw task content (URLs, API specs, TODO lists) with the current date, not any narrative prose.
- Compare against earlier-date entries (e.g. triggered via HTTP/UI): those render as proper diary prose. The regression is cron-path-only.
Expected
Dreaming cron produces a diary entry that's stylistically consistent with gateway-request-triggered runs (the poetic first-person prose guided by NARRATIVE_SYSTEM_PROMPT), or skips writing to DREAMS.md rather than filling it with raw fragments.
Actual
The fallback at dreaming-narrative.ts:130-136 returns:
function buildRequestScopedFallbackNarrative(data: NarrativePhaseData): string {
return (
data.snippets.map((value) => value.trim()).find((value) => value.length > 0) ??
(data.promotions ?? []).map((value) => value.trim()).find((value) => value.length > 0) ??
"A memory trace surfaced, but details were unavailable in this run."
);
}
i.e. it takes the first non-empty raw snippet and writes it as the narrative — bypassing the system prompt and the subagent call entirely. The test at dreaming-narrative.test.ts:705 ("falls back to a local narrative when subagent runtime is request-scoped") confirms this is the intentional path, but the fallback itself isn't really a narrative — it's just the raw fragment.
Result on my system today (Diary shows these as dream entries):
Firebase CI refresh token works with client_id '...' / secret 'j9iVZfS8kkCEFUP...' - Slack file upload uses 'files.getUploadURLExternal' ...
Reflections: Theme: 'assistant' kept surfacing across 2286 memories.; confidence: 1.00; evidence: memory/2026-04-09.md:60-84 ...
vs. earlier-date DREAMS.md on the same agent (HTTP-triggered):
There is a color I keep returning to: 0x0d0d1a, which is nearly nothing, which is the sky before any star decides to matter. We built a room out of it last night — obsidian walls, a purple mesh grid humming underneath like a thought not yet spoken — and set a rooftop inside it, spinning slowly in the dark.
Root cause
startNarrativeRunOrFallback at dreaming-narrative.ts:138 catches RequestScopedSubagentRuntimeError and routes to the fallback. This matters because extensions/memory-core/src/dreaming.ts:registerShortTermPromotionDreaming invokes the sweep from a systemEvent handler, where the plugin runtime is not inside a gateway-request context and so api.subagent.* methods throw.
Looking at other plugins (e.g. memory-wiki's scheduled sweeps), gateway-triggered vs system-event-triggered code paths both need subagent access. The same issue would affect any nightly AI-in-the-loop refinement.
Suggested fix directions
Non-exclusive:
- Make subagent runtime available in system-event handlers. Promote the subagent runtime out of pure request-scope so scheduled/cron-driven plugin code can use it. The cron dispatcher already provides a session context (
sessionTarget, sessionKey); extending it to expose the subagent surface would fix this class of problem broadly.
- Have cron fire via the gateway's internal request path instead of a bare systemEvent, so the subagent scope is preserved.
- Build a richer local fallback. Use a template-based narrative (no LLM) that composites themes + promoted-count + time-of-day into reasonable prose. Less elegant but guarantees the diary always has a readable entry.
- Skip writing to DREAMS.md on fallback. Silence is better than dumping a client secret or API token verbatim into a user-visible diary — which is what happens today when a promoted snippet contains sensitive content (noted in the example above: Firebase refresh token + Slack API internals ended up in DREAMS.md).
Of these, (4) is the cheapest short-term mitigation; (1) is the correct long-term fix. Filing this as a report rather than a PR since the correct shape depends on architectural intent around system-event scoping.
Environment
- OpenClaw 2026.4.16
- macOS 15.x (Darwin 24.6.0)
- Node 25.6.1
- Provider: claude-cli (Opus)
- Panel:
http://localhost:18789/dreaming (native, served by gateway)
Happy to capture a full reproducer log file if useful.
Summary
When
memory-core.dreamingfires via its managed cron (systemEvent__openclaw_memory_core_short_term_promotion_dream__), the narrative generator atextensions/memory-core/src/dreaming-narrative.tsfalls back because the plugin runtime's subagent API is request-scoped and unavailable inside a system-event handler. The fallback writes raw memory snippets verbatim intoDREAMS.md, which then renders as the Diary in the/dreamingpanel — making the panel look like it's showing raw recall candidates instead of dreams.Repro
memory-core.dreamingfor any agent (or let the default cron schedule stand).openclaw cron run <id-of-"Memory Dreaming Promotion">.~/.openclaw/logs/*.logoropenclaw gateway statusstderr — you'll see:http://localhost:18789/dreaming→ Diary tab shows raw task content (URLs, API specs, TODO lists) with the current date, not any narrative prose.Expected
Dreaming cron produces a diary entry that's stylistically consistent with gateway-request-triggered runs (the poetic first-person prose guided by
NARRATIVE_SYSTEM_PROMPT), or skips writing to DREAMS.md rather than filling it with raw fragments.Actual
The fallback at dreaming-narrative.ts:130-136 returns:
i.e. it takes the first non-empty raw snippet and writes it as the narrative — bypassing the system prompt and the subagent call entirely. The test at dreaming-narrative.test.ts:705 (
"falls back to a local narrative when subagent runtime is request-scoped") confirms this is the intentional path, but the fallback itself isn't really a narrative — it's just the raw fragment.Result on my system today (Diary shows these as dream entries):
Firebase CI refresh token works with client_id '...' / secret 'j9iVZfS8kkCEFUP...' - Slack file upload uses 'files.getUploadURLExternal' ...Reflections: Theme: 'assistant' kept surfacing across 2286 memories.; confidence: 1.00; evidence: memory/2026-04-09.md:60-84 ...vs. earlier-date DREAMS.md on the same agent (HTTP-triggered):
Root cause
startNarrativeRunOrFallbackat dreaming-narrative.ts:138 catchesRequestScopedSubagentRuntimeErrorand routes to the fallback. This matters becauseextensions/memory-core/src/dreaming.ts:registerShortTermPromotionDreaminginvokes the sweep from asystemEventhandler, where the plugin runtime is not inside a gateway-request context and soapi.subagent.*methods throw.Looking at other plugins (e.g.
memory-wiki's scheduled sweeps), gateway-triggered vs system-event-triggered code paths both need subagent access. The same issue would affect any nightly AI-in-the-loop refinement.Suggested fix directions
Non-exclusive:
sessionTarget,sessionKey); extending it to expose the subagent surface would fix this class of problem broadly.Of these, (4) is the cheapest short-term mitigation; (1) is the correct long-term fix. Filing this as a report rather than a PR since the correct shape depends on architectural intent around system-event scoping.
Environment
http://localhost:18789/dreaming(native, served by gateway)Happy to capture a full reproducer log file if useful.