You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
After the fix from #26 landed in 0.3.0 (cd <worktree> now runs before the env sources), the per-slot env files are still not loading on zsh. The new tmux startup command uses the POSIX . (dot) builtin to source .env, .env.local, and .env.ecluse with a relative path that has no ./ prefix:
In bash, . '.env' searches the current directory and works. In zsh (default shell on macOS since Catalina), the . builtin does not search the current directory by default — it only searches $PATH. The shell logs:
.: no such file or directory: .env
.: no such file or directory: .env.local
.: no such file or directory: .env.ecluse
…and continues silently. The per-slot env never loads, so any process spawned in the tmux window only sees the per-slug preamble's vars — which is fine for the ECLUSE_* vars (those are in the preamble) but loses anything from .env, .env.local, or .env.ecluse that isn't duplicated into the preamble. In practice this means apps that rely on user-managed .env (e.g. dotenv-style config, framework defaults like ONYX_ENVIRONMENT=development) crash on startup because their config schemas fail validation.
Version / environment
ecluse 0.3.0
process_manager = "tmux"
macOS 14, zsh 5.9 (default /bin/zsh)
Reproduction
cd /tmp && mkdir zsh-source-test &&cd zsh-source-test
echo'export FOO=bar'> .env
bash -c '. .env && echo "bash: FOO=$FOO"'# → bash: FOO=bar
zsh -c '. .env && echo "zsh: FOO=$FOO"'# → zsh:.:1: no such file or directory: .env# (FOO is unset, the source silently failed)
zsh -c '. ./.env && echo "zsh: FOO=$FOO"'# → zsh: FOO=bar ✓ works with ./ prefix
zsh -c 'source .env && echo "zsh: FOO=$FOO"'# → zsh: FOO=bar ✓ works with `source` instead of `.`
This is documented zsh behavior — see the zsh manual on shell builtins for .: "Unlike in some other shells, zsh's . builtin does NOT search the current directory for the script unless . is in $PATH". POSIX . is supposed to search $PATH only; bash extends it to also try cwd, which is what most users rely on without realizing.
Suggested fix
Two equivalent fixes — pick whichever fits the codebase:
Add ./ prefix to relative paths: change . '.env' to . './.env' (and same for .env.local, .env.ecluse). This is the POSIX-correct way and works in both bash and zsh.
Use source instead of .: source '.env' works in both bash and zsh because source is a bash/zsh extension that searches cwd in both shells (it does not exist in pure POSIX sh, but ecluse already targets bash-compatible shells via process_manager = "tmux" invoking the user's interactive shell — which is bash/zsh on macOS and Linux, never dash).
Option (1) is more portable (works under POSIX sh/dash too in case anyone runs ecluse there); option (2) is more readable.
But: any env defined in .env, .env.local, or .env.ecluse that is NOT mirrored into the per-slug preamble is lost on zsh. In practice this includes user-managed config files (.env), per-worktree overrides written by post_up hooks (.env.local), and the canonical ecluse env file (.env.ecluse).
Single-shell bash users don't see the bug. zsh users (default on macOS) do.
The failure is silent in tmux scrollback (only visible at the top of the pane before output scrolls past); errors only surface when an app tries to read a missing env var.
This issue is the residual half of #26 — the cd ordering and per-slug preamble parts of that fix both landed correctly and are working in 0.3.0. This is a separate, smaller bug that only manifests under zsh.
Summary
After the fix from #26 landed in 0.3.0 (
cd <worktree>now runs before the env sources), the per-slot env files are still not loading on zsh. The new tmux startup command uses the POSIX.(dot) builtin to source.env,.env.local, and.env.eclusewith a relative path that has no./prefix:In bash,
. '.env'searches the current directory and works. In zsh (default shell on macOS since Catalina), the.builtin does not search the current directory by default — it only searches$PATH. The shell logs:…and continues silently. The per-slot env never loads, so any process spawned in the tmux window only sees the per-slug preamble's vars — which is fine for the ECLUSE_* vars (those are in the preamble) but loses anything from
.env,.env.local, or.env.eclusethat isn't duplicated into the preamble. In practice this means apps that rely on user-managed.env(e.g. dotenv-style config, framework defaults likeONYX_ENVIRONMENT=development) crash on startup because their config schemas fail validation.Version / environment
process_manager = "tmux"/bin/zsh)Reproduction
This is documented zsh behavior — see the zsh manual on shell builtins for
.: "Unlike in some other shells, zsh's . builtin does NOT search the current directory for the script unless . is in $PATH". POSIX.is supposed to search$PATHonly; bash extends it to also try cwd, which is what most users rely on without realizing.Suggested fix
Two equivalent fixes — pick whichever fits the codebase:
Add
./prefix to relative paths: change. '.env'to. './.env'(and same for.env.local,.env.ecluse). This is the POSIX-correct way and works in both bash and zsh.Use
sourceinstead of.:source '.env'works in both bash and zsh becausesourceis a bash/zsh extension that searches cwd in both shells (it does not exist in pure POSIX sh, but ecluse already targets bash-compatible shells viaprocess_manager = "tmux"invoking the user's interactive shell — which is bash/zsh on macOS and Linux, neverdash).Option (1) is more portable (works under POSIX
sh/dashtoo in case anyone runs ecluse there); option (2) is more readable.Impact
.env,.env.local, or.env.eclusethat is NOT mirrored into the per-slug preamble is lost on zsh. In practice this includes user-managed config files (.env), per-worktree overrides written bypost_uphooks (.env.local), and the canonical ecluse env file (.env.ecluse).Followup to #26
This issue is the residual half of #26 — the
cdordering and per-slug preamble parts of that fix both landed correctly and are working in 0.3.0. This is a separate, smaller bug that only manifests under zsh.