Skip to content

[Bug]: Provider refresh does not update cached skills after installing skills or plugins #11497

Description

@BradyHazell

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. Connect a T3 Code client to a remote T3 server.
  2. Open a project and let its skill list load.
  3. Install a new skill on the remote machine under the same account and provider home.
  4. In the local client, select the remote environment in Settings > Providers and click Refresh provider status.
  5. Return to the same project and check the skill menu.

Expected behavior

Refreshing the provider makes newly installed skills available in the project’s skill menu without restarting the remote server.

Actual behavior

Newly installed remote skills remain missing from the local client and only seem to appear after restarting the T3 code server on the remote machine.

Impact

Minor bug or occasional failure

Version or commit

0.0.41-nightly.20260911.1520

Environment

No response

Logs or stack traces

Screenshots, recordings, or supporting files

No response

Workaround

Restart the remote T3 server, or disable and re-enable the affected provider in the remote environment’s settings, then reopen the project.

Activity

  1. added
    bugSomething is broken or behaving incorrectly.
    needs-triageIssue needs maintainer review and initial categorization.
    on Sep 13, 2026
  2. fionn77 commented on Sep 13, 2026

    @fionn77

    Additional evidence from T3 0.0.40 on a remote Linux server using Codex:

    The new skill existed on disk and a fresh codex app-server skills/list request, using the same account home and cwd as T3, returned it with enabled: true and no discovery errors. We checked both configured Codex account homes. The existing project's $ picker still omitted it after a client restart.

    Inspection of the installed 0.0.40 bundle identifies a workspace-cache path that can explain this:

    • refreshWorkspaceSnapshot returns immediately when provider.workspaceSnapshots already contains the requested cwd.
    • mergeProviderSnapshot preserves the previous workspaceSnapshots when a fresh provider snapshot does not supply them.
    • resolveProviderSkillsForCwd prefers the matching workspace snapshot over the provider's global skills.

    An isolated execution of the installed mergeProviderSnapshot function reproduced the mismatch: start with an empty cached workspace list, merge a fresh provider list containing a new enabled skill, and the global list contains the skill while the effective workspace list remains empty. This is a synthetic merge reproduction, not an end-to-end UI test.

    We restarted the remote T3 service successfully. Post-restart picker confirmation is still pending, so we are not claiming an independently verified UI recovery. No installed vendor code was modified.

    Investigated with GPT-6 through Codex in T3 Code.

  3. full-poulet commented on Sep 19, 2026

    @full-poulet

    Hi, I'm Fable, an AI assistant, writing on behalf of @full_poulet. Confirming this bug for the Claude provider (the report above and the existing evidence are Codex), with the mechanism from the installed bundle.

    Setup: T3 Code 0.0.40 on a headless Ubuntu server (t3 serve, web client over Tailscale). Claude skills are symlinks in ~/.claude/skills/<name>/ pointing into a git checkout.

    What happened

    • Server started 2026-09-16 11:18. A new skill was linked into ~/.claude/skills on 2026-09-18 16:58.
    • On 2026-09-19 the / picker in a project that had been open since before the 18th still did not list it. Typing /spiegel-spesenabrechnung by hand worked and the skill body was expanded, so the server-side scan at send time sees it.
    • The picker updated only when the thread's cwd changed (the project folder moved): a new cwd has no workspace snapshot, so the client requested one and it was built from a fresh discoverClaudeSkills. ~/.t3/caches/claudeAgent.json was rewritten at that moment and contains the skill.

    Where it sticks (0.0.40 bin.mjs, matches what @fionn77 found for Codex)

    • ClaudeDriver.snapshotForCwd = { ...machineSnapshot, skills: discoverClaudeSkills(config, cwd) }. The user-scope folder is only rescanned as part of a workspace snapshot.
    • The client (ChatView) requests server.refreshProviders with cwd only when workspaceSnapshots has no entry for that cwd, and stops once one exists.
    • Background health refreshes and the explicit "Refresh provider status" replace the machine snapshot and keep workspaceSnapshots, so an existing project's list is never rebuilt.

    Workarounds (as also noted in #11575): change any Claude provider setting in Settings > Providers and change it back, which rebuilds the instance and drops the workspace snapshots, or type the full /name. Restart works too. "Refresh provider status" alone does not.

    PR #11532 (invalidate workspace catalogs on explicit refresh) was closed without merging, so this is still open on 0.0.42 as far as I can tell. For people who add skills several times a week, having the picker rescan on open, or at least on explicit refresh, would remove the confusion.

  4. Zane-0x5a commented on Sep 25, 2026

    @Zane-0x5a

    Confirming this on 0.0.42 stable (Windows 11 desktop app, Claude provider, Claude Code 2.1.281). The 0.0.42 bin.mjs has the same paths described above: refreshWorkspaceSnapshot returns early once the cwd has a workspace snapshot, mergeProviderSnapshot carries the old workspaceSnapshots forward, and ChatView only requests a cwd refresh while no snapshot exists.

    One path the open PRs don't cover: running /reload-skills doesn't refresh the picker either. It's Claude Code's built-in command for picking up skills added mid-session, so it's the first thing users reach for. After running it, the skill picker still shows the old list.

    • The bundled Agent SDK exposes Query.reloadSkills() (control request reload_skills, which responds with the refreshed skill list). Apart from the SDK's own definition, nothing in the 0.0.42 server or client bundle references reloadSkills or reload_skills, so a /reload-skills turn never invalidates the cwd's workspace snapshot.
    • The Claude adapter already calls discoverClaudeSkills(settings, session.cwd) at the start of every turn to build skillNames, which is why typing the full /name works. That fresh list is discarded instead of being compared with the held workspace snapshot.

    #12672 (file watcher) and #13251 (rebuild on provider refresh) would each fix the stale list, but neither diff touches /reload-skills. It would still help to treat a /reload-skills (and /reload-plugins) turn as an explicit invalidation for that cwd, e.g. by calling query.reloadSkills() and publishing the result, or by reusing the per-turn scan above. Then the command does what users expect without waiting for a watcher event or the next 5-minute health check.

    Investigated with Claude Code.

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

    bugSomething is broken or behaving incorrectly.needs-triageIssue needs maintainer review and initial categorization.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions