Skip to content

bug: agent sessions launched before the shell-env probe finishes get the minimal GUI PATH (node/sf not found) #1004

Description

@rileymeye1

Platform

Field Value
OS macOS
OS version macOS 26.5.1 (build 25F80)
Architecture Apple Silicon (arm64)
Claudette version 0.26.0-dev.12.g626c3d2 (commit 626c3d2)

Description

When Claudette is launched as a normal macOS GUI app (Finder / Dock / Spotlight), agent sessions intermittently spawn claude with the minimal GUI PATH instead of the enriched login-shell PATH. In that state, tools installed under Homebrew (/opt/homebrew/bin), /usr/local/bin, or a version manager (nvm) are not on the Bash tool's PATH, so node, sf, and similar commands aren't found.

The visible symptom is that Claude Code notices the tools are missing and repeatedly prepends the PATH itself, narrating a line like:

This shell needs the PATH prefix (sf/node aren't on the Bash tool's default PATH)

…and running export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH" before each shell command for the rest of the session.

Claudette clearly intends to solve the classic macOS GUI-PATH problem — src/env.rs probes the login+interactive shell and every spawn is meant to use enriched_path(). The bug is that the enrichment isn't reliably applied to the agent process: it appears to depend on a startup race with the async shell probe (details below).

Steps to Reproduce

  1. Install node / sf (or any CLI) somewhere that's only on your PATH via shell init — e.g. Homebrew at /opt/homebrew/bin or an nvm shim — and not on the default GUI PATH (/usr/bin:/bin:/usr/sbin:/sbin).
  2. Launch Claudette from Finder / Dock / Spotlight (i.e. as a GUI app, not from a terminal that already exports the enriched PATH).
  3. Immediately open a workspace and start an agent session that runs a Bash command needing one of those tools (e.g. sf --version or node -v) right away, before the shell probe has warmed.
  4. Observe that the command can't find the binary; the agent falls back to prepending export PATH=… and emits the "This shell needs the PATH prefix …" narration for the rest of the session.

Notes:

  • The bug is masked only if Claudette is a direct child of your shell and thus inherits its full PATH — i.e. running the Mach-O binary directly (/Applications/Claudette.app/Contents/MacOS/claudette-app) or dev mode (./scripts/dev.sh / cargo tauri dev). Launching via double-click / Dock / Spotlight / open -a Claudette does not mask it, because macOS routes those through launchd, which hands the app the minimal system PATH rather than your shell environment.
  • Restarting the workspace/session after the probe has cached resolves it, which is consistent with the race hypothesis below. You can do this by clicking Ctrl + T on to open a new chat in the same workspace and that new chat will resolve correctly.

Expected Behavior

Every agent (and terminal) process should be spawned with the enriched login-shell PATH so that Homebrew/nvm//usr/local tools resolve, regardless of how Claudette was launched and regardless of whether the async shell probe has finished yet.

Actual Behavior

The claude agent process bakes in PATH once at spawn time from enriched_path():

// src/agent/environment.rs:75
command
    .current_dir(working_dir)
    .env("PATH", crate::env::enriched_path());

…but enriched_path() falls back to the bare (minimal) process PATH when the login-shell probe hasn't cached yet — shell_path() returns None "if the probe hasn't run yet" (src/env.rs, ~L433–443 and the enriched_path doc comment ~L479–493).

The probe is kicked off on a background thread at startup and can take up to ~5s (the code itself refers to "the 5-second shell probe"):

// src-tauri/src/main.rs:865
std::thread::spawn(move || claudette::env::prewarm_shell_env(user_deny));

So if an agent session is spawned before prewarm_shell_env finishes caching, that session is stuck on the minimal GUI PATH for its entire lifetime (the claude process env is fixed at spawn). This also affects any path where the probe fails outright or shell-env is disabled.

Suspected Root Cause & Suggested Fix

Root cause: a startup race between the async login-shell probe and the first agent spawn. enriched_path() silently degrades to the minimal process PATH when the cache is cold.

Suggested fix: gate the first agent launch on the probe being ready rather than spawning eagerly with a cold cache. The primitives already exist:

  • env::shell_path_is_cached() / shell_env_is_cached() — reports whether the probe has completed.
  • src/agent/environment.rs::build_agent_command is the natural place to await/block briefly on that (bounded by the existing ~5s probe ceiling) before setting .env("PATH", enriched_path()).

Alternatively, re-probe and respawn if a session was started with a cold cache. Either approach keeps the behavior correct for GUI launches without regressing the terminal-launch path.

Logs / Screenshots

Symptom (agent-generated narration seen every shell command)
This shell needs the PATH prefix (sf/node aren't on the Bash tool's default PATH):

export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"

Environment on the affected machine (for reference — these tools ARE on the login-shell PATH, just not the GUI baseline):

$ command -v node sf
/opt/homebrew/bin/node
/usr/local/bin/sf

Additional Context

  • Workaround for other users: Settings → "Shell environment" → confirm it's enabled and PATH is in the forwarded list, click "Reload", then restart the workspace/session so claude respawns with the warmed cache. Alternatively, running the GUI binary directly (/Applications/Claudette.app/Contents/MacOS/claudette-app) or in dev mode makes it inherit the shell's PATH — but a normal open/Dock/Spotlight launch does not.
  • Related code: src/env.rs (probe + enriched_path), src/agent/environment.rs (agent spawn PATH), src-tauri/src/main.rs:865 (prewarm), src-tauri/src/pty.rs (integrated-terminal PATH merge). Issue bug(env-nix-devshell): new terminals and agent commands are not inside the devshell (PATH dropped) #915 is adjacent (provider-emitted PATH merging) but addresses a different scenario.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions