Skip to content

[Feature]: Session trigger metadata + exclude cron-triggered sessions from memory-core Dreaming ingestion by default #67272

Description

@hyamie

Summary

Add trigger metadata to agent sessions (values: user, cron, subagent, hook) and exclude trigger: cron sessions from memory-core Dreaming ingestion by default, with opt-in override per cron job.

Problem to solve

memory-core's Dreaming pipeline ingests cron-triggered sessions (heartbeat pings, scheduled automation, email-watch jobs) into __dreaming_sessions__ identically to user-initiated conversations. On any deployment that uses openclaw cron non-trivially, this starves the REM and deep-promotion phases of real signal.

Concrete example from a fresh memory-core install, day 1, single-agent personal Donnie on Discord (OpenClaw 2026.4.14):

REM themes (confidence 1.00):
  - heartbeat-ok    60 memories
  - user            45
  - assistant       44
  - heartbeat.md    30
  - home/hyamie     30
  - openclaw/workspace/heartbeat.md  30
  - read            30

Deep phase: zero promotions. "No strong candidate truths surfaced."

The corpus file memory/.dreams/session-corpus/2026-04-13.txt contains 60 lines of:

User: Read HEARTBEAT.md if it exists [...] reply HEARTBEAT_OK.
Assistant: HEARTBEAT_OK

Actual signal (family context, golf communications, project work) scores identically at confidence 0.58 per line, and gets buried. The deep phase's promotion gates (minScore 0.8 / minRecallCount 3 / minUniqueQueries 3) can never fire on real content because it's outweighed by cron repetition.

This is closely related to #63921 (transcript wrapper noise), but that issue's proposed fixes (stopword filter, wrapper stripping, role-token normalization) operate at the token level and don't address cron-content pollution. Heartbeat content is valid English prose that repeats — no stopword list can remove it without also removing legitimate user content.

Related: #63921 #59095 #29442.

Proposed solution

1. Session-level trigger metadata (new)

Every session gets a trigger field set at creation, written to session state and available to plugins:

trigger value When set
user Default — DM, channel mention, direct agent invocation
cron Originated from openclaw cron scheduled job
subagent Spawned by parent agent via subagent delegation
hook Gateway lifecycle hook invocation

The [cron:<id> <name>] preamble already emitted by openclaw cron is sufficient signal — formalize it as session metadata at session open time rather than as in-band text.

2. memory-core Dreaming opt-out for non-user triggers (new default)

memory-core config gains a dreaming.ingest.triggers array. Default:

{
  "memory-core": {
    "dreaming": {
      "ingest": {
        "triggers": ["user"]
      }
    }
  }
}

Non-matching sessions are skipped during __dreaming_sessions__ enumeration. Operators who want a cron workload reflected on explicitly can set ["user", "cron"].

3. Per-cron-job override (fine-grained)

openclaw cron job definition gains dreamingIngest: boolean (default false if not set, same outcome as trigger filter). Lets someone whitelist a specific high-signal cron (e.g. a daily journaling prompt) without opening the floodgates.

4. Backward compatibility

Existing sessions without a trigger field default to user — matches current behavior, zero regression for users who don't run cron jobs.

Alternatives considered

  • Token/phrase blocklist only (what [Bug]: Dreaming/REM surfaces raw session-corpus metadata (untrusted, user, assistant) instead of meaningful reflections #63921 proposes): insufficient for cron content because heartbeat messages are valid English, not structural boilerplate. Scales poorly — every new cron job needs manual phrase additions.

  • Entropy/novelty gating (SimpleMem arxiv 2601.02553, entity novelty + semantic divergence threshold τ=0.35): principled but substantially more implementation work, requires embedding every exchange pre-ingestion, and gives fuzzy results when the right answer is a hard "skip." Good candidate for a Phase 2 layer on top of trigger filtering.

  • Min-token exchange gate: simple, catches heartbeat (4-6 tokens) but not longer cron runs like email-watch playbook invocations. Useful belt-and-suspenders but not sufficient alone.

  • Per-session importance weighting pre-TF-IDF (LangMem pattern — multiply phrase frequencies by a session weight before REM theme extraction): equivalent outcome to trigger filtering but more invasive change to the theme extractor. Trigger-based ingestion gating is simpler and affects fewer components.

  • Do nothing, rely on volume: wait for real user conversation to eventually outweigh cron noise. Doesn't work — cron runs on a fixed cadence, so the ratio stays roughly constant as real usage grows.

Impact

Affected: Anyone using openclaw cron with memory-core Dreaming enabled. As memory-core becomes the default memory plugin and cron gets used for automation (heartbeats, scheduled email checks, daily journaling prompts, periodic agent-driven tasks), this affects a growing share of users.

Severity: High for users who rely on Dreaming-promoted long-term memory. On my setup, deep phase produced zero promotions in week 1 despite real conversational content being present, because cron sessions dominated the corpus. Effectively breaks Dreaming's value proposition on any non-trivial cron deployment.

Frequency: Every Dreaming run. Daily for most users (default cron 0 3 * * *).

Consequence: Promoted "lasting truths" become noise or nothing. Operators lose trust in memory-core's consolidation layer and either disable Dreaming, disable cron automation, or manually prune session corpus files — all of which defeat the point.

Evidence/examples

Prior art:

Local evidence files (available on request):

  • memory/.dreams/session-corpus/2026-04-{13,14,15}.txt — 89 lines total, 60+ from heartbeat cron
  • memory/.dreams/phase-signals.json — shows every heartbeat line counted equally with every real-conversation line
  • memory/2026-04-15.md — REM output above, Axis B themes dominating

Additional information

Willing to contribute a draft PR if maintainers confirm direction. Two candidate scopes:

  • Minimal (recommended first): add trigger metadata field to session creation, add dreaming.ingest.triggers config to memory-core, filter at ingestion.
  • Full: also add dreamingIngest: bool to openclaw cron job schema and admin UI.

Cross-link: #63921 covers the orthogonal Axis A (transcript wrapper noise). Adding a comment there with this setup's repro data to confirm regression persists in 2026.4.14.

Happy to also seed a phrase blocklist for the cron preambles (HEARTBEAT_OK, HEARTBEAT.md, NO_REPLY, [cron:...]) as a lower-cost Phase 0 fix while trigger metadata lands — these are safe to stopword because they're literal protocol tokens, not semantic content.

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