openclaw - 💡(How to fix) Fix claude-cli resume binding survives long-lived session lifecycle and can bypass compaction

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Long-lived interactive sessions backed by claude-cli can retain stale CLI resume bindings (cliSessionBindings, cliSessionIds, and legacy claudeCliSessionId) across the OpenClaw session lifecycle. In practice this can make Claude CLI keep resuming an old internal Claude conversation while OpenClaw reports no compaction and does not reliably enforce its normal context lifecycle.

This appears to be a lifecycle/invariant gap around CLI backend session bindings rather than a single bad local session.

Root Cause

  • Fresh/new/reset session entries should not carry forward:
    • cliSessionBindings
    • cliSessionIds
    • claudeCliSessionId
  • liveModelSwitchPending should not remain stuck indefinitely after the switch lifecycle completes or fails.
  • Old Claude CLI resume ids should have an explicit TTL or invalidation rule for long-lived interactive sessions.
  • CLI backend compaction/memory lifecycle limitations should be documented or guarded because OpenClaw docs currently note that some compaction memory-flush housekeeping only applies to embedded Pi sessions, while CLI backends skip that path.

Fix Action

Fix / Workaround

Local mitigation

As a local safety guard, I added a scheduled script outside OpenClaw runtime that scans long-lived interactive sessions and clears Claude CLI bindings when the session is older than two days or liveModelSwitchPending is stuck. This is only a workaround; it should not be necessary if the runtime enforces the lifecycle invariant above.

Code Example

{
  "agents": {
    "defaults": {
      "compaction": { "mode": "safeguard" },
      "cliBackends": {
        "claude-cli": {
          "resumeArgs": ["-p", "--output-format", "stream-json", "--include-partial-messages", "--verbose", "--resume", "{sessionId}"],
          "sessionArg": "--session-id",
          "sessionMode": "existing",
          "systemPromptWhen": "first",
          "serialize": true
        }
      }
    }
  }
}

---

{
  "cliSessionIds": { "claude-cli": "<uuid>" },
  "cliSessionBindings": {
    "claude-cli": {
      "sessionId": "<uuid>",
      "authProfileId": "anthropic:claude-cli",
      "authEpochVersion": 4,
      "extraSystemPromptHash": "<hash>",
      "mcpConfigHash": "<hash>",
      "mcpResumeHash": "<hash>"
    }
  },
  "claudeCliSessionId": "<uuid>",
  "liveModelSwitchPending": true
}
RAW_BUFFERClick to expand / collapse

Summary

Long-lived interactive sessions backed by claude-cli can retain stale CLI resume bindings (cliSessionBindings, cliSessionIds, and legacy claudeCliSessionId) across the OpenClaw session lifecycle. In practice this can make Claude CLI keep resuming an old internal Claude conversation while OpenClaw reports no compaction and does not reliably enforce its normal context lifecycle.

This appears to be a lifecycle/invariant gap around CLI backend session bindings rather than a single bad local session.

Environment

  • OpenClaw version: 2026.5.18 (50a2481)
  • Install method: npm global
  • Gateway/runtime: Linux, Node v22.22.2
  • Channel: WhatsApp group sessions and other long-lived interactive sessions
  • Backend/model involved: claude-cli/claude-haiku-4-5, claude-cli/claude-sonnet-4-6
  • Relevant config:
{
  "agents": {
    "defaults": {
      "compaction": { "mode": "safeguard" },
      "cliBackends": {
        "claude-cli": {
          "resumeArgs": ["-p", "--output-format", "stream-json", "--include-partial-messages", "--verbose", "--resume", "{sessionId}"],
          "sessionArg": "--session-id",
          "sessionMode": "existing",
          "systemPromptWhen": "first",
          "serialize": true
        }
      }
    }
  }
}

What happened

A long-lived WhatsApp group session using Claude CLI reached an apparent context overrun without OpenClaw compaction firing:

  • Session key: agent:zafer:whatsapp:group:<redacted>.g.us
  • totalTokens: 648974
  • contextTokens: 200000
  • about 324% of the configured context window
  • compactionCount: 0
  • model: claude-haiku-4-5
  • liveModelSwitchPending: true
  • stale Claude CLI binding present:
{
  "cliSessionIds": { "claude-cli": "<uuid>" },
  "cliSessionBindings": {
    "claude-cli": {
      "sessionId": "<uuid>",
      "authProfileId": "anthropic:claude-cli",
      "authEpochVersion": 4,
      "extraSystemPromptHash": "<hash>",
      "mcpConfigHash": "<hash>",
      "mcpResumeHash": "<hash>"
    }
  },
  "claudeCliSessionId": "<uuid>",
  "liveModelSwitchPending": true
}

Clearing cliSessionIds, cliSessionBindings, claudeCliSessionId, and liveModelSwitchPending forced the next Claude CLI interaction to start fresh, which mitigated the issue.

A broader audit found 14 long-lived interactive session records across multiple agents with either stale Claude CLI bindings or stuck liveModelSwitchPending state. These were not isolated one-shot jobs; they were interactive sessions such as WhatsApp, TUI, dashboard, and main sessions.

Expected behavior

When OpenClaw creates a genuinely new interactive session or performs a session reset, the new session should not inherit an old CLI backend resume id unless the user explicitly requested backend session preservation.

For claude-cli, a new OpenClaw session should mean a new Claude CLI session by default.

More concretely:

  • Fresh/new/reset session entries should not carry forward:
    • cliSessionBindings
    • cliSessionIds
    • claudeCliSessionId
  • liveModelSwitchPending should not remain stuck indefinitely after the switch lifecycle completes or fails.
  • Old Claude CLI resume ids should have an explicit TTL or invalidation rule for long-lived interactive sessions.
  • CLI backend compaction/memory lifecycle limitations should be documented or guarded because OpenClaw docs currently note that some compaction memory-flush housekeeping only applies to embedded Pi sessions, while CLI backends skip that path.

Actual behavior

The session store can keep a Claude CLI resume id on long-lived interactive sessions. Claude CLI then receives --resume <sessionId> and may continue its own internal conversation even when OpenClaw’s normal transcript/context lifecycle is not being compacted as expected.

This can make context pressure invisible or misleading from OpenClaw’s perspective and can lead to stale, overgrown Claude CLI-backed sessions.

Why this seems upstream rather than local-only

Installed runtime code already has primitives like clearAllCliSessions(entry) / clearCliSession(entry, provider), and /reset soft appears to clear CLI session state correctly in one path. But other lifecycle paths appear to copy or preserve these fields. For example, installed dist paths referenced cliSessionBindings, cliSessionIds, and claudeCliSessionId being carried from existing entries in session reset / reply preparation paths.

Related upstream issues suggest this area is already fragile:

  • #62708: legacy claudeCliSessionId cleanup
  • #77974: Claude CLI context loss from resume/transcript race
  • #79047: backend-specific continuity via cliSessionBindings.claude-cli.sessionId
  • #56072: daily reset lifecycle/context preservation gap
  • #61426: isolated session leakage causing context accumulation
  • #40941: missing context accounting can break compaction expectations

This issue is specifically about stale Claude CLI resume bindings surviving long-lived/new/reset session lifecycle boundaries and allowing Claude CLI to bypass the intended OpenClaw context lifecycle.

Suggested fix

  1. Define and enforce a runtime invariant:

    • A newly created OpenClaw session entry must start with empty CLI backend bindings unless explicitly preserving backend state.
  2. Audit lifecycle paths that create/copy session entries and call clearAllCliSessions() where appropriate:

    • new session
    • hard reset
    • daily/idle stale session reset
    • session reset service rollover
    • any code path that snapshots/copies baseEntry into a fresh entry
  3. Add a TTL/invalidation policy for long-lived interactive CLI bindings:

    • e.g. reset cliSessionBindings[provider] if the OpenClaw session is older than session.cliBindings.maxAgeMs
    • default could be conservative or configurable
    • one-shot isolated jobs/subagents can keep their current behavior if intentional
  4. Ensure liveModelSwitchPending is finalized or cleaned up when a model switch succeeds/fails, so it does not leave sessions in a permanently ambiguous state.

  5. Add tests:

    • /new or equivalent fresh session does not copy cliSessionBindings / cliSessionIds / claudeCliSessionId
    • daily/idle reset does not preserve CLI bindings into the fresh session
    • same OpenClaw session can still reuse Claude CLI normally before TTL
    • after TTL or reset, Claude CLI runs without --resume and stores a new binding
    • isolated cron/sub-agent behavior remains explicit and unchanged

Local mitigation

As a local safety guard, I added a scheduled script outside OpenClaw runtime that scans long-lived interactive sessions and clears Claude CLI bindings when the session is older than two days or liveModelSwitchPending is stuck. This is only a workaround; it should not be necessary if the runtime enforces the lifecycle invariant above.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

When OpenClaw creates a genuinely new interactive session or performs a session reset, the new session should not inherit an old CLI backend resume id unless the user explicitly requested backend session preservation.

For claude-cli, a new OpenClaw session should mean a new Claude CLI session by default.

More concretely:

  • Fresh/new/reset session entries should not carry forward:
    • cliSessionBindings
    • cliSessionIds
    • claudeCliSessionId
  • liveModelSwitchPending should not remain stuck indefinitely after the switch lifecycle completes or fails.
  • Old Claude CLI resume ids should have an explicit TTL or invalidation rule for long-lived interactive sessions.
  • CLI backend compaction/memory lifecycle limitations should be documented or guarded because OpenClaw docs currently note that some compaction memory-flush housekeeping only applies to embedded Pi sessions, while CLI backends skip that path.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix claude-cli resume binding survives long-lived session lifecycle and can bypass compaction