pingdotgg / pingdotgg/t3code

[Bug]: One failed Claude capability probe empties the slash-command menu for 5 minutes and persists the empty list

Open
#7,111 1 comment 0 reactions 0 assignees View on GitHub

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
  1. Use the Claude provider on the desktop app, local connection, with skills or custom commands in ~/.claude/skills.

  2. Open a thread and type /. Confirm the Provider group lists your commands.

  3. Make the next capability probe unreadable. Save this as /tmp/slow-claude, chmod +x it, and set Settings → Providers → Claude → Binary path to it:

    #!/bin/sh
    for arg in "$@"; do
      case "$arg" in
        --version|auth) exec /usr/local/bin/claude "$@" ;;
      esac
    done
    sleep 60
    

    --version still answers, so the provider stays installed and the run reaches the capability probe. The SDK call then exceeds the 25-second timeout.

  4. Wait for the next probe, up to 5 minutes.

  5. Type / again.

In normal use no wrapper is needed. Any spawn failure or a probe slower than 25 seconds does the same thing — that is how I hit it.

Expected behavior

A probe that cannot be read leaves the known command list alone. The / menu keeps listing the provider commands from the last good probe.

Actual behavior

The Provider group is empty. Only the built-in /model, /plan, and /default remain, for at least 5 minutes, and the empty list is written to ~/.t3/caches/claudeAgent.json, so a restart does not clear it. It recovers only when a later probe succeeds.

The mechanism: probeClaudeCapabilities maps a failure or a 25-second timeout (CAPABILITIES_PROBE_TIMEOUT_MS) to undefined. In checkClaudeProviderStatus (apps/server/src/provider/Layers/ClaudeProvider.ts:930) that becomes

const slashCommands = capabilities?.slashCommands ?? [];

which reads "the CLI was unreadable this time" as "the CLI has no commands". ClaudeDriver caches that undefined for the full CAPABILITIES_PROBE_TTL of 5 minutes (ClaudeDriver.ts:156-163), and ProviderRegistry.persistProvider writes every published snapshot to the status cache unconditionally (ProviderRegistry.ts:311-330), so the empty list outlives the process. Nothing keeps the previous value: makeManagedServerProvider holds no prior snapshot.

Impact

Minor bug or occasional failure.

Occasional, but total while it lasts: every provider slash command disappears at once, which reads as "T3 Code lost my skills" rather than as a transient probe failure.

Version or commit

main @ ad117235b

Environment

macOS 26.0 (Darwin 27.0.0), T3 Code desktop dev build, Node v26.5.0, Claude Code CLI 2.1.233, @anthropic-ai/claude-agent-sdk 0.3.170, local connection.

Logs or stack traces

None. The failure is silent: probeClaudeCapabilities swallows the error via Effect.result, and the probe's stderr handler is () => {}, so nothing reaches the log.

Workaround

Wait for a probe to succeed, up to 5 minutes. A restart alone does not help, because the cached empty list is reloaded.


I have a fix and will open a pull request against this issue: keep the slash commands from the last probe that succeeded, and use them when a probe reports no capabilities. Auth still reports warning / unknown, so only the command list is reused.

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 with probeClaudeCapabilities and the referenced sections of apps/server/src/provider/Layers/ClaudeProvider.ts, ClaudeDriver.ts, and ProviderRegistry.ts. Trace how a failed probe becomes a published and persisted snapshot, then reproduce the timeout case. Done means the last successful slash-command list remains available after a failed probe and is not replaced by an empty cached list.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.