Skip to content

[Bug]: Workspace snapshot taken before the first Claude probe finishes leaves the / menu without provider commands for the whole session #11575

Description

@rutefig

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. Use the Claude provider on the desktop app, local connection, with at least one Claude Code plugin enabled at user scope (for example compound-engineering@compound-engineering-plugin or expo@claude-plugins-official in ~/.claude/settings.json). Any user-scope skill or command that only reaches T3 through the capability probe works the same way; plugin commands are just the easiest to notice.
  2. Quit T3 Code. Launch it again so it restores the last open thread for a local checkout.
  3. Once the thread is visible, type / followed by the first letters of a plugin command, for example /comp.
  4. Compare with a thread whose project or worktree is opened for the first time a few seconds after launch. Type /comp there.

Expected behavior

The / menu for the thread that was open at launch lists the provider commands from the capability probe, including the plugin:skill entries such as /compound-engineering:ce-plan, exactly like the thread opened later.

Actual behavior

The thread that was open at launch never shows any provider commands. Only the built-ins and the /skill: entries from ~/.claude/skills appear, and it stays that way for the whole process lifetime. Threads whose cwd is first opened after the first health check completes are fine.

Mechanism, verified on main @ 20363c3:

  • ClaudeDriver.ts passes makePendingClaudeProvider as the managed provider's initialSnapshot. That placeholder has no slashCommands (ClaudeProvider.ts, "Claude provider status has not been checked in this session yet").
  • The client requests a workspace snapshot for the thread's cwd as soon as the thread mounts. ProviderRegistry.refreshWorkspaceSnapshot (ProviderRegistry.ts:806) calls ClaudeDriver.snapshotForCwd (ClaudeDriver.ts:234), which is { ...snapshot.getSnapshot, skills }. When the first checkClaudeProviderStatus has not finished, getSnapshot is still the placeholder, so upsertProviderWorkspaceSnapshot (ProviderRegistry.ts:83) stores slashCommands: [] for that cwd.
  • refreshWorkspaceSnapshot returns early whenever a snapshot for the cwd already exists (ProviderRegistry.ts:812-818), and the periodic health check only replaces the machine-level snapshot. Nothing ever revisits the workspace snapshot, so the empty list is permanent until the instance is rebuilt.
  • The client prefers the workspace snapshot over the machine snapshot (packages/client-runtime/src/providerSkills.ts, resolveProviderSlashCommandsForCwd), which is why the correct machine-level list is never used for that thread.

Span timings from ~/.t3/userdata/logs/server.trace.ndjson for one launch (T3 desktop 0.0.40):

11:12:10.066 -> 11:12:11.128  checkClaudeProviderStatus   (first probe, machine snapshot)
11:12:10.803 -> 11:12:10.809  refreshWorkspaceSnapshot    (workspace snapshot taken from the placeholder)
11:12:10.804 -> 11:12:10.809  discoverClaudeSkills

After the probe finished, ~/.t3/caches/claudeAgent.json held 141 slash commands (81 of them plugin:skill entries), while the / menu for the thread still had none. Running the same probe by hand (initialize control request with --setting-sources user,project,local) also returns the full list, so Claude Code itself is not at fault.

Related but distinct:

Impact

Minor bug or occasional failure.

It hits every launch for whichever thread is restored first, so for a single-project user it looks permanent: "T3 does not see my plugins", even though the runtime session has them and typing the full /plugin:skill command works.

Version or commit

T3 Code desktop (Alpha) 0.0.40, reproduced against main @ 20363c3 by reading the same code paths.

Environment

macOS 26.5 (Darwin 25.5.0), T3 Code desktop 0.0.40, local connection, Claude Code CLI 2.1.270, @anthropic-ai/claude-agent-sdk 0.3.260 (per CLAUDE_AGENT_SDK_VERSION on the spawned process).

Logs or stack traces

None beyond the spans above. Nothing is logged because every step succeeds; the placeholder is a valid snapshot.

Workaround

Change any Claude provider setting in Settings > Providers and change it back. The instance rebuild drops the workspace snapshots, and the next thread mount rebuilds them from the populated machine snapshot. Alternatively, type the full command at the start of the message, for example /compound-engineering:ce-plan; the server forwards it to Claude Code unchanged.

Possible fixes: have refreshWorkspaceSnapshot wait for the first checkProvider to complete (or skip storing a snapshot while the machine snapshot is still the pending placeholder), and refresh existing workspace snapshots whenever the machine-level slashCommands change.

Activity

  1. juliusmarminge commented on Sep 13, 2026

    @juliusmarminge
    Member

    Thanks for the unusually precise write-up — the race is real on current main (20363c3).

    Confirmed. The restored thread mounts and asks for a workspace snapshot while Claude’s managed provider is still makePendingClaudeProvider (slashCommands: [], “status has not been checked in this session yet”). ClaudeDriver.snapshotForCwd copies that placeholder and only overlays filesystem skills, so upsertProviderWorkspaceSnapshot stores an empty command list for that cwd. refreshWorkspaceSnapshot then returns early whenever a snapshot for the cwd already exists, and background health checks only replace the machine-level snapshot (mergeProviderSnapshot keeps workspaceSnapshots). The client prefers the workspace list (resolveProviderSlashCommandsForCwd), and also stops retrying once any snapshot exists. That is why later-opened threads are fine and the restored one is stuck for the process lifetime.

    Error snapshots are already discarded (scopedSnapshot.status === "error"). The pending probe is warning + installed: false, so it is treated as a valid catalog.

    Surfaces

    • Web/desktop / menu: affected (composer uses the cwd resolver).
    • Mobile: currently reads machine-level slashCommands, so it may recover after the probe. feat(providers): expose native slash commands across clients #11519 would put mobile on the same resolver and inherit this.
    • Other drivers use the same { ...getSnapshot, skills } cwd snapshot. Claude is the worst case because plugin:skill entries only arrive from the capability probe.
    • Remote/relay: same server-side race.

    Related, not duplicates

    Fix (server, not client)

    1. Do not store a workspace snapshot while the machine snapshot is still the pending placeholder (same shape as the existing error skip). Clients already retry when no snapshot exists.
    2. When machine-level slashCommands change, refresh or patch existing workspace snapshots for that instance.

    Workaround stands: toggle a Claude setting (instance rebuild drops workspace snapshots) or type the full /plugin:skill command.

    Accepting as a bug. A follow-up PR should add a ProviderRegistry regression for “cwd snapshot taken during pending probe, then probe completes.”

  2. added
    bugSomething is broken or behaving incorrectly.
    acceptedfeature request accepted
    via-triageFiled through npx t3 triage
    on Sep 13, 2026
  3. 53able commented on Oct 4, 2026

    @53able

    On T3 Code desktop 0.0.45, typing /mattpocock-skills: in a Claude thread shows “No matching command,” even though T3’s persisted machine-level cache contains 25 commands from that plugin.

    Claude thread showing No matching command for /mattpocock-skills:

    Environment

    • macOS 26.7 (25G229), arm64
    • Claude Code 2.1.289; the thread uses Claude Opus 5.5
    • mattpocock-skills@claude-plugins-official 1.2.3, installed at user scope and enabled in ~/.claude/settings.json
    • T3 Claude instance: binaryPath: "claude", homePath: ""
    • “Show skills in slash menu” is enabled

    Cache evidence

    Read-only inspection of ~/.t3/caches/claudeAgent.json found status: "ready" and 436 slashCommands, including:

    mattpocock-skills:ask-matt
    mattpocock-skills:diagnosing-bugs
    mattpocock-skills:tdd
    

    The cache’s checkedAt is 2026-10-04T05:28:52.166Z, before the screenshot’s filename timestamp of 14:36:39 local time. The packaged backend’s cwd is the user’s home directory.

    This report concerns / autocomplete. The cache also lacks plugin entries in its filesystem skills list, matching the separate $ picker report in #5622.

    The populated machine-level cache and empty menu fit the catalog mismatch described here, but I have not captured the affected workspace’s live snapshot or reproduced the startup race. Restart behavior and full command execution remain untested. These checks were AI-assisted and read-only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions