fix(env): wait for shell probe before agent spawn - #1006
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes a startup race where the async login-shell environment probe could still be cold when the first agent or integrated terminal spawns, causing long-lived sessions (especially GUI-launched on macOS) to permanently inherit launchd’s minimal PATH. It introduces an explicit probe lifecycle + generation tracking, adds a bounded async readiness gate to subprocess command construction, and documents the first-spawn wait/fallback behavior.
Changes:
- Added explicit shell-env probe phases (
Idle/Running/Complete) with generation tokens and an asyncwait_for_shell_env_probe()bounded by an 11s timeout. - Gated env-provider resolution and agent command construction on probe readiness (skipping waits when shell-env is explicitly disabled).
- Updated Tauri startup/reload/watchers to mark probes as running synchronously (while keeping capture on a worker thread) and documented the new behavior.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
src/env.rs |
Adds probe lifecycle state + generation, bounded async wait, and updates prewarm/invalidate + tests. |
src/env_provider/mod.rs |
Waits for probe before resolving providers; preserves disabled shell-env marker as a synthetic source. |
src/agent/environment.rs |
Makes build_agent_command async and adds final readiness gating (with disabled-tier skip). |
src/agent/session.rs |
Awaits the now-async agent command builder for persistent sessions. |
src/agent/process.rs |
Awaits the now-async agent command builder for per-turn runs. |
src/agent/pi_sdk.rs |
Awaits the now-async agent command builder for Pi harness sessions. |
src/agent/codex_app_server.rs |
Awaits the now-async agent command builder for Codex app-server sessions. |
src-tauri/src/main.rs |
Calls prewarm_shell_env directly during setup so the probe is marked running synchronously. |
src-tauri/src/commands/env.rs |
Updates denylist reload/manual reload/watcher flows to schedule probe synchronously (worker remains threaded). |
site/src/content/docs/features/shell-environment.mdx |
Documents the first-spawn readiness wait and fallback behavior. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1006 +/- ##
==========================================
+ Coverage 81.34% 81.38% +0.04%
==========================================
Files 122 122
Lines 45373 45544 +171
==========================================
+ Hits 36908 37068 +160
- Misses 8465 8476 +11 🚀 New features to boost your workflow:
|
f5f8d3e to
17f12d5
Compare
| pub fn prewarm_shell_env(user_deny: Vec<String>) { | ||
| if shell_env_is_cached() { | ||
| return; | ||
| } | ||
| let Some(generation) = begin_shell_env_probe() else { | ||
| return; | ||
| }; |
Summary
Root cause
prewarm_shell_envran asynchronously whileenriched_path()silently fell back to the process PATH whenever the cache was still cold. A session launched immediately after a Finder, Dock, Spotlight, or desktop-launcher start therefore baked launchd's minimal PATH into its long-lived agent process.The old cache predicate could not distinguish an active probe from a completed probe that produced no result, so simply polling
shell_env_is_cached()would also have delayed every spawn after probe failure.Implementation
The shell environment now has explicit
Idle,Running, andCompletephases plus a generation counter. Startup and reload call sites transition toRunningsynchronously, while the blocking shell work remains on a dedicated thread. Async spawn paths wait for the active generation with an 11-second defensive bound (covering the interactive and login-only five-second attempts). Failed or timed-out probes transition toCompleteand retain the existing OS-environment fallback.Workspace environment resolution waits before taking its shell-env snapshot, which covers terminals and ensures all captured shell variables—not only PATH—are present on the first agent turn. The shared agent command builder also gates control-plane sessions that do not resolve workspace providers first.
Validation
cargo test -p claudette -p claudette-server -p claudette-cli --all-featurescargo clippy -p claudette -p claudette-server -p claudette-cli --all-targets --all-features -- -D warnings./scripts/stage-cli-sidecar.sh --profile debugcargo test -p claudette-tauri --no-default-features --features devtools,server,voice,alternative-backends,pi-sdk --no-runcargo fmt --all --checkgit diff --checkCloses #1004