Skip to content

Daily session reset silently discards context without memory flush or compaction #56072

@jlian

Description

@jlian

Problem

The daily session reset (default: 4 AM local time) archives the session transcript without triggering any memory preservation mechanism. Context from the previous session is silently lost unless the agent happened to write it to memory files in real-time.

This is especially impactful for users on large context models (e.g., Claude Opus 4.6 1M) where compaction rarely triggers. Sessions grow all day, then the daily reset at 4 AM silently archives everything without flushing.

What happens today

When a session is detected as stale (first message after the daily reset boundary):

  1. New session ID created
  2. Old transcript renamed to .jsonl.reset.<timestamp>
  3. session_end fires via the plugin hook system, but the bundled session-memory hook runs on the internal hook system (a completely separate dispatch path). Even if session-memory wanted to listen for session_end, it cannot — managed/workspace hooks can only register for internal hook events (command:new, command:reset, etc.), not plugin hook events (session_end, session_start). These two systems do not bridge.
  4. Agent runs with a fresh, empty session

What does NOT happen:

  • No pre-compaction memory flush
  • No session-memory internal hook (only fires on explicit /new or /reset commands)
  • No compaction summary
  • No user notification

Proposal

The daily session reset should not have to rely on a hook to preserve context. It should integrate directly with the existing compaction memory flush mechanism (agents.defaults.compaction.memoryFlush).

Suggested design

Expose a config on the session reset that lets users choose the reset behavior:

{
  session: {
    reset: {
      mode: "daily",
      atHour: 4,
      // New: what to do before archiving the transcript
      onReset: "flush"   // "flush" | "archive-only"
      // "flush" = run the same memory flush as compaction before archiving
      // "archive-only" = current behavior (just rename and move on)
    }
  }
}

When onReset: "flush" is configured (which should be the default):

  • Before archiving the old transcript, run the same pre-compaction memory flush that agents.defaults.compaction.memoryFlush defines
  • Share the same config: softThresholdTokens, reserveTokensFloor, flush prompt, etc.
  • The flush runs as a silent agentic turn (same as the existing pre-compaction ping), giving the agent a chance to write durable notes before the session is archived

This means:

  • No new hook dependency — the flush is built into the reset mechanism itself
  • Consistent behavior — same memory flush logic whether context is lost via compaction or daily reset
  • Configurable — users who want the current "just archive" behavior can set onReset: "archive-only"

Additional improvements

  1. Add disabled / off mode: Currently session.reset.mode only supports "daily" and "idle". Users who manage context via compaction + memory files should be able to disable reset entirely.

  2. Have session-memory hook also subscribe to session_end: As a complementary improvement (not the primary fix), the bundled session-memory hook currently only registers for command:new and command:reset (internal hook events). The session_end event fires during daily reset via the plugin hook system, but nothing listens. These are two separate hook systems (internal vs plugin), so bridging them would also help third-party hooks.

Code references

  • Daily reset detection: src/auto-reply/reply/session.ts:344-375
  • Transcript archive (no flush): src/auto-reply/reply/session.ts:572-579
  • session_end fires but nothing listens: src/auto-reply/reply/session.ts:605-613
  • session-memory hook only handles commands: src/hooks/bundled/session-memory/handler.ts:55-56
  • Pre-compaction memory flush config: agents.defaults.compaction.memoryFlush
  • Pre-compaction memory flush logic: src/auto-reply/reply/agent-runner-memory.ts:265-451
  • Reset mode schema (no disabled option): src/config/zod-schema.session.ts:18
  • Internal vs plugin hook systems are separate: internal hooks use triggerInternalHook() (src/hooks/internal-hooks.ts), plugin hooks use hookRunner.runSessionEnd() (src/plugins/hooks.ts)

Environment

  • OpenClaw v2026.3.24
  • Model: Claude Opus 4.6 (1M context) — compaction rarely triggers
  • Daily reset at default 4 AM

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions