Session-Verwaltung

OpenClaw behandelt eine Direktchat-Session pro Agent als primaer. Direktchats werden auf agent:<agentId>:<mainKey> (Standard main) zusammengefuehrt, waehrend Gruppen-/Kanal-Chats eigene Keys bekommen. session.mainKey wird beruecksichtigt.

Nutze session.dmScope, um zu steuern, wie Direktnachrichten gruppiert werden:

  • main (Standard): Alle DMs teilen sich die Hauptsession fuer Kontinuitaet.
  • per-peer: Isolation nach Absender-ID kanaluebergreifend.
  • per-channel-peer: Isolation nach Kanal + Absender (empfohlen fuer Multi-User-Posteingaenge).
  • per-account-channel-peer: Isolation nach Account + Kanal + Absender (empfohlen fuer Multi-Account-Posteingaenge). Nutze session.identityLinks, um provider-praefixierte Peer-IDs auf eine kanonische Identitaet abzubilden, damit dieselbe Person bei per-peer, per-channel-peer oder per-account-channel-peer kanaluebergreifend eine DM-Session teilt.

Sicherer DM-Modus (empfohlen fuer Multi-User-Setups)

Sicherheitswarnung: Wenn dein Agent DMs von mehreren Personen empfangen kann, solltest du dringend den sicheren DM-Modus aktivieren. Ohne ihn teilen sich alle Nutzer denselben Gespraechskontext, was private Informationen zwischen Nutzern leaken kann.

Beispiel des Problems mit Standardeinstellungen:

  • Alice (<SENDER_A>) schreibt deinem Agent ueber ein privates Thema (zum Beispiel einen Arzttermin)
  • Bob (<SENDER_B>) schreibt deinem Agent “Worueber haben wir geredet?”
  • Weil beide DMs dieselbe Session teilen, antwortet das Modell Bob moeglicherweise mit Alices Kontext.

Die Loesung: Setze dmScope, um Sessions pro Nutzer zu isolieren:

// ~/.openclaw/openclaw.json
{
  session: {
    // Sicherer DM-Modus: DM-Kontext pro Kanal + Absender isolieren.
    dmScope: "per-channel-peer",
  },
}

Wann du das aktivieren solltest:

  • Du hast Pairing-Genehmigungen fuer mehr als einen Absender
  • Du nutzt eine DM-Allowlist mit mehreren Eintraegen
  • Du hast dmPolicy: "open" gesetzt
  • Mehrere Telefonnummern oder Accounts koennen deinem Agent schreiben

Hinweise:

  • Standard ist dmScope: "main" fuer Kontinuitaet (alle DMs teilen die Hauptsession). Das ist fuer Single-User-Setups in Ordnung.
  • Lokales CLI-Onboarding schreibt session.dmScope: "per-channel-peer" als Standard, wenn nicht gesetzt (bestehende explizite Werte bleiben erhalten).
  • Fuer Multi-Account-Posteingaenge auf demselben Kanal bevorzuge per-account-channel-peer.
  • Wenn dieselbe Person dich ueber mehrere Kanaele kontaktiert, nutze session.identityLinks, um deren DM-Sessions in eine kanonische Identitaet zusammenzufuehren.
  • Du kannst deine DM-Einstellungen mit openclaw security audit ueberpruefen (siehe security).

Das Gateway ist die Wahrheitsquelle

Alle Session-Zustaende gehoeren dem Gateway (dem “Master”-OpenClaw). UI-Clients (macOS-App, WebChat usw.) muessen das Gateway fuer Session-Listen und Token-Zaehler abfragen, statt lokale Dateien zu lesen.

  • Im Remote-Modus lebt der relevante Session-Store auf dem Remote-Gateway-Host, nicht auf deinem Mac.
  • Token-Zaehler in UIs stammen aus den Store-Feldern des Gateways (inputTokens, outputTokens, totalTokens, contextTokens). Clients parsen keine JSONL-Transkripte, um Summen zu “korrigieren”.

Wo der Zustand lebt

  • Auf dem Gateway-Host:
    • Store-Datei: ~/.openclaw/agents/<agentId>/sessions/sessions.json (pro Agent).
  • Transkripte: ~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl (Telegram-Topic-Sessions nutzen .../<SessionId>-topic-<threadId>.jsonl).
  • Der Store ist eine Map sessionKey -> { sessionId, updatedAt, ... }. Eintraege zu loeschen ist sicher; sie werden bei Bedarf neu erstellt.
  • Gruppeneintraege koennen displayName, channel, subject, room und space enthalten, um Sessions in UIs zu beschriften.
  • Session-Eintraege enthalten origin-Metadaten (Label + Routing-Hinweise), damit UIs erklaeren koennen, woher eine Session stammt.
  • OpenClaw liest keine Legacy-Pi/Tau-Session-Ordner.

Wartung

OpenClaw wendet Session-Store-Wartung an, um sessions.json und Transkript-Artefakte ueber die Zeit begrenzt zu halten.

Standardwerte

  • session.maintenance.mode: warn
  • session.maintenance.pruneAfter: 30d
  • session.maintenance.maxEntries: 500
  • session.maintenance.rotateBytes: 10mb
  • session.maintenance.resetArchiveRetention: Standard ist pruneAfter (30d)
  • session.maintenance.maxDiskBytes: nicht gesetzt (deaktiviert)
  • session.maintenance.highWaterBytes: Standard ist 80% von maxDiskBytes, wenn Budgetierung aktiviert ist

So funktioniert es

Wartung laeuft waehrend Session-Store-Schreibvorgaengen, und du kannst sie bei Bedarf mit openclaw sessions cleanup ausloesen.

  • mode: "warn": meldet, was bereinigt werden wuerde, veraendert aber keine Eintraege/Transkripte.
  • mode: "enforce": wendet die Bereinigung in dieser Reihenfolge an:
    1. veraltete Eintraege aelter als pruneAfter bereinigen
    2. Eintragsanzahl auf maxEntries begrenzen (aelteste zuerst)
    3. Transkript-Dateien fuer entfernte Eintraege archivieren, die nicht mehr referenziert werden
    4. alte *.deleted.<timestamp>- und *.reset.<timestamp>-Archive nach Aufbewahrungsrichtlinie bereinigen
    5. sessions.json rotieren, wenn sie rotateBytes ueberschreitet
    6. wenn maxDiskBytes gesetzt ist, Disk-Budget bis highWaterBytes durchsetzen (aelteste Artefakte zuerst, dann aelteste Sessions)

Performance-Hinweis fuer grosse Stores

Grosse Session-Stores sind bei High-Volume-Setups ueblich. Wartungsarbeit ist Write-Path-Arbeit, sodass sehr grosse Stores die Schreib-Latenz erhoehen koennen.

Was die Kosten am meisten erhoet:

  • sehr hohe session.maintenance.maxEntries-Werte
  • lange pruneAfter-Fenster, die veraltete Eintraege am Leben halten
  • viele Transkript-/Archiv-Artefakte in ~/.openclaw/agents/<agentId>/sessions/
  • Disk-Budgets (maxDiskBytes) aktivieren ohne vernuenftige Pruning-/Cap-Limits

Was du tun kannst:

  • mode: "enforce" im Produktivbetrieb nutzen, damit das Wachstum automatisch begrenzt ist
  • sowohl Zeit- als auch Anzahl-Limits setzen (pruneAfter + maxEntries), nicht nur eins von beiden
  • maxDiskBytes + highWaterBytes fuer harte Obergrenzen in grossen Deployments setzen
  • highWaterBytes deutlich unter maxDiskBytes halten (Standard: 80%)
  • openclaw sessions cleanup --dry-run --json nach Config-Aenderungen ausfuehren, um die prognostizierten Auswirkungen zu pruefen, bevor du durchsetzt
  • bei haeufig aktiven Sessions --active-key bei manueller Bereinigung uebergeben

Beispiele

Konservative Enforce-Richtlinie:

{
  session: {
    maintenance: {
      mode: "enforce",
      pruneAfter: "45d",
      maxEntries: 800,
      rotateBytes: "20mb",
      resetArchiveRetention: "14d",
    },
  },
}

Hartes Disk-Budget fuer das Sessions-Verzeichnis:

{
  session: {
    maintenance: {
      mode: "enforce",
      maxDiskBytes: "1gb",
      highWaterBytes: "800mb",
    },
  },
}

Fuer groessere Installationen optimieren (Beispiel):

{
  session: {
    maintenance: {
      mode: "enforce",
      pruneAfter: "14d",
      maxEntries: 2000,
      rotateBytes: "25mb",
      maxDiskBytes: "2gb",
      highWaterBytes: "1.6gb",
    },
  },
}

Wartung per CLI pruefen oder erzwingen:

openclaw sessions cleanup --dry-run
openclaw sessions cleanup --enforce

Session-Pruning

OpenClaw kuerzt standardmaessig alte Tool-Ergebnisse im In-Memory-Kontext direkt vor LLM-Aufrufen. Das veraendert nicht die JSONL-Historie. Siehe /concepts/session-pruning.

Pre-Compaction Memory Flush

Wenn eine Session sich der Auto-Kompaktierung naehert, kann OpenClaw eine stille Memory-Flush-Runde ausfuehren, die das Modell daran erinnert, dauerhafte Notizen auf die Festplatte zu schreiben. Das laeuft nur, wenn der Workspace beschreibbar ist. Siehe Memory und Compaction.

Zuordnung von Transporten zu Session-Keys

  • Direktchats folgen session.dmScope (Standard main).
    • main: agent:<agentId>:<mainKey> (Kontinuitaet ueber Geraete/Kanaele).
      • Mehrere Telefonnummern und Kanaele koennen auf denselben Agent-Main-Key abgebildet werden; sie fungieren als Transporte in eine Konversation.
    • per-peer: agent:<agentId>:direct:<peerId>.
    • per-channel-peer: agent:<agentId>:<channel>:direct:<peerId>.
    • per-account-channel-peer: agent:<agentId>:<channel>:<accountId>:direct:<peerId> (accountId ist standardmaessig default).
    • Wenn session.identityLinks eine provider-praefixierte Peer-ID matched (zum Beispiel telegram:123), ersetzt der kanonische Key <peerId>, sodass dieselbe Person kanaluebergreifend eine Session teilt.
  • Gruppenchats isolieren den Zustand: agent:<agentId>:<channel>:group:<id> (Raeume/Kanaele nutzen agent:<agentId>:<channel>:channel:<id>).
    • Telegram-Forum-Themen haengen :topic:<threadId> an die Gruppen-ID fuer Isolation an.
    • Legacy-group:<id>-Keys werden weiterhin fuer die Migration erkannt.
  • Eingehende Kontexte koennen weiterhin group:<id> nutzen; der Kanal wird aus Provider abgeleitet und in die kanonische agent:<agentId>:<channel>:group:<id>-Form normalisiert.
  • Andere Quellen:
    • Cron-Jobs: cron:<job.id>
    • Webhooks: hook:<uuid> (sofern nicht explizit vom Hook gesetzt)
    • Node-Laeufe: node-<nodeId>

Lebenszyklus

  • Reset-Richtlinie: Sessions werden wiederverwendet, bis sie ablaufen, und der Ablauf wird bei der naechsten eingehenden Nachricht geprueft.
  • Taeglicher Reset: Standard ist 4:00 Uhr Ortszeit auf dem Gateway-Host. Eine Session gilt als veraltet, sobald ihre letzte Aktualisierung vor dem letzten taeglichen Reset-Zeitpunkt liegt.
  • Idle-Reset (optional): idleMinutes fuegt ein gleitendes Idle-Fenster hinzu. Wenn sowohl taeglicher als auch Idle-Reset konfiguriert sind, erzwingt der zuerst ablaufende eine neue Session.
  • Legacy Idle-only: Wenn du session.idleMinutes ohne session.reset/resetByType-Config setzt, bleibt OpenClaw aus Gruenden der Abwaertskompatibilitaet im Idle-only-Modus.
  • Pro-Typ-Overrides (optional): resetByType erlaubt das Ueberschreiben der Richtlinie fuer direct-, group- und thread-Sessions (Thread = Slack/Discord-Threads, Telegram-Themen, Matrix-Threads, wenn vom Connector bereitgestellt).
  • Pro-Kanal-Overrides (optional): resetByChannel ueberschreibt die Reset-Richtlinie fuer einen Kanal (gilt fuer alle Session-Typen dieses Kanals und hat Vorrang vor reset/resetByType).
  • Reset-Trigger: exaktes /new oder /reset (plus Extras in resetTriggers) starten eine neue Session-ID und leiten den Rest der Nachricht weiter. /new <model> akzeptiert einen Model-Alias, provider/model oder Provider-Namen (Fuzzy-Match) zum Setzen des neuen Session-Modells. Wenn /new oder /reset allein gesendet wird, fuehrt OpenClaw eine kurze “Hallo”-Begruessungsrunde aus, um den Reset zu bestaetigen.
  • Manueller Reset: bestimmte Keys aus dem Store loeschen oder das JSONL-Transkript entfernen; die naechste Nachricht erstellt sie neu.
  • Isolierte Cron-Jobs erzeugen immer eine neue sessionId pro Lauf (keine Idle-Wiederverwendung).

Send Policy (optional)

Zustellung fuer bestimmte Session-Typen blockieren, ohne einzelne IDs auflisten zu muessen.

{
  session: {
    sendPolicy: {
      rules: [
        { action: "deny", match: { channel: "discord", chatType: "group" } },
        { action: "deny", match: { keyPrefix: "cron:" } },
        // Den rohen Session-Key matchen (einschliesslich des `agent:<id>:`-Praefixes).
        { action: "deny", match: { rawKeyPrefix: "agent:main:discord:" } },
      ],
      default: "allow",
    },
  },
}

Runtime-Override (nur Owner):

  • /send on — fuer diese Session erlauben
  • /send off — fuer diese Session verweigern
  • /send inherit — Override loeschen und Config-Regeln verwenden Sende diese als eigenstaendige Nachrichten, damit sie registriert werden.

Konfiguration (optionales Umbenennungsbeispiel)

// ~/.openclaw/openclaw.json
{
  session: {
    scope: "per-sender", // Gruppen-Keys separat halten
    dmScope: "main", // DM-Kontinuitaet (fuer Shared Inboxes per-channel-peer/per-account-channel-peer setzen)
    identityLinks: {
      alice: ["telegram:123456789", "discord:987654321012345678"],
    },
    reset: {
      // Standards: mode=daily, atHour=4 (Gateway-Host-Ortszeit).
      // Wenn du zusaetzlich idleMinutes setzt, gewinnt der zuerst ablaufende.
      mode: "daily",
      atHour: 4,
      idleMinutes: 120,
    },
    resetByType: {
      thread: { mode: "daily", atHour: 4 },
      direct: { 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",
  },
}

Inspektion

  • openclaw status — zeigt Store-Pfad und aktuelle Sessions.
  • openclaw sessions --json — gibt jeden Eintrag aus (filtern mit --active <minutes>).
  • openclaw gateway call sessions.list --params '{}' — Sessions vom laufenden Gateway abrufen (nutze --url/--token fuer Remote-Gateway-Zugriff).
  • Sende /status als eigenstaendige Nachricht im Chat, um zu sehen, ob der Agent erreichbar ist, wie viel des Session-Kontexts belegt ist, aktuelle Thinking/Fast/Verbose-Toggles und wann deine WhatsApp-Web-Credentials zuletzt aktualisiert wurden (hilft bei der Erkennung, wann ein Relink noetig ist).
  • Sende /context list oder /context detail, um zu sehen, was im System-Prompt und den injizierten Workspace-Dateien steckt (und die groessten Kontext-Verbraucher).
  • Sende /stop (oder eigenstaendige Abbruchphrasen wie stop, stop action, stop run, stop openclaw), um den aktuellen Lauf abzubrechen, eingereihte Followups fuer diese Session zu loeschen und Sub-Agent-Laeufe zu stoppen, die davon gestartet wurden (die Antwort enthaelt die Anzahl gestoppter Laeufe).
  • Sende /compact (optionale Anweisungen) als eigenstaendige Nachricht, um aelteren Kontext zusammenzufassen und Fensterplatz freizugeben. Siehe /concepts/compaction.
  • JSONL-Transkripte koennen direkt geoeffnet werden, um vollstaendige Runden zu pruefen.

Tipps

  • Halte den primaeren Key fuer 1:1-Traffic reserviert; lass Gruppen ihre eigenen Keys behalten.
  • Wenn du Bereinigung automatisierst, loesche einzelne Keys statt den ganzen Store, um Kontext anderswo zu erhalten.

Session-Origin-Metadaten

Jeder Session-Eintrag zeichnet auf, woher er stammt (Best-Effort) in origin:

  • label: menschenlesbares Label (aufgeloest aus Gespraechslabel + Gruppenbetreff/Kanal)
  • provider: normalisierte Kanal-ID (einschliesslich Erweiterungen)
  • from/to: Roh-Routing-IDs aus dem eingehenden Envelope
  • accountId: Provider-Account-ID (bei Multi-Account)
  • threadId: Thread-/Topic-ID, wenn der Kanal sie unterstuetzt Die Origin-Felder werden fuer Direktnachrichten, Kanaele und Gruppen befuellt. Wenn ein Connector nur das Delivery-Routing aktualisiert (zum Beispiel um eine DM-Hauptsession aktuell zu halten), sollte er trotzdem eingehenden Kontext liefern, damit die Session ihre Erklaerungsmetadaten behaelt. Erweiterungen koennen das tun, indem sie ConversationLabel, GroupSubject, GroupChannel, GroupSpace und SenderName im eingehenden Kontext senden und recordSessionMetaFromInbound aufrufen (oder denselben Kontext an updateLastRoute uebergeben).