Skip to content

Bug: Skills snapshot not refreshed for existing sessions after gateway restart #49059

@rivercrab26

Description

@rivercrab26

Bug: Skills snapshot not refreshed for existing sessions after gateway restart

Summary

When new skills are installed while the gateway is running, existing sessions continue using a stale skill snapshot even after gateway restart. Only new sessions (created after skill installation) see the updated skill list. This is caused by two interacting issues in the snapshot version system.

Steps to Reproduce

  1. Start the gateway with N skills installed
  2. Create a session (e.g., Discord channel) — session captures snapshot with N skills
  3. Install a new skill (e.g., clawhub install <skill>) — watcher bumps workspaceVersions
  4. Restart the gateway
  5. Send a message in the existing session
  6. Observe: session still shows N skills, not N+1
  7. Create a new session (/new or new channel) — shows N+1 skills ✅

Root Cause

There are two code paths for skill snapshot refresh, both affected:

Path A — manager.runtime-CXnMXwZT.js (general channels)

const needsSkillsSnapshot = isNewSession || !sessionEntry?.skillsSnapshot;
const skillsSnapshotVersion = getSkillsSnapshotVersion(workspaceDir);
const skillsSnapshot = needsSkillsSnapshot 
    ? buildWorkspaceSkillSnapshot(workspaceDir, { snapshotVersion, ... })
    : sessionEntry?.skillsSnapshot;  // ← reuses old snapshot, no version check

Problem: No version comparison at all. If sessionEntry.skillsSnapshot exists, it's always reused regardless of whether the skill list has changed.

Path B — discord-CcCLMjHw.js (Discord-specific, ensureSkillSnapshot)

const snapshotVersion = getSkillsSnapshotVersion(workspaceDir);
ensureSkillsWatcher({ workspaceDir, config: cfg });
const shouldRefreshSnapshot = snapshotVersion > 0 
    && (nextEntry?.skillsSnapshot?.version ?? 0) < snapshotVersion;

Problem: globalVersion (module-level variable) resets to 0 on process start:

// model-selection-46xMp11W.js
let globalVersion = 0;  // ← reset every restart

function getSkillsSnapshotVersion(workspaceDir) {
    const local = workspaceVersions.get(workspaceDir) ?? 0;
    return Math.max(globalVersion, local);  // ← returns 0 after restart
}

After restart: getSkillsSnapshotVersion() returns 0 → snapshotVersion > 0 is false → shouldRefreshSnapshot is always false.

The file watcher (ensureSkillsWatcher) would bump the version on file changes, but:

  • It uses ignoreInitial: true (correct — avoids false triggers on startup)
  • If the skill was installed before restart, the watcher won't detect a change
  • So globalVersion stays 0, and the snapshot is never refreshed

Impact

  • Any user who installs a new skill and restarts the gateway will find their existing sessions don't see the new skills
  • The workaround is to manually delete skillsSnapshot from all sessions in sessions.json, or use /new//reset on each session
  • With many sessions (e.g., 58 in our setup), this is impractical

Additional Issues

  1. Two code paths with different behavior: Path A completely ignores versions, Path B tries but fails due to globalVersion = 0. All channels should follow the same refresh logic.

  2. Per-session snapshot duplication: Each session stores its own copy of skillsSnapshot (~11.5KB). With N sessions, this is N × 11.5KB of identical data. This should be a shared reference per agent.

  3. No startup diff check: The system has no mechanism to compare the current skill list against stored snapshots at startup. A simple hash comparison on startup would catch staleness.

Proposed Fixes

  1. Persist globalVersion — Write it to sessions.json or a separate file so it survives restarts
  2. Add startup diff check — On gateway start, compute a hash of the current skill list. If it differs from any session's snapshot, bump the version
  3. Unify code paths — Path A should also check version, not just isNewSession || !snapshot
  4. Remove the snapshotVersion > 0 guard — Or at least handle the cold-start case where version is 0 but snapshot may be stale
  5. Store snapshot per-agent, not per-session — Share a single snapshot reference across all sessions for the same agent

Version

OpenClaw 2026.3.13 (also present in 2026.3.8, likely earlier)

Environment

  • macOS (arm64)
  • Node.js v25.8.1
  • Discord channel integration
  • Skills installed via clawhub install

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions