Windows: Plugin hook \${CLAUDE_PLUGIN_ROOT} expansion produces broken bash paths
Bug
On Windows, when Claude Code expands ${CLAUDE_PLUGIN_ROOT} in plugin hook commands (hooks.json), the resulting path uses Windows backslashes (C:\Users\...). This path is then passed directly to /bin/bash which interprets the backslashes as escape characters, stripping them entirely.
Expected
${CLAUDE_PLUGIN_ROOT} should be converted to POSIX format (/c/Users/...) or properly escaped before passing to bash on Windows.
Actual
Stop hook error: Failed with non-blocking status code: /bin/bash: C:Users<user>.claudepluginscacheclaude-plugins-officialralph-loop<hash>/hooks/stop-hook.sh: No such file or directory
The path C:\Users\<user>\.claude\plugins\cache\... becomes C:Users<user>.claudepluginscache... after bash strips the backslash escapes.
Reproduction
- Windows 11 with Git Bash (MSYS2)
- Enable any plugin that uses hooks with
${CLAUDE_PLUGIN_ROOT}in the command (e.g.,ralph-loop) - End a Claude Code session
- Observe the stop hook error
Affected plugin
ralph-loop@claude-plugins-official — its hooks/hooks.json contains:
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/stop-hook.sh"
Suggested fix
In the hook runner, convert CLAUDE_PLUGIN_ROOT to POSIX format before template expansion when the shell is bash/sh on Windows:
// Before expanding ${CLAUDE_PLUGIN_ROOT} in hook commands
if (process.platform === 'win32' && shellIsBash) {
pluginRoot = pluginRoot.replace(/\/g, '/').replace(/^([A-Z]):/, '/$1');
}
Environment
- OS: Windows 11 Pro
- Shell: bash (Git Bash / MSYS2)
- Claude Code: latest
- Affected plugin: ralph-loop@claude-plugins-official
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗