OpenClaw Session Management: What Lives in a Conversation and Where It Is Stored
Read from search, close with the playbook
If this post helped, here is the fastest path into the full operator setup.
Search posts do the first job. The preview, homepage, and full playbook show how the pieces fit together when you want the whole operating system.
When an OpenClaw agent replies, it is not answering from a vague pile of messages. It is answering inside a specific session. That session decides which conversation bucket gets loaded, which transcript continues, which token counters update, and which old context may still be influencing the next turn.
This matters more than most operators expect. A bad session setup can make an agent forget work that should have continued, leak one person's context into another person's DM, or keep giant stale transcripts around until every turn gets slow. A clean setup makes the agent feel consistent because each message lands in the right place.
The OpenClaw docs describe sessions as gateway-owned conversation state. The gateway resolves inbound messages into session keys, stores session metadata, writes transcripts, tracks recent activity, and gives UIs the authoritative view. If you are debugging a real deployment, start there.
The gateway owns session state
OpenClaw is designed around one gateway process as the source of truth for sessions. UI clients such as the macOS app, WebChat, Control UI, and TUI should query the gateway for session lists and token counts. In remote mode, the session store you care about lives on the remote gateway host, not necessarily on the laptop in front of you.
That small detail saves a lot of confusion. If the dashboard shows a session but your local file check does not, you may be looking on the wrong machine. If token counts look different from what a client guessed from JSONL files, trust the gateway-backed store fields first.
# Start with the gateway-backed view
openclaw status
openclaw sessions --json
# For remote gateway checks, use the gateway session list API
openclaw gateway call sessions.list --params '{}' The practical rule: do not treat local files as the authority unless that machine is the gateway host for the agent you are inspecting.
There are two persistence layers
OpenClaw persists conversation state in two layers. The first is the session store. The second is the transcript.
- Session store:
~/.openclaw/agents/<agentId>/sessions/sessions.json - Transcript files:
~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl
The store is a map from sessionKey to metadata. It tracks the current sessionId, recent activity, model overrides, toggles, token counters, origin metadata, compaction count, and other runtime fields. The transcript is append-only JSONL. It stores the actual conversation, tool calls, tool results, compaction summaries, branch summaries, and extension-injected messages that belong to the model context.
That distinction is useful when debugging. If a session points at the wrong transcript, check the store. If an old tool result keeps resurfacing, inspect the transcript and context behavior. If a UI label looks wrong, look at the origin metadata and channel routing details in the store.
Session keys decide the conversation bucket
A sessionKey identifies which conversation bucket a message belongs to. OpenClaw maps transports into canonical keys. Direct chats, groups, rooms, cron jobs, webhooks, and node runs are not the same kind of conversation, so they should not all share one bucket.
# Common patterns from the docs
agent:<agentId>:<mainKey>
agent:<agentId>:<channel>:direct:<peerId>
agent:<agentId>:<channel>:group:<id>
agent:<agentId>:<channel>:channel:<id>
cron:<job.id>
hook:<uuid> Direct messages default to the agent's main session for continuity. Groups and rooms isolate state by group or room. Telegram forum topics append a topic id for isolation. Cron jobs can be isolated per run or use a custom persistent session. Webhooks are isolated by hook unless a hook explicitly sets otherwise.
The operator question is simple: should this message continue the same working memory, or should it be isolated from it? The right answer depends on the channel.
Secure DM mode is not optional for shared inboxes
OpenClaw's default direct-message behavior is convenient for a single-user setup: all DMs share the main session. That is great when one owner reaches the agent through multiple transports. It is dangerous when multiple people can DM the same agent.
The docs give the exact failure mode: Alice messages the agent privately, then Bob asks what they were discussing. If both DMs share the main session, Bob can receive context from Alice's conversation. That is not a model problem. That is an isolation problem.
// ~/.openclaw/openclaw.json
{
session: {
// Recommended secure DM mode for multi-user inboxes
dmScope: "per-channel-peer"
}
} Use per-channel-peer to isolate by channel and sender. Use per-account-channel-peer when multiple accounts on the same channel can receive messages. If the same human contacts the agent across providers, session.identityLinks can map provider-prefixed peer ids to a canonical identity so that person's isolated sessions still connect intentionally.
If your agent handles real users, session isolation is a safety feature, not a cleanup chore. Get ClawKit for the full operator checklist before you let multiple people message one agent.
Messages enter sessions through a pipeline
The messages docs summarize the flow clearly:
Inbound message
-> routing/bindings -> session key
-> queue (if a run is active)
-> agent run (streaming + tools)
-> outbound replies (channel limits + chunking) Before a message becomes a model turn, OpenClaw may dedupe redelivered channel events, debounce rapid text-only messages from the same sender, wrap pending group history for context, and decide whether the message should queue, steer, collect, or trigger a followup. Those behaviors are configured under messages.*, agents.defaults.*, and channel-specific overrides.
The important session-management point is this: history wrappers and pending group messages are not the same as transcript history. The docs say pending group history includes messages that did not trigger a run and excludes messages already in the session transcript. That keeps a mention-gated group useful without duplicating everything forever.
Reset creates a new session id
A session key is the bucket. A sessionId is the current transcript inside that bucket. Resetting does not necessarily change the key; it points the key at a fresh transcript.
OpenClaw supports manual resets with standalone /new or /reset. Daily reset defaults to 4:00 AM local time on the gateway host, evaluated on the next inbound message. Optional idle reset creates a fresh session after a sliding idle window. If both daily and idle reset are configured, whichever expires first wins.
// Example reset policy
{
session: {
reset: {
mode: "daily",
atHour: 4,
idleMinutes: 120
},
resetByType: {
direct: { mode: "idle", idleMinutes: 240 },
group: { mode: "idle", idleMinutes: 120 }
}
}
} This is why a user can say “it forgot yesterday” and still be seeing correct behavior. The old transcript may exist on disk, but the session key may have rolled to a new sessionId after the reset boundary.
Compaction is persistent; pruning is not
Long sessions eventually hit context limits. OpenClaw has two related but different tools here.
- Compaction summarizes older conversation into a persisted transcript entry and keeps recent messages after
firstKeptEntryId. - Session pruning trims old tool results from the in-memory context right before model calls by default, but does not rewrite JSONL history.
If you want the longer version, read the ClawKit posts on OpenClaw compaction and session pruning. The short version: compaction changes what future turns rebuild from the transcript. Pruning changes what gets sent in this run.
The deep-dive docs also describe a pre-compaction memory flush. Before auto-compaction, OpenClaw can run a silent NO_REPLY housekeeping turn that reminds the model to write durable notes to memory files. It runs only when the workspace is writable, and it is tracked in sessions.json so it does not repeat endlessly in the same compaction cycle.
Keep session stores bounded
Session files can grow in high-volume systems. OpenClaw has maintenance controls for that. Defaults include warn mode, a 30-day prune window, a 500-entry cap, and a 10 MB rotation threshold for sessions.json. In warn mode, OpenClaw reports potential cleanup but does not mutate files. In enforce mode, it prunes stale entries, caps count, archives unreferenced transcripts, purges old reset/deleted archives, rotates oversized stores, and can enforce a disk budget.
// Conservative production-style policy
{
session: {
maintenance: {
mode: "enforce",
pruneAfter: "45d",
maxEntries: 800,
rotateBytes: "20mb",
resetArchiveRetention: "14d"
}
}
} Preview cleanup before enforcing it:
openclaw sessions cleanup --dry-run
openclaw sessions cleanup --all-agents --dry-run --json
openclaw sessions cleanup --enforce The docs call out a performance caveat: maintenance runs during session-store writes. Very large stores, long prune windows, too many transcript archives, and disk-budget enforcement without reasonable caps can increase write latency. Use both time and count limits. Do not let the sessions directory become your archive strategy.
What to inspect when a session feels wrong
When a user says the agent forgot, mixed conversations, or replied from stale context, do not start by rewriting the prompt. Inspect the session.
- Run
openclaw statusto confirm the store path and recent sessions. - Run
openclaw sessions --jsonoropenclaw sessions --agent <id> --active 120 --jsonto see the current keys. - Send
/statusin the affected chat to see session reachability, toggles, and context usage. - Send
/context listor/context detailto inspect injected context and major token contributors. - Use
/compactwhen old history needs summarizing, or/stopwhen a run and queued followups need aborting.
If you need to manually recover, delete individual keys from the store instead of wiping the whole file. The docs say entries are recreated on demand, but preserving unrelated session state is usually the calmer move.
The operator takeaway
Session management is where agent reliability becomes concrete. A session key answers “which conversation is this?” A session id answers “which transcript continues?” The gateway answers “what is the authoritative state?” The transcript answers “what actually happened?” Maintenance answers “how do we stop this from growing forever?”
Get those layers right and the agent feels steady. Get them wrong and you will chase fake memory problems, prompt problems, and model problems that are really routing and persistence problems.
Want the complete guide? Get ClawKit — $9.99