Repository navigation
Description
What happens
When Claude Code runs inside WSL in a wsl.exe pane, wmux doesn't restore the session correctly. Four separate problems combine:
- The Claude hooks don't reach WSL. wmux writes them only to the Windows
%USERPROFILE%\.claude\settings.json. Claude Code in WSL reads the distro's~/.claude/settings.json, so no hook fires and the pane never gets aclaudeSessionId. Copying the hooks over isn't enough on its own:wmux-hook.jscallsnet.connecton\\.\pipe\wmux, and Linux node can't open that pipe. The hook has no npiperelay route; onlywmux.jshas one. WSL_ENV_PASSTHROUGHuses/u. It's set toWMUX/u:WMUX_SURFACE_ID/u:WMUX_CLI/up:WMUX_PIPE/u:WMUX_PIPE_TOKEN/u:WMUX_INTEGRATION/u, and/upasses values only from Windows into WSL. A Windows helper started inside the pane, such asnode.exerunning the hook, never getsWMUX_SURFACE_ID,WMUX_PIPEorWMUX_PIPE_TOKEN.shell-integration/wmux-bash-integration.shhas CRLF line endings. WSL bash can't source it (error below). Nothing loads it in WSL panes either.- In WSL,
_wmux_reportwrites to a file wmux never reads. WithoutWMUX_REMOTE, it appends to/mnt/c/Users/$USER/AppData/Local/Temp/wmux/messages. That file only grows, andreport_pwdnever reaches wmux. So the workspace never gets aposixCwd, andworkspaceFallbackCwd()returns undefined for a WSL shell when the workspacecwdis a Windows path.wslCdArgthen falls back to--cd ~, so the restored pane opens in$HOME. There,claude --resume <id>can't find the session, because Claude finds sessions by project directory.
Steps to reproduce
- Install Claude Code inside WSL2 (Ubuntu) and enable wmux's agent integration (hooks).
- Create a workspace on a Windows folder, e.g.
C:\Projects\foo, and open awsl.exepane in it. The pane opens in$HOME, not/mnt/c/Projects/foo. cd /mnt/c/Projects/foo, runclaude, and send one message.- Check
%APPDATA%\wmux\sessions\session.json. The pane has noclaudeSessionId, and the workspace has noposixCwd. - Run
. "/mnt/c/Program Files/wmux/resources/shell-integration/wmux-bash-integration.sh". It fails with a syntax error. - Restart wmux. Claude is not resumed, and the pane opens in
$HOME.
wmux version
2.54.0
Windows version
Windows 11 25H2 26200.9711
Anything else
Version and environment: wmux 2.54.0, Windows 11, WSL2 Ubuntu (systemd on), Claude Code installed inside WSL.
Shell: C:\Windows\System32\wsl.exe. The same thing happens when WSL is started from a Git Bash pane, which never gets the WMUX_* variables at all.
Error when sourcing the bash integration:
: command not found
-bash: /mnt/c/Program Files/wmux/resources/shell-integration/wmux-bash-integration.sh: line 14: syntax error near unexpected token `$'{\r''
Workarounds that make it work (confirmed)
The hooks in WSL ~/.claude/settings.json run Windows node and pass the variables back out of WSL:
WSLENV=WMUX:WMUX_SURFACE_ID:WMUX_PIPE:WMUX_PIPE_TOKEN:WMUX_INSTANCE:WMUX_REMOTE:WMUX_REMOTE_TOKEN "/mnt/c/Program Files/nodejs/node.exe" "C:/Program Files/wmux/resources/cli/wmux-hook.js" --event SessionStart
With this, claudeSessionId appears in session.json.
~/.bashrc loads the integration with the CRs removed and sends reports over the pipe:
if [ "$WMUX_INTEGRATION" = "1" ] && [ -n "$WMUX_SURFACE_ID" ]; then
. <(tr -d '\r' < "/mnt/c/Program Files/wmux/resources/shell-integration/wmux-bash-integration.sh")
_wmux_report() {
( WSLENV="WMUX:WMUX_PIPE:WMUX_PIPE_TOKEN" "/mnt/c/Program Files/nodejs/node.exe" \
"C:/Program Files/wmux/resources/cli/wmux.js" raw-v1 "$1" >/dev/null 2>&1 & )
}
firaw-v1 report_pwd <surface> /mnt/c/... returns ok in about 0.1 s, and posixCwd then appears on the workspace.
Suggested fixes
- Ship the
.shfiles with LF line endings (.gitattributes:*.sh text eol=lf). - Drop
/ufrom theWMUX_*entries inWSL_ENV_PASSTHROUGH. - Install the hooks into the WSL Claude config too, run through Windows
node.exe. - In WSL, have
_wmux_reportsend over the pipe (raw-v1through Windows node or npiperelay) instead of the temp file. - Load the bash integration in WSL panes automatically.
This report was investigated and written by Claude (Claude Code, Anthropic's AI assistant) at my request. I confirmed the workarounds on my machine.
Activity
fix(shell-integration): check out shell scripts with LF (#428)
fix(shell-integration): report cwd from Git Bash and WSL over the pipe (
amirlehmam commentedon Nov 3, 2026
Thanks for the precise breakdown. 2.55.0 fixes three of the four points:
.shfiles are now checked out with LF (.gitattributes), so the shipped script sources in WSL bash.WMUX,WMUX_SURFACE_ID,WMUX_PIPEandWMUX_PIPE_TOKENnow cross both ways, andWMUX_CLIis/p. A Windowsnode.exestarted inside the pane, such as your hook, gets them without the inlineWSLENV=prefix._wmux_reportnow sends over the pipe through Windows node runningwmux.js raw-v1, like your workaround, soreport_pwdreaches wmux and the workspace gets itsposixCwd.wmux still does not load the integration in a WSL pane by itself.
wsl.exestarts the distro's own login shell, and replacing it would break zsh and fish users. Instead every WSL pane now getsWMUX_BASH_SCRIPT, so one line in the distro's~/.bashrcis enough:(documented in
docs/wsl-explorer.md).The remaining point is installing the Claude hooks into the distro's
~/.claude/settings.json. That has to go through wmux's consent gate with a matching removal path. It also has to find each distro's home without waking stopped WSL VMs on every launch, so it isn't in this release. Until then, your manual hook works without itsWSLENVprefix. I'm keeping this issue open for that part.feat(wsl): install Claude Code hooks into running WSL distros (#428)
fix(wsl): keep WSL Claude sessions through the startup prune (#428)
fix(wsl): throttle pane-open hook syncs instead of debouncing them (#428
fix(wsl): never let the hook helper exit with the runtime's status (#428
fix(wsl): give a pane opened mid-wait its full boot window (#428)
amirlehmam commentedon Nov 4, 2026
2.56.0 covers the last part: installing the Claude Code hooks inside the distro.
With agent hooks enabled (the same consent as the Windows hooks), wmux now adds its hooks to
~/.claude/settings.jsonin each running WSL distro. Your own hooks and settings are left alone, and turning hooks off removes wmux's entries again. It never starts a stopped distro for this. It only looks at distroswsl.exe --list --runningreports, a few seconds after a WSL pane opens, and updates a stopped one the next time it is running. A distro without~/.claude/settings.jsonis left alone.Each hook command looks for wmux's helper next to
WMUX_BASH_SCRIPT. Outside a wmux pane it does nothing and exits 0, so Claude in another terminal is unaffected. Inside a pane, the helper runs the Windowswmux-hook.jsthrough interop over the same pipe route_wmux_reportuses since 2.55.0. The session id is recorded with its origin, so restoring wmux no longer drops a WSL Claude session because its transcript isn't in the Windows~/.claude/projects.Two things to know:
~/.bashrcline from 2.55.0 is still needed ([ -n "$WMUX_BASH_SCRIPT" ] && . "$WMUX_BASH_SCRIPT").wmux-hook.jstoo, so wmux treats it as its own. It is replaced by the managed ones, and removed if you turn hooks off. Details are indocs/wsl-explorer.md.I tested the install, update and removal against a distro's settings file, and ran the hook command end to end through a POSIX shell into a fake pipe. I could not run Claude in a real Ubuntu pane here. Could you confirm on 2.56.0 that Claude in a WSL pane shows its state in the sidebar and comes back after a wmux restart? I'll close the issue once you do.
ZvikaZ commentedon Nov 4, 2026
Confirmed on 2.57.0 (Windows 11, WSL2 Ubuntu, Claude Code inside WSL):
~/.claude/settings.jsonwith the managedwmux-hook-wsl.shones.currentCwdsaved per pane) and resumed their Claude sessions (claudeSessionHost: "wsl"insession.json).~/.bashrcline fromdocs/wsl-explorer.mdis still needed on my side.Thanks for the quick fixes! Fine to close.
Verified with Claude (Claude Code), which checked the settings and session files.
amirlehmam commentedon Nov 6, 2026
Thanks for confirming on 2.57.0, @ZvikaZ. Closing.