Skip to content

[Bug]: OpenCode worktree snapshot caches a builtins-only /skill: list mid-thread and never refreshes (recovered by "Restart agent session") #16912

Closed

Description

@DHerrmannP

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

Observed twice on the same thread; not yet deterministic, but the conditions below reproduce the shape:

  1. Provider: OpenCode v2 (opencode serve per workspace, spawned by T3), desktop app, local environment, project
    dotfiles opened in worktree mode (thread cwd ~/.t3/worktrees/<repo>/<id>).
  2. Progress a thread past skill/config churn that touches the OpenCode skill registry: e.g. commits editing skills and
    opencode.json, a stow --adopt -R . restow, or post-merge publish steps (setup-agent-skills.sh + stow).
  3. Mid-thread, OpenCode's per-directory skill registry goes through a rebuild cycle (logged as
    watcher stopped → watcher subscribe → watcher started for <worktree>/.agents/skills, twice 15 s apart in our
    log at 14:08:53Z / 14:09:08Z on 2026-10-07, interleaved with the periodic provider.updated/model.updated
    refresh pair for the same cwd at 14:09:58Z).
  4. If T3's per-cwd workspace-snapshot probe resolves inside that rebuild window, the composer's
    workspaceSnapshots[...matching cwd].skills list is cached as OpenCode's built-in skills only
    (OpenCode, Report) — all discovered personal/global/project skills drop out.
  5. Open / in that thread afterwards: only /model, /compact, /init, /review, /usage-limits and the two
    built-in skills remain. It never heals on its own — still broken after ~40 min, a PR merge, and a machine-wide
    skill republish.

Expected behavior

The palette keeps listing all registered skills (probed or retained from the previous healthy snapshot), and a
mid-thread registry rebuild never leaves the thread with a partial, non-empty skill list.

Actual behavior

The per-cwd snapshot caches the partial (built-ins-only) skill list. Two gaps make it sticky:

  1. The auto-refresh effect only fires when no workspaceSnapshots entry exists for the cwd; a bad-but-present
    entry suppresses refresh indefinitely (see _chat-CBE06zzM.js:
    if (t) { Lr.current = e; Rr.current = null; return } before the refreshProviders call).
  2. The empty-list retention guard only rescues skills.length === 0
    (skills: nextProvider.skills.length === 0 ? previousProvider.skills : nextProvider.skills,
    shouldRetainMissingOpenCodeMetadata); a 2-item builtins-only list passes through untouched.

On the OpenCode side the narrowed list is real state, not just UI caching: the session's available-skills list is
pushed as deltas ("The following skill IDs are no longer available and must not be used: …"), so the agent's
model-visible skill set narrows the same way until recovery.

Recovery confirmed on the live thread: command palette (Ctrl+K) → "Restart agent session" (runs switchRef, then
refreshProviders with fresh: true for {instanceId, cwd: worktreePath}), then one short message → full
/skill: list returns.

Impact

Minor bug or occasional failure — the agent's invocable-skill set silently shrinks mid-thread (registry deltas, not
just UI caching), and the $-picker/skill invocations stop working on that thread until a manual "Restart agent
session"; threads recover cleanly with that workaround at the cost of agent-session continuity.

Version or commit

T3 Code 0.0.46-nightly.20261004.2644 (pacman t3code-nightly-bin 0.0.46_nightly.20261004.2644-1),
OpenCode v2 provider CLI 2.0.23.

Environment

Arch Linux (x64), T3 Code desktop app (/usr/lib/t3code-nightly), local environment + Tailscale-serve web client
(both clients share the same t3 serve snapshot, so the shrink should be visible on phone/web too), per-thread
OpenCode server 127.0.0.1:34323, provider opencode, model glm-5.3-flash.

Logs or stack traces

~/.local/share/opencode/log/opencode.log, 2026-10-07 (OpenCode v2.0.23, run ids cbd46a36 / e0b1da69):

14:08:53.455Z watcher stopped   path=~/.t3/worktrees/dotfiles/t3code-0bc72be4/.agents/skills type=directory
14:08:53.462Z watcher subscribe path=~/.claude/skills type=directory
14:08:53.495Z watcher subscribe path=~/.agents/skills type=directory
14:08:53.508Z watcher subscribe path=~/.t3/worktrees/.../t3code-0bc72be4/.agents/skills type=directory
14:08:53.512Z watcher started   path=~/.t3/worktrees/.../t3code-0bc72be4/.agents/skills backend=inotify
14:09:08.003Z watcher stopped   (same skills path again — second rebuild cycle 15 s later)
14:09:58.890Z event type=provider.updated location.directory=~/.t3/worktrees/.../t3code-0bc72be4
14:09:58.906Z event type=model.updated  location.directory=~/.t3/worktrees/.../t3code-0bc72be4

Palette state after this window: only built-in skills (/skill:OpenCode, /skill:Report) remained; all 61 discovered
dotfiles skills missing. Same persisted cache also holds a machine snapshot with skills:0 and slashCommands
[compact] (~/.t3/caches/opencode.json), so partial snapshots reach disk.

The per-cwd prober resolves only after a fresh skill.updated + command.updated event pair for the directory
(listOpenCode2Workspace: pending = Set("command.updated","skill.updated"), then skill.list/command.list are
taken as-is) — a skill.updated emitted at the start of a rebuild (before the personal/project/compat sources are
re-registered) satisfies the wait while skill.list still returns only built-ins.

Screenshots, recordings, or supporting files

(1) Shrunk state — unfiltered / palette, only the two OpenCode built-in skills:

shrunk

(2) Same thread after Restart agent session + one message — full list restored:

recovered

Workaround

"Restart agent session" on the affected thread (via command palette Ctrl+K → Actions), then send a message. It
costs the thread's agent-session continuity. Creating a fresh thread also shows the full list. No non-destructive
refresh path found for an existing thread.

Related but not duplicates

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