Session Management & Compaction (Deep Dive)
Dieses Dokument erklärt, wie OpenClaw Sessions von Anfang bis Ende verwaltet:
- Session Routing (wie eingehende Nachrichten auf einen
sessionKeygemappt werden) - Session Store (
sessions.json) und was er trackt - Transcript Persistence (
*.jsonl) und seine Struktur - Transcript Hygiene (Provider-spezifische Fixups vor Runs)
- Context Limits (Context Window vs. getrackte Tokens)
- Compaction (manuell + Auto-Compaction) und wo du Pre-Compaction Work einhaken kannst
- Silent Housekeeping (z.B. Memory Writes, die keine sichtbare Ausgabe erzeugen sollen)
Wenn du zuerst einen Überblick haben möchtest, schau dir diese Seiten an:
Source of Truth: der Gateway
OpenClaw ist um einen einzelnen Gateway Process herum aufgebaut, der den Session State besitzt.
- UIs (macOS App, Web Control UI, TUI) sollten den Gateway nach Session Listen und Token Counts abfragen.
- Im Remote Mode liegen die Session Files auf dem Remote Host; “deine lokalen Mac Files checken” zeigt nicht, was der Gateway verwendet.
Zwei Persistence Layer
OpenClaw persistiert Sessions in zwei Layern:
-
Session Store (
sessions.json)- Key/Value Map:
sessionKey -> SessionEntry - Klein, veränderbar, sicher zu editieren (oder Einträge zu löschen)
- Trackt Session Metadata (aktuelle Session ID, letzte Aktivität, Toggles, Token Counter, etc.)
- Key/Value Map:
-
Transcript (
<sessionId>.jsonl)- Append-only Transcript mit Baumstruktur (Einträge haben
id+parentId) - Speichert die eigentliche Konversation + Tool Calls + Compaction Summaries
- Wird verwendet, um den Model Context für zukünftige Turns zu rebuilden
- Append-only Transcript mit Baumstruktur (Einträge haben
Speicherorte auf der Festplatte
Pro Agent, auf dem Gateway Host:
- Store:
~/.openclaw/agents/<agentId>/sessions/sessions.json - Transcripts:
~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl- Telegram Topic Sessions:
.../<sessionId>-topic-<threadId>.jsonl
- Telegram Topic Sessions:
OpenClaw löst diese Pfade über src/config/sessions.ts auf.
Session Keys (sessionKey)
Ein sessionKey identifiziert, in welchem Conversation Bucket du dich befindest (Routing + Isolation).
Gängige Muster:
- Main/Direct Chat (pro Agent):
agent:<agentId>:<mainKey>(Standard:main) - Group:
agent:<agentId>:<channel>:group:<id> - Room/Channel (Discord/Slack):
agent:<agentId>:<channel>:channel:<id>oder...:room:<id> - Cron:
cron:<job.id> - Webhook:
hook:<uuid>(außer überschrieben)
Die kanonischen Regeln sind unter /concepts/session dokumentiert.
Session IDs (sessionId)
Jeder sessionKey zeigt auf eine aktuelle sessionId (das Transcript File, das die Konversation fortsetzt).
Faustregeln:
- Reset (
/new,/reset) erstellt eine neuesessionIdfür diesensessionKey. - Daily Reset (Standard: 4:00 Uhr morgens Lokalzeit auf dem Gateway Host) erstellt eine neue
sessionIdbei der nächsten Nachricht nach der Reset-Grenze. - Idle Expiry (
session.reset.idleMinutesoder Legacysession.idleMinutes) erstellt eine neuesessionId, wenn eine Nachricht nach dem Idle Window eintrifft. Wenn Daily + Idle beide konfiguriert sind, gewinnt das, was zuerst abläuft.
Implementierungsdetail: Die Entscheidung passiert in initSessionState() in src/auto-reply/reply/session.ts.
Session Store Schema (sessions.json)
Der Value Type des Stores ist SessionEntry in src/config/sessions.ts.
Wichtige Felder (nicht vollständig):
sessionId: aktuelle Transcript ID (Dateiname wird davon abgeleitet, außersessionFileist gesetzt)updatedAt: Zeitstempel der letzten AktivitätsessionFile: optionaler expliziter Transcript Path OverridechatType:direct | group | room(hilft UIs und Send Policy)provider,subject,room,space,displayName: Metadata für Group/Channel Labeling- Toggles:
thinkingLevel,verboseLevel,reasoningLevel,elevatedLevelsendPolicy(Per-Session Override)
- Model Selection:
providerOverride,modelOverride,authProfileOverride
- Token Counter (Best-Effort / Provider-abhängig):
inputTokens,outputTokens,totalTokens,contextTokens
compactionCount: wie oft Auto-Compaction für diesen Session Key abgeschlossen wurdememoryFlushAt: Zeitstempel für den letzten Pre-Compaction Memory FlushmemoryFlushCompactionCount: Compaction Count, als der letzte Flush lief
Der Store ist sicher zu editieren, aber der Gateway ist die Autorität: Er kann Einträge neu schreiben oder rehydrieren, während Sessions laufen.
Transcript Struktur (*.jsonl)
Transcripts werden vom SessionManager von @mariozechner/pi-coding-agent verwaltet.
Das File ist JSONL:
- Erste Zeile: Session Header (
type: "session", enthältid,cwd,timestamp, optionalparentSession) - Dann: Session Entries mit
id+parentId(Baum)
Wichtige Entry Types:
message: User/Assistant/ToolResult Messagescustom_message: Extension-injizierte Messages, die in den Model Context eingehen (können im UI versteckt sein)custom: Extension State, der nicht in den Model Context eingehtcompaction: persistierte Compaction Summary mitfirstKeptEntryIdundtokensBeforebranch_summary: persistierte Summary beim Navigieren eines Tree Branch
OpenClaw “fixt” Transcripts absichtlich nicht; der Gateway verwendet SessionManager, um sie zu lesen/schreiben.
Context Windows vs. getrackte Tokens
Zwei verschiedene Konzepte sind wichtig:
- Model Context Window: hartes Limit pro Model (Tokens, die für das Model sichtbar sind)
- Session Store Counter: rollende Stats, die in
sessions.jsongeschrieben werden (verwendet für /status und Dashboards)
Wenn du Limits tunst:
- Das Context Window kommt aus dem Model Catalog (und kann via Config überschrieben werden).
contextTokensim Store ist ein Runtime Estimate/Reporting Value; behandle es nicht als strikte Garantie.
Mehr dazu unter /token-use.
Compaction: Was es ist
Compaction fasst ältere Konversation in einem persistierten compaction Entry im Transcript zusammen und hält aktuelle Messages intakt.
Nach Compaction sehen zukünftige Turns:
- Die Compaction Summary
- Messages nach
firstKeptEntryId
Compaction ist persistent (im Gegensatz zu Session Pruning). Siehe /concepts/session-pruning.
Wann Auto-Compaction passiert (Pi Runtime)
Im embedded Pi Agent triggert Auto-Compaction in zwei Fällen:
- Overflow Recovery: Das Model gibt einen Context Overflow Error zurück → compact → retry.
- Threshold Maintenance: Nach einem erfolgreichen Turn, wenn:
contextTokens > contextWindow - reserveTokens
Dabei gilt:
contextWindowist das Context Window des ModelsreserveTokensist Headroom, der für Prompts + den nächsten Model Output reserviert ist
Das sind Pi Runtime Semantics (OpenClaw konsumiert die Events, aber Pi entscheidet, wann kompaktiert wird).
Compaction Settings (reserveTokens, keepRecentTokens)
Pis Compaction Settings leben in den Pi Settings:
{
compaction: {
enabled: true,
reserveTokens: 16384,
keepRecentTokens: 20000,
},
}
OpenClaw erzwingt außerdem einen Safety Floor für embedded Runs:
- Wenn
compaction.reserveTokens < reserveTokensFloor, bumpt OpenClaw es hoch. - Standard Floor ist
20000Tokens. - Setze
agents.defaults.compaction.reserveTokensFloor: 0, um den Floor zu deaktivieren. - Wenn es bereits höher ist, lässt OpenClaw es in Ruhe.
Warum: Genug Headroom für Multi-Turn “Housekeeping” (wie Memory Writes) lassen, bevor Compaction unvermeidbar wird.
Implementation: ensurePiCompactionReserveTokens() in src/agents/pi-settings.ts
(aufgerufen von src/agents/pi-embedded-runner.ts).
User-sichtbare Oberflächen
Du kannst Compaction und Session State beobachten über:
/status(in jeder Chat Session)openclaw status(CLI)openclaw sessions/sessions --json- Verbose Mode:
🧹 Auto-compaction complete+ Compaction Count
Silent Housekeeping (NO_REPLY)
OpenClaw unterstützt “silent” Turns für Background Tasks, bei denen der User keine Zwischenausgabe sehen soll.
Konvention:
- Der Assistant startet seine Ausgabe mit
NO_REPLY, um anzuzeigen “deliver keine Reply an den User”. - OpenClaw strippt/unterdrückt das im Delivery Layer.
Seit 2026.1.10 unterdrückt OpenClaw auch Draft/Typing Streaming, wenn ein partieller Chunk mit NO_REPLY beginnt, sodass Silent Operations keine partielle Ausgabe mid-turn leaken.
Pre-Compaction “Memory Flush” (implementiert)
Ziel: Bevor Auto-Compaction passiert, einen silent agentic Turn laufen lassen, der dauerhaften
State auf die Festplatte schreibt (z.B. memory/YYYY-MM-DD.md im Agent Workspace), sodass Compaction
keinen kritischen Context löschen kann.
OpenClaw verwendet den Pre-Threshold Flush Ansatz:
- Session Context Usage monitoren.
- Wenn er einen “Soft Threshold” überschreitet (unterhalb von Pis Compaction Threshold), einen silent “write memory now” Directive an den Agent laufen lassen.
NO_REPLYverwenden, sodass der User nichts sieht.
Config (agents.defaults.compaction.memoryFlush):
enabled(Standard:true)softThresholdTokens(Standard:4000)prompt(User Message für den Flush Turn)systemPrompt(extra System Prompt, der für den Flush Turn angehängt wird)
Hinweise:
- Der Standard Prompt/System Prompt enthält einen
NO_REPLYHint, um Delivery zu unterdrücken. - Der Flush läuft einmal pro Compaction Cycle (getrackt in
sessions.json). - Der Flush läuft nur für embedded Pi Sessions (CLI Backends überspringen ihn).
- Der Flush wird übersprungen, wenn der Session Workspace read-only ist (
workspaceAccess: "ro"oder"none"). - Siehe Memory für das Workspace File Layout und Write Patterns.
Pi exponiert auch einen session_before_compact Hook in der Extension API, aber OpenClaws
Flush Logic lebt heute auf der Gateway Seite.
Troubleshooting Checkliste
- Session Key falsch? Starte mit /concepts/session und bestätige den
sessionKeyin/status. - Store vs. Transcript Mismatch? Bestätige den Gateway Host und den Store Path von
openclaw status. - Compaction Spam? Prüfe:
- Model Context Window (zu klein)
- Compaction Settings (
reserveTokenszu hoch für das Model Window kann frühere Compaction verursachen) - Tool-Result Bloat: aktiviere/tune Session Pruning
- Silent Turns leaken? Bestätige, dass die Reply mit
NO_REPLY(exakter Token) startet und du auf einem Build bist, der den Streaming Suppression Fix enthält.