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):
- New session ID created
- Old transcript renamed to
.jsonl.reset.<timestamp>
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.
- 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:
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
-
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.
-
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
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):
.jsonl.reset.<timestamp>session_endfires via the plugin hook system, but the bundledsession-memoryhook runs on the internal hook system (a completely separate dispatch path). Even ifsession-memorywanted to listen forsession_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.What does NOT happen:
session-memoryinternal hook (only fires on explicit/newor/resetcommands)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):agents.defaults.compaction.memoryFlushdefinessoftThresholdTokens,reserveTokensFloor, flush prompt, etc.This means:
onReset: "archive-only"Additional improvements
Add
disabled/offmode: Currentlysession.reset.modeonly supports"daily"and"idle". Users who manage context via compaction + memory files should be able to disable reset entirely.Have
session-memoryhook also subscribe tosession_end: As a complementary improvement (not the primary fix), the bundledsession-memoryhook currently only registers forcommand:newandcommand:reset(internal hook events). Thesession_endevent 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
src/auto-reply/reply/session.ts:344-375src/auto-reply/reply/session.ts:572-579session_endfires but nothing listens:src/auto-reply/reply/session.ts:605-613session-memoryhook only handles commands:src/hooks/bundled/session-memory/handler.ts:55-56agents.defaults.compaction.memoryFlushsrc/auto-reply/reply/agent-runner-memory.ts:265-451src/config/zod-schema.session.ts:18triggerInternalHook()(src/hooks/internal-hooks.ts), plugin hooks usehookRunner.runSessionEnd()(src/plugins/hooks.ts)Environment