Shell sessions losing $PATH value from parent shell
Issue: Shell Sessions Losing $PATH Value
Summary
Shell commands executed via the Bash tool receive a minimal system PATH instead of inheriting the full parent shell environment. This causes commands to fail when they depend on tools installed in custom paths (homebrew, nvm, conda, etc.).
Reproduction
Current Behavior
# Parent shell PATH (current Claude Code session)
$ echo $PATH
/Users/optron/.opencode/bin:/Users/optron/.antigravity/antigravity/bin:/Users/optron/.npm-global/bin:/Users/optron/.config/iterm2:/Users/optron/.bun/bin:...
# (40+ paths)
# OpenCode spawned shell PATH
$ opencode run --model openrouter/qwen/qwen3-coder:free "Show me your \$PATH value by running echo \$PATH"
/Users/optron/.local/bin:/Users/optron/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
# (Only 9 minimal system paths)
Missing Paths
When OpenCode spawns shell sessions, the following paths are lost:
-
~/.opencode/bin -
~/.bun/bin -
~/.npm-global/bin - Node version managers (nvm, fnm)
- Language managers (conda, rbenv, pyenv)
- Development tools (flutter, android-sdk, docker)
- Custom user paths from
.zshrc/.bashrc
Root Cause
Location: packages/opencode/src/tool/bash.ts:216-224
const proc = spawn(params.command, {
shell,
cwd: Instance.directory,
env: {
...process.env, // This spreads the env, but...
},
stdio: ["ignore", "pipe", "pipe"],
detached: process.platform !== "win32",
})
Problem: While process.env is spread correctly, spawn() with shell: "/bin/zsh" (or bash) creates a non-interactive, non-login shell that doesn't source initialization files (.zshrc, .bashrc, .zprofile).
This means:
- Shell RC files are NOT sourced
- Custom PATH modifications in RC files are NOT applied
- Only the minimal system PATH is used
Impact
Commands that depend on tools in custom paths will fail:
-
node,npm,pnpm(if installed via nvm/volta) -
python(if using conda/pyenv) -
docker(if installed via Docker Desktop) -
flutter,dart(custom SDK paths) - Any homebrew-installed tools
- Project-specific toolchains
Proposed Solutions
Option 1: Launch Interactive Shell (Recommended)
Modify the command to source RC files:
const shellCommand = (() => {
if (typeof shell === 'string' && shell.includes('zsh')) {
return `/bin/zsh -i -c ${JSON.stringify(params.command)}`
}
if (typeof shell === 'string' && shell.includes('bash')) {
return `/bin/bash -i -c ${JSON.stringify(params.command)}`
}
return params.command
})()
const proc = spawn(shellCommand, {
shell: true, // Let system handle shell selection
cwd: Instance.directory,
env: {
...process.env,
},
stdio: ["ignore", "pipe", "pipe"],
detached: process.platform !== "win32",
})
Pros: Full PATH inheritance, matches user's shell environment Cons: Slightly slower startup (RC file sourcing), potential side effects from RC files
Option 2: Explicit PATH Preservation
Explicitly preserve PATH from parent process:
const proc = spawn(params.command, {
shell,
cwd: Instance.directory,
env: {
...process.env,
PATH: process.env.PATH, // Explicitly preserve PATH
},
stdio: ["ignore", "pipe", "pipe"],
detached: process.platform !== "win32",
})
Pros: Simple, no RC file sourcing overhead Cons: Misses other env vars set in RC files (JAVA_HOME, etc.)
Option 3: Login Shell Flag
Use login shell flag:
const shellPath = typeof shell === 'string' ? shell : '/bin/bash'
const proc = spawn(params.command, {
shell: `${shellPath} -l`, // Login shell
cwd: Instance.directory,
env: {
...process.env,
},
stdio: ["ignore", "pipe", "pipe"],
detached: process.platform !== "win32",
})
Pros: Sources login profile files Cons: May not source all interactive RC settings
Testing
To verify fix:
# Test 1: PATH inheritance
opencode run "echo \$PATH" | wc -l
# Should show many paths, not just system defaults
# Test 2: Custom tools available
opencode run "which node && which docker && which bun"
# Should find tools in custom paths
# Test 3: Environment variables
opencode run "env | grep -E '(NVM_DIR|CONDA_|HOMEBREW_)'"
# Should show custom env vars from RC files
Additional Context
- Platform: macOS (Darwin 25.1.0)
- Shell: zsh (default on macOS)
- OpenCode Version: Latest dev branch
-
Related Code:
packages/opencode/src/tool/bash.ts
References
- Node.js spawn documentation: https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
- Shell invocation modes: https://www.gnu.org/software/bash/manual/html_node/Invoking-Bash.html
Testing comment creation
Duplicate Search Complete
I've reviewed the repository's open issues and found NO clear duplicates for this issue.
Related Issue Found:
- #4961: Feature Request about environment variable security (focuses on secret protection, not PATH inheritance)
This issue appears to be unique in addressing the specific problem of shell sessions spawned by OpenCode not inheriting the full PATH and custom environment variables from the parent shell environment due to non-interactive shell spawning.
Note: Removed test comment. This is the actual duplicate search result.