pingdotgg / pingdotgg/t3code

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

Open
#11,575 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

accepted bug via-triage
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
  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:

  • #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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.