Browse docs
Docs / concepts / session
Session Management
Session Management
main(default): all DMs share the main session for continuity.per-peer: isolate by sender id across channels.per-channel-peer: isolate by channel + sender (recommended for multi-user inboxes).per-account-channel-peer: isolate by account + channel + sender (recommended for multi-account inboxes). Usesession.identityLinksto map provider-prefixed peer ids to a canonical identity so the same person shares a DM session across channels when usingper-peer,per-channel-peer, orper-account-channel-peer.
Gateway is the source of truth
- In remote mode, the session store you care about lives on the remote gateway host, not your Mac.
- Token counts shown in UIs come from the gateway’s store fields (
inputTokens,outputTokens,totalTokens,contextTokens). Clients do not parse JSONL transcripts to “fix up” totals.
Where state lives
- On the gateway host:
- Store file:
~/.openclaw/agents/<agentId>/sessions/sessions.json(per agent).
- Store file:
- Store file:
~/.openclaw/agents/<agentId>/sessions/sessions.json(per agent). - Transcripts:
~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl(Telegram topic sessions use.../<SessionId>-topic-<threadId>.jsonl). - The store is a map
sessionKey -> { sessionId, updatedAt, ... }. Deleting entries is safe; they are recreated on demand. - Group entries may include
displayName,channel,subject,room, andspaceto label sessions in UIs. - Session entries include
originmetadata (label + routing hints) so UIs can explain where a session came from. - OpenClaw does not read legacy Pi/Tau session folders.
- Store file:
~/.openclaw/agents/<agentId>/sessions/sessions.json(per agent).
Session pruning
Pre-compaction memory flush
Mapping transports → session keys
- Direct chats follow
session.dmScope(defaultmain).main:agent:<agentId>:<mainKey>(continuity across devices/channels).- Multiple phone numbers and channels can map to the same agent main key; they act as transports into one conversation.
per-peer:agent:<agentId>:dm:<peerId>.per-channel-peer:agent:<agentId>:<channel>:dm:<peerId>.per-account-channel-peer:agent:<agentId>:<channel>:<accountId>:dm:<peerId>(accountId defaults todefault).- If
session.identityLinksmatches a provider-prefixed peer id (for exampletelegram:123), the canonical key replaces<peerId>so the same person shares a session across channels.
main:agent:<agentId>:<mainKey>(continuity across devices/channels).- Multiple phone numbers and channels can map to the same agent main key; they act as transports into one conversation.
- Multiple phone numbers and channels can map to the same agent main key; they act as transports into one conversation.
per-peer:agent:<agentId>:dm:<peerId>.per-channel-peer:agent:<agentId>:<channel>:dm:<peerId>.per-account-channel-peer:agent:<agentId>:<channel>:<accountId>:dm:<peerId>(accountId defaults todefault).- If
session.identityLinksmatches a provider-prefixed peer id (for exampletelegram:123), the canonical key replaces<peerId>so the same person shares a session across channels. - Group chats isolate state:
agent:<agentId>:<channel>:group:<id>(rooms/channels useagent:<agentId>:<channel>:channel:<id>).- Telegram forum topics append
:topic:<threadId>to the group id for isolation. - Legacy
group:<id>keys are still recognized for migration.
- Telegram forum topics append
- Telegram forum topics append
:topic:<threadId>to the group id for isolation. - Legacy
group:<id>keys are still recognized for migration. - Inbound contexts may still use
group:<id>; the channel is inferred fromProviderand normalized to the canonicalagent:<agentId>:<channel>:group:<id>form. - Other sources:
- Cron jobs:
cron:<job.id> - Webhooks:
hook:<uuid>(unless explicitly set by the hook) - Node runs:
node-<nodeId>
- Cron jobs:
- Cron jobs:
cron:<job.id> - Webhooks:
hook:<uuid>(unless explicitly set by the hook) - Node runs:
node-<nodeId>
main:agent:<agentId>:<mainKey>(continuity across devices/channels).- Multiple phone numbers and channels can map to the same agent main key; they act as transports into one conversation.
- Multiple phone numbers and channels can map to the same agent main key; they act as transports into one conversation.
per-peer:agent:<agentId>:dm:<peerId>.per-channel-peer:agent:<agentId>:<channel>:dm:<peerId>.per-account-channel-peer:agent:<agentId>:<channel>:<accountId>:dm:<peerId>(accountId defaults todefault).- If
session.identityLinksmatches a provider-prefixed peer id (for exampletelegram:123), the canonical key replaces<peerId>so the same person shares a session across channels.
- Multiple phone numbers and channels can map to the same agent main key; they act as transports into one conversation.
- Telegram forum topics append
:topic:<threadId>to the group id for isolation. - Legacy
group:<id>keys are still recognized for migration.
- Cron jobs:
cron:<job.id> - Webhooks:
hook:<uuid>(unless explicitly set by the hook) - Node runs:
node-<nodeId>
Lifecycle
- Reset policy: sessions are reused until they expire, and expiry is evaluated on the next inbound message.
- Daily reset: defaults to 4:00 AM local time on the gateway host. A session is stale once its last update is earlier than the most recent daily reset time.
- Idle reset (optional):
idleMinutesadds a sliding idle window. When both daily and idle resets are configured, whichever expires first forces a new session. - Legacy idle-only: if you set
session.idleMinuteswithout anysession.reset/resetByTypeconfig, OpenClaw stays in idle-only mode for backward compatibility. - Per-type overrides (optional):
resetByTypelets you override the policy fordm,group, andthreadsessions (thread = Slack/Discord threads, Telegram topics, Matrix threads when provided by the connector). - Per-channel overrides (optional):
resetByChanneloverrides the reset policy for a channel (applies to all session types for that channel and takes precedence overreset/resetByType). - Reset triggers: exact
/newor/reset(plus any extras inresetTriggers) start a fresh session id and pass the remainder of the message through./new <model>accepts a model alias,provider/model, or provider name (fuzzy match) to set the new session model. If/newor/resetis sent alone, OpenClaw runs a short “hello” greeting turn to confirm the reset. - Manual reset: delete specific keys from the store or remove the JSONL transcript; the next message recreates them.
- Isolated cron jobs always mint a fresh
sessionIdper run (no idle reuse).
Send policy (optional)
text
{
session: {
sendPolicy: {
rules: [
{ action: "deny", match: { channel: "discord", chatType: "group" } },
{ action: "deny", match: { keyPrefix: "cron:" } },
],
default: "allow",
},
},
}/send on→ allow for this session/send off→ deny for this session/send inherit→ clear override and use config rules Send these as standalone messages so they register.
Configuration (optional rename example)
text
// ~/.openclaw/openclaw.json
{
session: {
scope: "per-sender", // keep group keys separate
dmScope: "main", // DM continuity (set per-channel-peer/per-account-channel-peer for shared inboxes)
identityLinks: {
alice: ["telegram:123456789", "discord:987654321012345678"],
},
reset: {
// Defaults: mode=daily, atHour=4 (gateway host local time).
// If you also set idleMinutes, whichever expires first wins.
mode: "daily",
atHour: 4,
idleMinutes: 120,
},
resetByType: {
thread: { mode: "daily", atHour: 4 },
dm: { mode: "idle", idleMinutes: 240 },
group: { mode: "idle", idleMinutes: 120 },
},
resetByChannel: {
discord: { mode: "idle", idleMinutes: 10080 },
},
resetTriggers: ["/new", "/reset"],
store: "~/.openclaw/agents/{agentId}/sessions/sessions.json",
mainKey: "main",
},
}Inspecting
openclaw status— shows store path and recent sessions.openclaw sessions --json— dumps every entry (filter with--active <minutes>).openclaw gateway call sessions.list --params '{}'— fetch sessions from the running gateway (use--url/--tokenfor remote gateway access).- Send
/statusas a standalone message in chat to see whether the agent is reachable, how much of the session context is used, current thinking/verbose toggles, and when your WhatsApp web creds were last refreshed (helps spot relink needs). - Send
/context listor/context detailto see what’s in the system prompt and injected workspace files (and the biggest context contributors). - Send
/stopas a standalone message to abort the current run, clear queued followups for that session, and stop any sub-agent runs spawned from it (the reply includes the stopped count). - Send
/compact(optional instructions) as a standalone message to summarize older context and free up window space. See /concepts/compaction. - JSONL transcripts can be opened directly to review full turns.
Tips
- Keep the primary key dedicated to 1:1 traffic; let groups keep their own keys.
- When automating cleanup, delete individual keys instead of the whole store to preserve context elsewhere.
Session origin metadata
label: human label (resolved from conversation label + group subject/channel)provider: normalized channel id (including extensions)from/to: raw routing ids from the inbound envelopeaccountId: provider account id (when multi-account)threadId: thread/topic id when the channel supports it The origin fields are populated for direct messages, channels, and groups. If a connector only updates delivery routing (for example, to keep a DM main session fresh), it should still provide inbound context so the session keeps its explainer metadata. Extensions can do this by sendingConversationLabel,GroupSubject,GroupChannel,GroupSpace, andSenderNamein the inbound context and callingrecordSessionMetaFromInbound(or passing the same context toupdateLastRoute).