[Bug]: Workspace snapshot taken before the first Claude probe finishes leaves the / menu without provider commands for the whole session
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 23k
- Forks
- 5.9k
- Avg merge
- 11h 14m
- Merged PRs (30d)
- 357
Description
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
- 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-pluginorexpo@claude-plugins-officialin~/.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. - Quit T3 Code. Launch it again so it restores the last open thread for a local checkout.
- Once the thread is visible, type
/followed by the first letters of a plugin command, for example/comp. - Compare with a thread whose project or worktree is opened for the first time a few seconds after launch. Type
/compthere.
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.tspassesmakePendingClaudeProvideras the managed provider'sinitialSnapshot. That placeholder has noslashCommands(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) callsClaudeDriver.snapshotForCwd(ClaudeDriver.ts:234), which is{ ...snapshot.getSnapshot, skills }. When the firstcheckClaudeProviderStatushas not finished,getSnapshotis still the placeholder, soupsertProviderWorkspaceSnapshot(ProviderRegistry.ts:83) storesslashCommands: []for that cwd. refreshWorkspaceSnapshotreturns 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:
- #7111 covers a failed probe emptying the list. Here the probe succeeds; the workspace snapshot is simply taken before it returns.
- #5622 covers plugin skills missing from the
$picker. That is the filesystem-only skill discovery and is unaffected by this race. - #11497 reports that a provider refresh does not update cached workspace skills. It is likely the same "workspace snapshot is never revisited" rule, seen from the refresh side.
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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in apps/server's ProviderRegistry.ts around refreshWorkspaceSnapshot and upsertProviderWorkspaceSnapshot, then trace ClaudeDriver.ts snapshotForCwd and the pending snapshot in ClaudeProvider.ts. Read packages/client-runtime/src/providerSkills.ts to understand workspace-versus-machine resolution. Done means a workspace opened during the initial probe eventually exposes the provider and plugin slash commands, with coverage for the launch race.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100