Skip to content

[Bug]: Claude project skills missing from picker after worktree cleanup #32459

Closed

Description

@beastyrabbit

Note

🤖 Claude Opus 5.5 responding on behalf of beastyrabbit

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 a project that commits a Claude project skill, e.g. .claude/skills/finalize/SKILL.md.
  2. Run a Claude thread in a managed worktree and let the turn finish.
  3. Let storage cleanup remove the worktree (here storageCleanup.worktreeUnchanged: true), or run git worktree remove by hand. Wait for any cached workspace snapshot to expire (5 min).
  4. Open the thread and type $ in the composer.

Expected behavior

The picker lists the project's skills. The thread's branch still exists and turn start already restores the worktree, so a missing folder should not make the project's skills disappear.

Actual behavior

The picker lists user-level skills only, with no error. With the skill missing from the picker, I entered finalize. The provider received the literal text finalize, without native skill dispatch. Turn start then recreated the worktree (provider turn start recreating missing worktree).

This happened twice in the same project, on 2026-11-05 and 2026-11-07, both times after cleanup had removed the thread's worktree.

Cause

probeClaudeWorkspaceSnapshot handles a missing cwd on purpose and returns a finished snapshot (ClaudeProvider.ts:486-510):

// A deleted worktree can never answer the probe. Pending would make clients rescan it forever.
const cwdExists = yield* fileSystem.exists(cwd).pipe(Effect.orElseSucceed(() => true));
...
slashCommandsPending: cwdExists && !capabilities,

discoverClaudeSkills resolves the project's .claude/skills under that missing cwd (ClaudeSkills.ts:512), so the snapshot has no project skills. Because slashCommandsPending is false, the client treats that snapshot as complete. The worktree is recreated only in ProviderTurnStartService (ProviderTurnStartService.ts:647), after the user has already written the message.

Impact

Minor bug or occasional failure. It happens when cleanup removes an eligible worktree and the composer discovers skills before the worktree is restored.

Version or commit

0.1.7 (server). The same code is on main @ 9f00ced.

Environment

Linux 7.0, web UI, Claude Code 2.1.319, Node 26.8. storageCleanup: worktreeUnchanged: true, worktreeSettledAfterDays: 14. Reproduced with the Claude provider only; Codex uses a separate discovery path and was not tested.

Logs or stack traces

# Relevant events from the server trace, boot log and Claude provider log, 2026-11-07 UTC
11:41:01.778 refreshWorkspaceSnapshot > probeClaudeWorkspaceSnapshot   Success
11:41:01.781 projects.readFile 't3.json'   Failure: 'realpath-workspace-root' failed at '~/.t3/worktrees/cowork/t3-bd52ae66'
11:41:14.539 WARN provider turn start recreating missing worktree { worktreePath: '~/.t3/worktrees/cowork/t3-bd52ae66' }
11:41:18.338 prompt.offer { content: "finalize" }
11:41:20.074 refreshWorkspaceSnapshot > probeClaudeWorkspaceSnapshot   (after recreation; what the picker showed then was not captured)

Workaround

Send any message first so turn start restores the worktree, then use the skill once the picker has refreshed. Turning off storageCleanup.worktreeUnchanged stops removals under that rule. Other cleanup rules still apply, and it does not bring back a folder that is already gone.

Related

Other missing-worktree reports cover terminal attachment (#24154), Git status and initialization (#29062), and setup scripts during restoration (#30765). This report is about composer skill discovery before the next turn.

Activity

  1. HoneyPaptan commented on Nov 7, 2026

    @HoneyPaptan
    Contributor

    I'd like to take this one. My plan: when the composer's cwd is a managed worktree that no longer exists, look up the thread that owns it and scan the project's workspace root for project skills, publishing the result under the worktree cwd so the picker reads it as usual. Turn start keeps recreating the worktree as today. Reading the skills from the branch with git, or recreating the worktree when the thread opens, would also work; happy to switch if you'd rather go one of those ways.

  2. VDrozd-Cyclis commented on Nov 9, 2026

    @VDrozd-Cyclis

    Additional evidence for this issue from macOS desktop triage on 2026-11-09.

    What happened: A user could no longer find the repository skill github-stack-repair in an existing Claude conversation, despite having invoked it in that same conversation on November 6. Triage confirmed the earlier $github-stack-repair user messages in the conversation history.

    Environment: T3 Code Desktop 0.1.7 connected to its local server, also 0.1.7; macOS arm64 (Darwin 27.2.0); Node 24.22.1; Claude Code 2.1.319. Diagnosis used the v0.1.7 source at 322f6544dfad0a3c8a0c8cbecf2c7f7874b14268.

    Observed state:

    • The conversation still records its managed worktree path and branch, but the directory is absent and is no longer registered in git worktree list.
    • The local branch still exists. Its Git tree contains .agents/skills/github-stack-repair/SKILL.md and the .claude/skills/github-stack-repair symlink. The skill is also readable in the project's main checkout.
    • Global cleanup settings include worktreeUnchanged: true and worktreeOnMerge: true. No deletion event was recovered, so cleanup is a plausible cause of the missing directory, rather than a proven cause of its removal.

    Redacted trace evidence (UTC):

    2026-11-09 11:15:11.808646 probeClaudeWorkspaceSnapshot Success (18.6 ms)
    2026-11-09 11:15:11.808667 discoverClaudeSkills Success (18.5 ms)
    2026-11-09 11:15:11.816259 WorkspaceFileSystem.resolveReadTarget Failure:
      ENOENT: no such file or directory, realpath '<managed-worktree>'
      requested file: t3.json
    

    The same missing-root failure and successful discovery spans also appear around 10:40 and 10:54 UTC.

    Source explanation: In v0.1.7, ClaudeSkills.ts:507-535 scans the requested cwd's .claude/skills and treats directory read failures as an empty list. ClaudeProvider.ts:424-448 returns a non-pending snapshot when that cwd is absent. ProviderTurnStartService.ts:637-676 restores missing managed worktrees only at turn start. This explains why a previously usable repository skill disappears before the next turn.

    Repro shape: Use a repository skill in a managed-worktree Claude thread; remove that worktree while retaining the branch; let its cached workspace snapshot expire; reopen the conversation and search for the skill.

    Workaround and limits: No fix or configuration change was applied during triage. Starting a plain-text turn should let T3 recreate the worktree, after which the picker may need up to the five-minute snapshot TTL to rescan. This workaround was not executed here. The UI omission is user-reported; the filesystem, branch contents, conversation history and trace evidence were independently checked. The raw picker snapshot was not captured.

    This appears to be the same defect as #32459, with a proposed fix in #32471; no additional issue is needed.

    Prepared by Codex (GPT-6.1 Sol, extra-high reasoning) in T3 Code triage.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions