forked from Selig/openclaw-skill
6 custom skills (assign-task, dispatch-webhook, daily-briefing, task-capture, qmd-brain, tts-voice) with technical documentation. Compatible with Claude Code, OpenClaw, Codex CLI, and OpenCode.
78 lines
15 KiB
JSON
Executable File
78 lines
15 KiB
JSON
Executable File
{
|
||
"title": "Session Management",
|
||
"content": "OpenClaw treats **one direct-chat session per agent** as primary. Direct chats collapse to `agent:<agentId>:<mainKey>` (default `main`), while group/channel chats get their own keys. `session.mainKey` is honored.\n\nUse `session.dmScope` to control how **direct messages** are grouped:\n\n* `main` (default): all DMs share the main session for continuity.\n* `per-peer`: isolate by sender id across channels.\n* `per-channel-peer`: isolate by channel + sender (recommended for multi-user inboxes).\n* `per-account-channel-peer`: isolate by account + channel + sender (recommended for multi-account inboxes).\n Use `session.identityLinks` to map provider-prefixed peer ids to a canonical identity so the same person shares a DM session across channels when using `per-peer`, `per-channel-peer`, or `per-account-channel-peer`.\n\n### Secure DM mode (recommended)\n\nIf your agent can receive DMs from **multiple people** (pairing approvals for more than one sender, a DM allowlist with multiple entries, or `dmPolicy: \"open\"`), enable **secure DM mode** to avoid cross-user context leakage:\n\n* Default is `dmScope: \"main\"` for continuity (all DMs share the main session).\n* For multi-account inboxes on the same channel, prefer `per-account-channel-peer`.\n* If the same person contacts you on multiple channels, use `session.identityLinks` to collapse their DM sessions into one canonical identity.\n\n## Gateway is the source of truth\n\nAll session state is **owned by the gateway** (the “master” OpenClaw). UI clients (macOS app, WebChat, etc.) must query the gateway for session lists and token counts instead of reading local files.\n\n* In **remote mode**, the session store you care about lives on the remote gateway host, not your Mac.\n* 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.\n\n* On the **gateway host**:\n * Store file: `~/.openclaw/agents/<agentId>/sessions/sessions.json` (per agent).\n* Transcripts: `~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl` (Telegram topic sessions use `.../<SessionId>-topic-<threadId>.jsonl`).\n* The store is a map `sessionKey -> { sessionId, updatedAt, ... }`. Deleting entries is safe; they are recreated on demand.\n* Group entries may include `displayName`, `channel`, `subject`, `room`, and `space` to label sessions in UIs.\n* Session entries include `origin` metadata (label + routing hints) so UIs can explain where a session came from.\n* OpenClaw does **not** read legacy Pi/Tau session folders.\n\nOpenClaw trims **old tool results** from the in-memory context right before LLM calls by default.\nThis does **not** rewrite JSONL history. See [/concepts/session-pruning](/concepts/session-pruning).\n\n## Pre-compaction memory flush\n\nWhen a session nears auto-compaction, OpenClaw can run a **silent memory flush**\nturn that reminds the model to write durable notes to disk. This only runs when\nthe workspace is writable. See [Memory](/concepts/memory) and\n[Compaction](/concepts/compaction).\n\n## Mapping transports → session keys\n\n* Direct chats follow `session.dmScope` (default `main`).\n * `main`: `agent:<agentId>:<mainKey>` (continuity across devices/channels).\n * Multiple phone numbers and channels can map to the same agent main key; they act as transports into one conversation.\n * `per-peer`: `agent:<agentId>:dm:<peerId>`.\n * `per-channel-peer`: `agent:<agentId>:<channel>:dm:<peerId>`.\n * `per-account-channel-peer`: `agent:<agentId>:<channel>:<accountId>:dm:<peerId>` (accountId defaults to `default`).\n * If `session.identityLinks` matches a provider-prefixed peer id (for example `telegram:123`), the canonical key replaces `<peerId>` so the same person shares a session across channels.\n* Group chats isolate state: `agent:<agentId>:<channel>:group:<id>` (rooms/channels use `agent:<agentId>:<channel>:channel:<id>`).\n * Telegram forum topics append `:topic:<threadId>` to the group id for isolation.\n * Legacy `group:<id>` keys are still recognized for migration.\n* Inbound contexts may still use `group:<id>`; the channel is inferred from `Provider` and normalized to the canonical `agent:<agentId>:<channel>:group:<id>` form.\n* Other sources:\n * Cron jobs: `cron:<job.id>`\n * Webhooks: `hook:<uuid>` (unless explicitly set by the hook)\n * Node runs: `node-<nodeId>`\n\n* Reset policy: sessions are reused until they expire, and expiry is evaluated on the next inbound message.\n* 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.\n* Idle reset (optional): `idleMinutes` adds a sliding idle window. When both daily and idle resets are configured, **whichever expires first** forces a new session.\n* Legacy idle-only: if you set `session.idleMinutes` without any `session.reset`/`resetByType` config, OpenClaw stays in idle-only mode for backward compatibility.\n* Per-type overrides (optional): `resetByType` lets you override the policy for `dm`, `group`, and `thread` sessions (thread = Slack/Discord threads, Telegram topics, Matrix threads when provided by the connector).\n* Per-channel overrides (optional): `resetByChannel` overrides the reset policy for a channel (applies to all session types for that channel and takes precedence over `reset`/`resetByType`).\n* Reset triggers: exact `/new` or `/reset` (plus any extras in `resetTriggers`) 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 `/new` or `/reset` is sent alone, OpenClaw runs a short “hello” greeting turn to confirm the reset.\n* Manual reset: delete specific keys from the store or remove the JSONL transcript; the next message recreates them.\n* Isolated cron jobs always mint a fresh `sessionId` per run (no idle reuse).\n\n## Send policy (optional)\n\nBlock delivery for specific session types without listing individual ids.\n\nRuntime override (owner only):\n\n* `/send on` → allow for this session\n* `/send off` → deny for this session\n* `/send inherit` → clear override and use config rules\n Send these as standalone messages so they register.\n\n## Configuration (optional rename example)\n\n* `openclaw status` — shows store path and recent sessions.\n* `openclaw sessions --json` — dumps every entry (filter with `--active <minutes>`).\n* `openclaw gateway call sessions.list --params '{}'` — fetch sessions from the running gateway (use `--url`/`--token` for remote gateway access).\n* Send `/status` as 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).\n* Send `/context list` or `/context detail` to see what’s in the system prompt and injected workspace files (and the biggest context contributors).\n* Send `/stop` as 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).\n* Send `/compact` (optional instructions) as a standalone message to summarize older context and free up window space. See [/concepts/compaction](/concepts/compaction).\n* JSONL transcripts can be opened directly to review full turns.\n\n* Keep the primary key dedicated to 1:1 traffic; let groups keep their own keys.\n* When automating cleanup, delete individual keys instead of the whole store to preserve context elsewhere.\n\n## Session origin metadata\n\nEach session entry records where it came from (best-effort) in `origin`:\n\n* `label`: human label (resolved from conversation label + group subject/channel)\n* `provider`: normalized channel id (including extensions)\n* `from`/`to`: raw routing ids from the inbound envelope\n* `accountId`: provider account id (when multi-account)\n* `threadId`: thread/topic id when the channel supports it\n The origin fields are populated for direct messages, channels, and groups. If a\n connector only updates delivery routing (for example, to keep a DM main session\n fresh), it should still provide inbound context so the session keeps its\n explainer metadata. Extensions can do this by sending `ConversationLabel`,\n `GroupSubject`, `GroupChannel`, `GroupSpace`, and `SenderName` in the inbound\n context and calling `recordSessionMetaFromInbound` (or passing the same context\n to `updateLastRoute`).",
|
||
"code_samples": [
|
||
{
|
||
"code": "Notes:\n\n* Default is `dmScope: \"main\"` for continuity (all DMs share the main session).\n* For multi-account inboxes on the same channel, prefer `per-account-channel-peer`.\n* If the same person contacts you on multiple channels, use `session.identityLinks` to collapse their DM sessions into one canonical identity.\n\n## Gateway is the source of truth\n\nAll session state is **owned by the gateway** (the “master” OpenClaw). UI clients (macOS app, WebChat, etc.) must query the gateway for session lists and token counts instead of reading local files.\n\n* In **remote mode**, the session store you care about lives on the remote gateway host, not your Mac.\n* 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.\n\n## Where state lives\n\n* On the **gateway host**:\n * Store file: `~/.openclaw/agents/<agentId>/sessions/sessions.json` (per agent).\n* Transcripts: `~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl` (Telegram topic sessions use `.../<SessionId>-topic-<threadId>.jsonl`).\n* The store is a map `sessionKey -> { sessionId, updatedAt, ... }`. Deleting entries is safe; they are recreated on demand.\n* Group entries may include `displayName`, `channel`, `subject`, `room`, and `space` to label sessions in UIs.\n* Session entries include `origin` metadata (label + routing hints) so UIs can explain where a session came from.\n* OpenClaw does **not** read legacy Pi/Tau session folders.\n\n## Session pruning\n\nOpenClaw trims **old tool results** from the in-memory context right before LLM calls by default.\nThis does **not** rewrite JSONL history. See [/concepts/session-pruning](/concepts/session-pruning).\n\n## Pre-compaction memory flush\n\nWhen a session nears auto-compaction, OpenClaw can run a **silent memory flush**\nturn that reminds the model to write durable notes to disk. This only runs when\nthe workspace is writable. See [Memory](/concepts/memory) and\n[Compaction](/concepts/compaction).\n\n## Mapping transports → session keys\n\n* Direct chats follow `session.dmScope` (default `main`).\n * `main`: `agent:<agentId>:<mainKey>` (continuity across devices/channels).\n * Multiple phone numbers and channels can map to the same agent main key; they act as transports into one conversation.\n * `per-peer`: `agent:<agentId>:dm:<peerId>`.\n * `per-channel-peer`: `agent:<agentId>:<channel>:dm:<peerId>`.\n * `per-account-channel-peer`: `agent:<agentId>:<channel>:<accountId>:dm:<peerId>` (accountId defaults to `default`).\n * If `session.identityLinks` matches a provider-prefixed peer id (for example `telegram:123`), the canonical key replaces `<peerId>` so the same person shares a session across channels.\n* Group chats isolate state: `agent:<agentId>:<channel>:group:<id>` (rooms/channels use `agent:<agentId>:<channel>:channel:<id>`).\n * Telegram forum topics append `:topic:<threadId>` to the group id for isolation.\n * Legacy `group:<id>` keys are still recognized for migration.\n* Inbound contexts may still use `group:<id>`; the channel is inferred from `Provider` and normalized to the canonical `agent:<agentId>:<channel>:group:<id>` form.\n* Other sources:\n * Cron jobs: `cron:<job.id>`\n * Webhooks: `hook:<uuid>` (unless explicitly set by the hook)\n * Node runs: `node-<nodeId>`\n\n## Lifecycle\n\n* Reset policy: sessions are reused until they expire, and expiry is evaluated on the next inbound message.\n* 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.\n* Idle reset (optional): `idleMinutes` adds a sliding idle window. When both daily and idle resets are configured, **whichever expires first** forces a new session.\n* Legacy idle-only: if you set `session.idleMinutes` without any `session.reset`/`resetByType` config, OpenClaw stays in idle-only mode for backward compatibility.\n* Per-type overrides (optional): `resetByType` lets you override the policy for `dm`, `group`, and `thread` sessions (thread = Slack/Discord threads, Telegram topics, Matrix threads when provided by the connector).\n* Per-channel overrides (optional): `resetByChannel` overrides the reset policy for a channel (applies to all session types for that channel and takes precedence over `reset`/`resetByType`).\n* Reset triggers: exact `/new` or `/reset` (plus any extras in `resetTriggers`) 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 `/new` or `/reset` is sent alone, OpenClaw runs a short “hello” greeting turn to confirm the reset.\n* Manual reset: delete specific keys from the store or remove the JSONL transcript; the next message recreates them.\n* Isolated cron jobs always mint a fresh `sessionId` per run (no idle reuse).\n\n## Send policy (optional)\n\nBlock delivery for specific session types without listing individual ids.",
|
||
"language": "unknown"
|
||
},
|
||
{
|
||
"code": "Runtime override (owner only):\n\n* `/send on` → allow for this session\n* `/send off` → deny for this session\n* `/send inherit` → clear override and use config rules\n Send these as standalone messages so they register.\n\n## Configuration (optional rename example)",
|
||
"language": "unknown"
|
||
}
|
||
],
|
||
"headings": [
|
||
{
|
||
"level": "h3",
|
||
"text": "Secure DM mode (recommended)",
|
||
"id": "secure-dm-mode-(recommended)"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Gateway is the source of truth",
|
||
"id": "gateway-is-the-source-of-truth"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Where state lives",
|
||
"id": "where-state-lives"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Session pruning",
|
||
"id": "session-pruning"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Pre-compaction memory flush",
|
||
"id": "pre-compaction-memory-flush"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Mapping transports → session keys",
|
||
"id": "mapping-transports-→-session-keys"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Lifecycle",
|
||
"id": "lifecycle"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Send policy (optional)",
|
||
"id": "send-policy-(optional)"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Configuration (optional rename example)",
|
||
"id": "configuration-(optional-rename-example)"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Inspecting",
|
||
"id": "inspecting"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Tips",
|
||
"id": "tips"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Session origin metadata",
|
||
"id": "session-origin-metadata"
|
||
}
|
||
],
|
||
"url": "llms-txt#session-management",
|
||
"links": []
|
||
} |