OpenCode and Muse show "not found" after desktop launch without a cached shell environment#28890

opened10d agobyGgui-complypro

What happened

After the desktop app updated from nightly 4016 to 4035, Settings showed OpenCode ("OpenCode CLI (opencode) is not installed or not on PATH.") and Muse Code ("Muse Code CLI (muse) was not found...") as Not found. Both CLIs work from a terminal and worked in T3 Code the day before. Claude, Codex and Cursor stayed ready. Quitting and relaunching the desktop app fixed both.

Diagnosis

Regression from #28556 (in v0.1.7-nightly.20261101.4035, not in 4016).

  1. With no matching shell-environment-cache.json, the desktop spawns the backend with the launchd PATH (/usr/bin:/bin:/usr/sbin:/sbin) and shellEnvironmentPrepared: true, so the server's fixPath skips its own login-shell hydration (apps/server/src/os-jank.ts).
  2. The real PATH arrives later as a shellEnvironment telemetry message and is applied to the server's live process.env (DesktopTelemetryReceiver.ts, applyShellSnapshot).
  3. Drivers that copy the environment at creation keep the bare PATH:
    • mergeProviderInstanceEnvironment returns { ...baseEnv } whenever instance env vars are set (packages/provider-core/src/server/instanceEnvironment.ts). This OpenCode instance had two.
    • Muse always copies through makeMuseEnvironment(hostEnvironment) (packages/provider-muse/src/server/driver.ts).
  4. Probes spawn opencode / muse with that stale env, get ENOENT, and report "not found". Providers using the live process.env (no instance env) are unaffected.

On the next launch the cache exists, the desktop applies it before spawning, and the backend starts with the full PATH, so a restart hides the bug.

Possible fixes: re-create or re-probe drivers that copied the environment when a shell snapshot is applied, have them read the live environment, or keep shellEnvironmentPrepared false until discovery has completed.

Steps to reproduce

Observed on first launch after updating to 4035. Steps 2-4 are inferred from the code, not re-run:

  1. macOS desktop app. Have opencode and muse only on the login-shell PATH (here ~/.opencode/bin, ~/.local/bin). Give the OpenCode instance at least one environment variable.
  2. Quit T3 Code and delete ~/.t3/userdata/shell-environment-cache.json (or update to 4035 for the first time).
  3. Launch from Finder or the Dock.
  4. Settings: OpenCode and Muse Code show Not found; Claude, Codex and Cursor are ready.
  5. Quit and relaunch: both are ready.

Version

T3 Code Desktop v0.1.7-nightly.20261101.4035 (commit 80120b1), local server on the same build. Worked on v0.1.7-nightly.20261101.4016.

Environment

macOS (Darwin 27.0.0, arm64), desktop app with its built-in local server, zsh login shell. OpenCode 2.2.5, Muse Code 1.4.14.

Evidence

shell
1- Server process (first launch after update) exec env: `PATH=/usr/bin:/bin:/usr/sbin:/sbin`. Agent sessions it spawned later had the full login-shell PATH, so the live `process.env` was hydrated.
2- `shell-environment-cache.json` was first written at that launch and contains `~/.opencode/bin` and `~/.local/bin`.
3- Provider status cache about 6 minutes after launch: `opencode` and `muse` `status: error, installed: false`; `claudeAgent`, `codex` and `cursor` `ready`.
4- After relaunch, the server exec env starts with `~/.opencode/bin:...` and both providers are `ready`.
5- Screenshots of the two "Not found" cards are attached.

#28556 (introduced the async shell discovery). Not a duplicate of #15994 (OpenCode model missing at startup) or #2163 (Windows, closed).

Fix applied or workaround

Quit and relaunch T3 Code once the shell environment cache exists.

Filed by

Claude Code (Opus 5.5, claude-opus-5-5) running the T3 Code triage playbook.

Synced from GitHub

Another hit on v0.1.7-nightly.20261102.4066 (macOS 27.0 arm64, desktop app), with no instance env vars

Same root cause, but this case contradicts "providers using the live process.env (no instance env) are unaffected". OpenCode 2.x is affected even without instance env vars.

  • OpenCode v2.2.5 in ~/.opencode/bin (added by ~/.zshrc), Server URL blank (managed), providerInstances.opencode.environment unset.
  • First launch after updating to 4066 (shell-environment-cache.json was rewritten at that launch). Backend process env: PATH=/usr/bin:/bin:/usr/sbin:/sbin. Desktop trace: desktop.shellEnvironment.refresh 645 ms, publish succeeded.
  • Settings shows "Unavailable · OpenCode could not load its model list." rather than "not found": probeOpenCodeBinary succeeds (it gets the live process.env by reference and reports 2.2.5), then checkOpenCode2 → OpenCode2Server.withConnection → OpenCodeRuntime.startServerAttempt fails:
    1PlatformError: NotFound: ChildProcess.spawn (opencode serve --hostname=127.0.0.1 --port=61520)
    2 [cause]: Error: spawn opencode ENOENT
  • Extra copy site: serverEnvironment() in packages/provider-opencode/src/server/v2/OpenCode2Server.ts always spreads { ...rest }, so OpenCode2Server.make freezes the pre-snapshot PATH at driver creation whether or not instance env vars are set. AgentScope.wrap then can't resolve opencode and the spawn uses the bare name with the stale PATH.

A fix that re-creates or re-probes drivers on a shell snapshot should cover OpenCode2Server's owner env too, not only mergeProviderInstanceEnvironment.

Produced by Claude Opus 5.5 (claude-opus-5-5) via Claude Code, using the T3 Code triage playbook.

Synced from GitHub

Claude is affected too, on stable v0.1.7 (macOS 27.0 arm64, desktop app, no instance env vars)

This contradicts "Claude, Codex and Cursor stayed ready". The Claude driver now copies the environment at creation as well, so it hits the same race.

  • Copy site: ClaudeDriver.create calls mergeClaudeProcessEnvironment(config, environment, process.env), which always builds { ...hostEnvironment, CLAUDE_CODE_ENTRYPOINT: "t3-code" }. That copy becomes processEnv for checkClaudeProviderStatus, so the health check never sees the snapshot applied later to the live process.env.
  • The adapter and text generation are built a few ms later from the live env, so Claude sessions work. Only the provider status is wrong, and the "Claude Agent CLI (claude) was not found on PATH" error toast keeps coming back on every re-check.
  • claude is Homebrew's /opt/homebrew/bin/claude (2.1.318). The backend exec env was PATH=/usr/bin:/bin:/usr/sbin:/sbin.

Timeline of the restart that installed the update (local time, from desktop and server traces):

114:24:13.653 desktop shellEnvironment.installIntoProcess 0.2 ms (cache miss)
214:24:13.654 desktop shellEnvironment.refresh 989 ms
314:24:13.697 desktop backendInstance.start
414:24:14.642 desktop shellEnvironment.publish
514:24:14.645 server mergeClaudeProcessEnvironment (copies bare PATH)
614:24:14.647 server desktopTelemetryReceiver.applyShellEnvironment
714:24:14.652 server checkClaudeProviderStatus -> "Claude Agent CLI health check failed." {errorTag: PlatformError}

The copy lost the race by 1.5 ms. Every checkClaudeProviderStatus since then fails the same way. Every check before the update-restart (13:10 to 14:23:57) succeeded.

This supports the fix that removes the race entirely: drivers read the live environment at spawn time, or are re-created when a discovered: true snapshot is applied. Making the snapshot arrive sooner would only narrow the window.

Workaround: set an absolute binary path (here /opt/homebrew/bin/claude) in Settings > Providers > Claude, or quit and relaunch.