Environment
- OS: Windows 11
- Shell: PowerShell 7 (default shell in psmux)
- psmux: v3.3.2 (tmux compatible multiplexer for Windows)
- overstory cli: v0.9.3
- Claude Code: latest
Problem
The PreToolUse hook scripts deployed by hooks-deployer.ts use bash case pattern matching against $OVERSTORY_WORKTREE_PATH to enforce worktree path boundaries. On Windows, this path is always in Windows format (e.g. C:\cctest\agharness\.overstory\worktrees\my-agent) because git worktree add returns Windows paths natively.
However, the hook scripts are bash and may receive file paths in Unix format (/c/cctest/agharness/...) depending on how Claude Code resolves them through Git Bash. This causes the case match to always fail:
# OVERSTORY_WORKTREE_PATH = "C:\cctest\agharness\.overstory\worktrees\my-agent"
# FILE_PATH might be "/c/cctest/agharness/.overstory/worktrees/my-agent/src/main.rs"
case "$FILE_PATH" in "$OVERSTORY_WORKTREE_PATH"/*) exit 0 ;; esac
# ^ never matches because C:\... != /c/...
This blocks all Write, Edit, and Bash file modification hooks, making the agent unable to write any files inside its own worktree. The agent itself reports:
The Write/Edit/Bash file write hooks are broken on this Windows+Git Bash setup because $OVERSTORY_WORKTREE_PATH is a Windows style path (C:...) but bash file paths are Unix style (/c/...), causing all path boundary checks to fail.
Root Cause
In src/agents/hooks-deployer.ts, both buildPathBoundaryGuardScript() and buildBashPathBoundaryScript() use raw $OVERSTORY_WORKTREE_PATH in a bash case statement without normalizing the path format. On Windows, the env var holds a native Windows path but the bash environment may present file paths in POSIX format.
The env var is set in src/commands/sling.ts (lines ~925 and ~1016) using the return value of createWorktree(), which returns platform native paths.
Suggested Fix
Add a cygpath normalization at the top of each hook script, right after the OVERSTORY_AGENT_NAME guard:
# Normalize Windows paths to POSIX format when running under Git Bash / MSYS2
OVERSTORY_WORKTREE_PATH=$(cygpath -u "$OVERSTORY_WORKTREE_PATH" 2>/dev/null || echo "$OVERSTORY_WORKTREE_PATH");
This converts C:\cctest\agharness\... to /c/cctest/agharness/... when cygpath is available (Git Bash, MSYS2), and is a no op on Linux/macOS where cygpath does not exist.
The same normalization should also be applied to $FILE_PATH after extraction, since it could arrive in either format:
FILE_PATH=$(cygpath -u "$FILE_PATH" 2>/dev/null || echo "$FILE_PATH");
Affected Functions
buildPathBoundaryGuardScript() in src/agents/hooks-deployer.ts (line ~109)
buildBashPathBoundaryScript() in src/agents/hooks-deployer.ts (line ~388)
Reproduction
- On Windows, install psmux (tmux compatible multiplexer)
- Run:
ov sling some-task --runtime claude --name my-agent
- The agent launches but all Write/Edit hooks fail with path boundary violations
- The agent falls back to workarounds like
git cherry-pick to modify files
Environment
Problem
The PreToolUse hook scripts deployed by
hooks-deployer.tsuse bashcasepattern matching against$OVERSTORY_WORKTREE_PATHto enforce worktree path boundaries. On Windows, this path is always in Windows format (e.g.C:\cctest\agharness\.overstory\worktrees\my-agent) becausegit worktree addreturns Windows paths natively.However, the hook scripts are bash and may receive file paths in Unix format (
/c/cctest/agharness/...) depending on how Claude Code resolves them through Git Bash. This causes thecasematch to always fail:This blocks all Write, Edit, and Bash file modification hooks, making the agent unable to write any files inside its own worktree. The agent itself reports:
Root Cause
In
src/agents/hooks-deployer.ts, bothbuildPathBoundaryGuardScript()andbuildBashPathBoundaryScript()use raw$OVERSTORY_WORKTREE_PATHin a bashcasestatement without normalizing the path format. On Windows, the env var holds a native Windows path but the bash environment may present file paths in POSIX format.The env var is set in
src/commands/sling.ts(lines ~925 and ~1016) using the return value ofcreateWorktree(), which returns platform native paths.Suggested Fix
Add a
cygpathnormalization at the top of each hook script, right after theOVERSTORY_AGENT_NAMEguard:This converts
C:\cctest\agharness\...to/c/cctest/agharness/...whencygpathis available (Git Bash, MSYS2), and is a no op on Linux/macOS wherecygpathdoes not exist.The same normalization should also be applied to
$FILE_PATHafter extraction, since it could arrive in either format:Affected Functions
buildPathBoundaryGuardScript()insrc/agents/hooks-deployer.ts(line ~109)buildBashPathBoundaryScript()insrc/agents/hooks-deployer.ts(line ~388)Reproduction
ov sling some-task --runtime claude --name my-agentgit cherry-pickto modify files