Session Management
OpenClaw는 agent당 하나의 direct-chat session을 primary로 취급합니다. direct chat은agent:<agentId>:<mainKey>로 collapse되며
(기본 main), group/channel chat은 각자 별도 key를 가집니다.
session.mainKey도 그대로 존중됩니다.
direct message가 어떻게 묶일지는 session.dmScope로 제어합니다.
main(기본값): 모든 DM이 continuity를 위해 main session을 공유per-peer: channel 전반에서 sender id별로 분리per-channel-peer: channel + sender별로 분리 (multi-user inbox에 권장)per-account-channel-peer: account + channel + sender별로 분리 (multi-account inbox에 권장)
per-peer, per-channel-peer, per-account-channel-peer를 쓸 때는
session.identityLinks를 사용해 provider-prefixed peer id를 canonical identity로
매핑할 수 있습니다. 그러면 같은 사람이 여러 channel로 연락해도 하나의 DM session을
공유하게 할 수 있습니다.
Secure DM mode (recommended for multi-user setups)
Security Warning: agent가 여러 사람의 DM을 받을 수 있다면, secure DM mode를 강하게 권장합니다. 그렇지 않으면 모든 사용자가 같은 conversation context를 공유해 private information이 다른 사용자에게 노출될 수 있습니다.기본 설정에서 생길 수 있는 문제 예시:
- Alice (
<SENDER_A>)가 medical appointment 같은 private topic을 agent와 이야기함 - Bob (
<SENDER_B>)이 agent에게 “What were we talking about?”라고 질문함 - 두 DM이 같은 session을 공유하므로, model이 Alice의 prior context를 써서 Bob에게 답할 수 있음
dmScope를 사용자별로 분리되는 값으로 설정합니다.
- pairing approval을 받은 sender가 둘 이상일 때
- 여러 entry가 있는 DM allowlist를 쓸 때
dmPolicy: "open"을 쓸 때- 여러 phone number나 account가 agent에 message를 보낼 수 있을 때
- 기본값
dmScope: "main"은 continuity를 위한 값이며, single-user setup에는 적절합니다 - local CLI onboarding은 값이 unset일 때 기본적으로
session.dmScope: "per-channel-peer"를 기록합니다 (기존 explicit 값은 유지) - 같은 channel에서 여러 account를 쓰는 inbox라면
per-account-channel-peer가 더 적합합니다 - 같은 사람이 여러 channel로 연락한다면
session.identityLinks로 하나의 canonical identity에 collapse할 수 있습니다 - DM 설정은
openclaw security audit로 검증할 수 있습니다 (security)
Gateway is the source of truth
모든 session state는 gateway(master OpenClaw)가 소유합니다. macOS app, WebChat 같은 UI client는 local file을 직접 읽지 말고 gateway에 질의해 session list와 token count를 받아와야 합니다.- remote mode에서는 실제 session store가 Mac이 아니라 remote gateway host에 있습니다
- UI에 보이는 token count는 gateway store field
(
inputTokens,outputTokens,totalTokens,contextTokens)에서 옵니다. client는 JSONL transcript를 직접 파싱해서 total을 “보정”하지 않습니다
Where state lives
- gateway host:
- store file:
~/.openclaw/agents/<agentId>/sessions/sessions.json(agent별)
- store file:
- transcript:
~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl(Telegram topic session은.../<SessionId>-topic-<threadId>.jsonl) - store는
sessionKey -> { sessionId, updatedAt, ... }map입니다. entry를 삭제해도 필요 시 on demand로 다시 만들어지므로 안전합니다 - group entry에는 UI용 label을 위해
displayName,channel,subject,room,space가 들어갈 수 있습니다 - session entry에는 어디서 온 session인지 설명하는
originmetadata (label + routing hint)가 포함됩니다 - OpenClaw는 legacy Pi/Tau session folder를 읽지 않습니다
Maintenance
OpenClaw는 시간이 지나도sessions.json과 transcript artifact가 무한정 커지지 않도록
session-store maintenance를 수행합니다.
Defaults
session.maintenance.mode:warnsession.maintenance.pruneAfter:30dsession.maintenance.maxEntries:500session.maintenance.rotateBytes:10mbsession.maintenance.resetArchiveRetention: 기본값은pruneAfter(30d)session.maintenance.maxDiskBytes: unset (disabled)session.maintenance.highWaterBytes: disk budget을 켠 경우 기본값은maxDiskBytes의80%
How it works
maintenance는 session-store write 시 실행되며,openclaw sessions cleanup으로 수동 실행도 가능합니다.
mode: "warn": 무엇이 제거될지 보고만 하고 실제 mutation은 하지 않음mode: "enforce": 다음 순서로 cleanup 적용pruneAfter보다 오래된 stale entry 제거- entry count를
maxEntries로 cap (가장 오래된 것부터) - 제거된 entry가 더 이상 참조하지 않는 transcript file archive
- retention policy에 따라 오래된
*.deleted.<timestamp>,*.reset.<timestamp>archive 제거 sessions.json이rotateBytes를 넘으면 rotatemaxDiskBytes가 설정돼 있으면highWaterBytes까지 disk budget 강제 (오래된 artifact 우선, 그다음 오래된 session)
Performance caveat for large stores
고부하 환경에서는 큰 session store가 흔합니다. maintenance는 write path에서 수행되므로, store가 아주 크면 write latency가 늘어날 수 있습니다. 특히 비용이 커지는 요인:- 너무 높은
session.maintenance.maxEntries - stale entry를 오래 남기는 긴
pruneAfter ~/.openclaw/agents/<agentId>/sessions/안의 많은 transcript/archive artifact- 적절한 prune/cap 없이
maxDiskBytes만 켜는 경우
- production에서는
mode: "enforce"를 사용해 growth를 자동으로 bounded 상태로 유지 - 시간 제한과 개수 제한을 함께 설정
(
pruneAfter+maxEntries) - 큰 배포에서는
maxDiskBytes+highWaterBytes로 hard upper bound 설정 highWaterBytes는maxDiskBytes보다 충분히 낮게 유지 (기본 80%)- config 변경 후
openclaw sessions cleanup --dry-run --json으로 예상 영향 확인 - active session이 많다면 manual cleanup 시
--active-key를 전달
Customize examples
보수적인 enforce policy:Session pruning
OpenClaw는 기본적으로 LLM call 직전에 in-memory context에서 오래된 tool result를 trim합니다. JSONL history를 다시 쓰지는 않습니다. 자세한 내용은 /concepts/session-pruning을 보세요.Pre-compaction memory flush
session이 auto-compaction에 가까워지면, OpenClaw는 model에게 durable note를 disk에 쓰라고 상기시키는 silent memory flush turn을 실행할 수 있습니다. 이 동작은 workspace에 쓰기 권한이 있을 때만 실행됩니다. Memory와 Compaction을 참고하세요.Mapping transports → session keys
- direct chat은
session.dmScope(기본값main)를 따릅니다main:agent:<agentId>:<mainKey>(device/channel을 넘어 continuity 유지)- 여러 phone number와 channel이 같은 agent main key에 매핑될 수 있으며, 하나의 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기본값은default)session.identityLinks가 provider-prefixed peer id (예:telegram:123)와 일치하면<peerId>대신 canonical key를 사용해 같은 사람이 channel을 넘어 session을 공유하게 합니다
- group chat은 state를 분리합니다:
agent:<agentId>:<channel>:group:<id>(room/channel은agent:<agentId>:<channel>:channel:<id>)- Telegram forum topic은 group id 뒤에
:topic:<threadId>를 붙여 분리합니다 - legacy
group:<id>key도 migration용으로 인식됩니다
- Telegram forum topic은 group id 뒤에
- inbound context는 여전히
group:<id>를 쓸 수 있지만, channel은Provider에서 추론되어 canonicalagent:<agentId>:<channel>:group:<id>형태로 normalize됩니다 - 그 외 source:
- Cron job:
cron:<job.id> - Webhook:
hook:<uuid>(hook이 명시적으로 설정하지 않은 경우) - Node run:
node-<nodeId>
- Cron job:
Lifecycle
- reset policy: session은 만료될 때까지 재사용되며, 만료 여부는 다음 inbound message에서 평가됨
- daily reset: 기본값은 gateway host local time 기준 오전 4시. 마지막 update가 가장 최근 daily reset 시각보다 이전이면 stale로 간주
- idle reset
(optional):
idleMinutes는 sliding idle window를 추가합니다. daily와 idle이 함께 있으면 더 먼저 만료되는 쪽이 새 session을 강제 - legacy idle-only:
session.idleMinutes만 있고session.reset/resetByType이 없으면 backward compatibility를 위해 idle-only mode 유지 - type별 override
(optional):
resetByType으로direct,group,threadpolicy override 가능 (thread = Slack/Discord thread, Telegram topic, connector가 제공하는 Matrix thread) - channel별 override
(optional):
resetByChannel은 channel의 reset policy를 override하며,reset/resetByType보다 우선 - reset trigger:
정확히
/new또는/reset(및resetTriggers의 추가 trigger)는 새 session id를 시작하고 message의 나머지를 계속 전달합니다./new <model>은 model alias,provider/model, provider name의 fuzzy match를 받아 새 session model을 설정할 수 있습니다./new나/reset만 단독으로 보내면, OpenClaw는 짧은 “hello” greeting turn으로 reset을 확인해 줍니다 - manual reset: store에서 특정 key를 지우거나 JSONL transcript를 제거하면, 다음 message가 다시 만들어 냅니다
- isolated cron job은 매 run마다 항상 새
sessionId를 만듭니다 (idle reuse 없음)
Send policy (optional)
특정 session type에 대한 delivery를 개별 id 나열 없이 차단할 수 있습니다./send on→ 이 session에서 allow/send off→ 이 session에서 deny/send inherit→ override를 지우고 config rule 사용
Configuration (optional rename example)
Inspecting
openclaw status— store path와 recent session 표시openclaw sessions --json— 모든 entry dump (--active <minutes>로 filter 가능)openclaw gateway call sessions.list --params '{}'— 실행 중인 gateway에서 session fetch (remote gateway면--url/--token사용)- chat에서
/status를 standalone message로 보내면, agent reachability, session context 사용량, thinking/verbose toggle, WhatsApp web credential의 last refresh 시각 등을 볼 수 있습니다 /context list또는/context detail은 system prompt와 injected workspace file, 그리고 큰 context contributor를 보여줍니다/stop(또는stop,stop action,stop run,stop openclaw)은 현재 run을 abort하고, queued followup과 그 session에서 spawned된 sub-agent run도 멈춥니다/compact(optional instruction 포함 가능)는 오래된 context를 summarize해 window 공간을 확보합니다. /concepts/compaction을 참고하세요- JSONL transcript는 직접 열어 full turn을 검토할 수 있습니다
Tips
- primary key는 1:1 traffic에만 쓰고, group은 각자의 key를 유지하게 두세요
- cleanup 자동화 시에는 전체 store를 지우지 말고 개별 key만 삭제해 다른 context를 보존하세요
Session origin metadata
각 session entry는origin에 best-effort source metadata를 기록합니다.
label: human label (conversation label + group subject/channel에서 resolve)provider: normalized channel id (extension 포함)from/to: inbound envelope의 raw routing idaccountId: multi-account일 때 provider account idthreadId: channel이 지원할 때 thread/topic id
ConversationLabel, GroupSubject, GroupChannel,
GroupSpace, SenderName을 넣고 recordSessionMetaFromInbound를 호출하거나,
같은 context를 updateLastRoute에 전달해 이를 달성할 수 있습니다.