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
PowerShell 7.6.2 installed via Store (MSIX, WindowsApps app-execution alias)
Problem
The shell config option is documented as "Default shell to use for terminal and bash tool" and the docs state "Compatible shells are also used for agent tool calls". On Windows, however, the built-in bash tool always runs Windows PowerShell 5.1 regardless of the configured shell.
Evidence
Global config ~/.config/opencode/opencode.json contains "shell": "pwsh" (confirmed loaded):
> opencode debug config
"shell": "pwsh",
pwsh is resolvable and spawnable from Node (same mechanism opencode uses):
spawnSync('pwsh', ['-NoProfile','-Command','Write-Output hi']) → status 0, stdout "hi"
Yet the agent bash tool executes as PowerShell 5.1:
The bash tool's generated description literally says "Windows PowerShell (5.1)" — it appears to use a hard-coded Windows default rather than the shell config.
Expected
The bash tool should honor shell: "pwsh" on Windows, matching the documented behavior ("Compatible shells are also used for agent tool calls").
Impact
shell config only affects the interactive terminal, not agent tool calls.
Windows users cannot make agents use pwsh 7 (modern syntax, UTF-8-no-BOM default), which matters for tools like Set-Content (5.1 corrupts UTF-8 Chinese text) and rg.
Repro steps
Set "shell": "pwsh" in global config
Restart opencode
Invoke the bash tool with $PSVersionTable.PSVersion.ToString()
Observe 5.1.26100.8875 / Desktop
Workaround (agent-side)
Explicitly invoke pwsh per command: pwsh -NoProfile -Command '...' (single-quote the inner command to avoid outer-shell variable expansion).
Taking this if nobody's on it. I think this is the root cause behind #30615 and #17372 as well.
When PowerShell 7 comes from the Store/MSIX package, pwsh on PATH is a Windows app-execution alias — a zero-byte AppExecLink reparse point rather than a real executable. CreateProcess resolves it by name, but stat and PATH scanning do not see it. Measured on Windows 11:
fs.existsSync(<alias>) -> false
fs.statSync(<alias>) -> undefined
spawnSync("winget", ...) -> status 0 (same alias kind, spawns fine)
Shell.resolve() uses which(), which stats candidates, so a Store-installed pwsh resolves to nothing and select() silently falls back to win()[0] — Windows PowerShell 5.1. The configured shell is never reported as missing, which is why this looks like "config ignored".
Fix I have working: when which() finds nothing on Windows for a known shell name, fall back to where.exe, which does resolve aliases (exit 0 for winget, exit 1 for absent pwsh/zsh), and use the bare name so CreateProcess resolves it. PR shortly.
Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.
Verifying on opencode 1.19.0 / Windows 11 — still reproducible, with one additional data point beyond the alias theory above.
Environment
pwsh --version = 7.6.6, but it exists only as a Store app-execution alias (AppData\Local\Microsoft\WindowsApps\pwsh.exe); Test-Path 'C:\Program Files\PowerShell\7\pwsh.exe' = False. So this machine matches the alias scenario exactly.
$env:SHELL is empty.
Global config has "shell": "pwsh".
Test 1 — config shell ignored by bash tool: the bash tool reports $PSVersionTable.PSVersion = 5.1.26100.9444 despite the config. A chained command fails with ParserError ... The token '&&' is not a valid statement separator (PowerShell 5.1 grammar). Consistent with the which()-misses-alias → silent fallback to 5.1 theory.
Test 2 — $SHELL appears unconsulted entirely (new): launched a nested server via opencode run with SHELL forced in the child environment, then ran the bash tool inside it:
SHELL set to the Store-alias pwsh path → inner bash still 5.1.
SHELL set to C:\Windows\System32\cmd.exe, command ver → returned a PowerShell CommandNotFoundException, not cmd.exe output. If the resolve chain consulted $SHELL at all, ver would have executed under cmd.
So on 1.19.0 the bash tool reaches 5.1 through both doors: the configured shell fails alias resolution (this machine), and $SHELL is never read. The v1 resolve chain seems to be config → silent fallback with no $SHELL step (cf. unmerged PR #9724 which proposed config > plugin > $SHELL > fallback).
Can't verify 2.0 from here (pinned on 1.19.0) — leaving this note so whoever re-verifies has the $SHELL data point. Workarounds in use: semicolon separators, pwsh -NoProfile -Command prefixes, and PTY terminal sessions.
Thanks @MotionDevLab, this is really useful. Your environment (Store-only pwsh 7.6.6, nothing in Program Files\PowerShell\7) is exactly the case I was trying to pin down.
#48968 ports the alias fix to 2.0. On current v2, findExecutable in packages/core/src/shell/select.ts still uses only which(), so it misses the zero-byte AppExecLink in WindowsApps. select() then silently falls through to win(), which picks Windows PowerShell 5.1. The PR adds a where.exe fallback to resolve the alias.
On $SHELL: 2.0 handles this differently from what you saw on 1.19.0. resolve() checks the config shell first and then environment(), which reads process.env.SHELL, so 2.0 does consult $SHELL when no shell is configured. #48968 doesn't change that order. If $SHELL still seems to be ignored on 2.0, I think it should be its own issue.
If you get a chance to try 2.0 (opencode upgrade --major), could you run the same two tests? It would confirm whether the alias fallback is the only problem left.
@thdxr, since this was closed as a v1 issue but I've confirmed the root cause in the v2 source, would you rather I reopen this or keep the fresh 2.0 issue I filed (#55255)?
Activity
github-actions commentedon Aug 9, 2026
This issue might be a duplicate of existing issues. Please check:
shell: "pwsh"config not respected, bash tool still uses PowerShell 5.1 on Windowsbashtool respectshellconfig or add env var override #38799: Feature request tracking the same underlying need — make the bash tool respect theshellconfigPlease review those issues and consider adding your details there if they cover the same problem.
Hotragn commentedon Aug 19, 2026
Taking this if nobody's on it. I think this is the root cause behind #30615 and #17372 as well.
When PowerShell 7 comes from the Store/MSIX package,
pwshon PATH is a Windows app-execution alias — a zero-byteAppExecLinkreparse point rather than a real executable.CreateProcessresolves it by name, butstatand PATH scanning do not see it. Measured on Windows 11:Shell.resolve()useswhich(), which stats candidates, so a Store-installedpwshresolves to nothing andselect()silently falls back towin()[0]— Windows PowerShell 5.1. The configured shell is never reported as missing, which is why this looks like "config ignored".Fix I have working: when
which()finds nothing on Windows for a known shell name, fall back towhere.exe, which does resolve aliases (exit 0 forwinget, exit 1 for absentpwsh/zsh), and use the bare name soCreateProcessresolves it. PR shortly.fix(core): resolve Windows shells installed as app-execution aliases
thdxr commentedon Oct 11, 2026
Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (
opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.— from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊
MotionDevLab commentedon Oct 13, 2026
Verifying on opencode 1.19.0 / Windows 11 — still reproducible, with one additional data point beyond the alias theory above.
Environment
pwsh --version= 7.6.6, but it exists only as a Store app-execution alias (AppData\Local\Microsoft\WindowsApps\pwsh.exe);Test-Path 'C:\Program Files\PowerShell\7\pwsh.exe'= False. So this machine matches the alias scenario exactly.$env:SHELLis empty."shell": "pwsh".Test 1 — config shell ignored by bash tool: the bash tool reports
$PSVersionTable.PSVersion= 5.1.26100.9444 despite the config. A chained command fails withParserError ... The token '&&' is not a valid statement separator(PowerShell 5.1 grammar). Consistent with thewhich()-misses-alias → silent fallback to 5.1 theory.Test 2 —
$SHELLappears unconsulted entirely (new): launched a nested server viaopencode runwithSHELLforced in the child environment, then ran the bash tool inside it:SHELLset to the Store-alias pwsh path → inner bash still 5.1.SHELLset toC:\Windows\System32\cmd.exe, commandver→ returned a PowerShellCommandNotFoundException, not cmd.exe output. If the resolve chain consulted$SHELLat all,verwould have executed under cmd.So on 1.19.0 the bash tool reaches 5.1 through both doors: the configured shell fails alias resolution (this machine), and
$SHELLis never read. The v1 resolve chain seems to be config → silent fallback with no$SHELLstep (cf. unmerged PR #9724 which proposed config > plugin >$SHELL> fallback).Can't verify 2.0 from here (pinned on 1.19.0) — leaving this note so whoever re-verifies has the
$SHELLdata point. Workarounds in use: semicolon separators,pwsh -NoProfile -Commandprefixes, and PTY terminal sessions.Hotragn commentedon Oct 13, 2026
Thanks @MotionDevLab, this is really useful. Your environment (Store-only pwsh 7.6.6, nothing in
Program Files\PowerShell\7) is exactly the case I was trying to pin down.#48968 ports the alias fix to 2.0. On current
v2,findExecutableinpackages/core/src/shell/select.tsstill uses onlywhich(), so it misses the zero-byteAppExecLinkinWindowsApps.select()then silently falls through towin(), which picks Windows PowerShell 5.1. The PR adds awhere.exefallback to resolve the alias.On
$SHELL: 2.0 handles this differently from what you saw on 1.19.0.resolve()checks the config shell first and thenenvironment(), which readsprocess.env.SHELL, so 2.0 does consult$SHELLwhen noshellis configured. #48968 doesn't change that order. If$SHELLstill seems to be ignored on 2.0, I think it should be its own issue.If you get a chance to try 2.0 (
opencode upgrade --major), could you run the same two tests? It would confirm whether the alias fallback is the only problem left.@thdxr, since this was closed as a v1 issue but I've confirmed the root cause in the v2 source, would you rather I reopen this or keep the fresh 2.0 issue I filed (#55255)?