anthropics / anthropics/claude-code
[BUG] Windows: path-guard hook shared with Linux denies every Edit/Write, even on its own settings file (tool_input.file_path is D:\... but hook shell $PWD/$HOME are POSIX /d/...)
- Ngôn ngữ chính
- Python
- Star
- 145k
- Fork
- 23.1k
- Chỉ số merge pull request
- Chỉ số pull request đang chờ
Mô tả
### Environment
- Claude Code 2.1.270, native Windows 10 Pro (10.0.19045); hook commands run in Git Bash
- The same project is also used on Ubuntu. The folder is synced between the machines, so `.claude/settings.json` (permissions + hooks) is shared.
### What's wrong
The project settings contain a PreToolUse guard for `Edit|Write|NotebookEdit` that only allows files inside the project, the memory dir and the scratchpad (deny message abridged):
```json
"command": "jq -r '.tool_input.file_path // .tool_input.notebook_path // empty' | { read -r f; case \"$f\" in \"$PWD\"/*|\"$HOME\"/.claude/*|/tmp/claude-*) exit 0;; *) printf '%s' '{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"BLOCKED: file outside the project\"}}';; esac; }"
```
It works on Linux. On Windows it denies **every** Edit/Write, because the two sides of the comparison use different path formats:
| value | on Windows |
|---|---|
| `tool_input.file_path` | `D:\Dropbox\project\doc.tex` |
| `$PWD` in the hook shell (Git Bash) | `/d/Dropbox/project` |
| memory file vs `$HOME` | `C:\Users\\.claude\projects\...` vs `/c/Users/` |
| scratchpad | `C:\Users\\AppData\Local\Temp\claude\...` (Git Bash sees `/tmp/claude/...`, not `/tmp/claude-*`) |
Consequences:
1. The guard fails **closed**: every file inside the project is reported as "outside the project".
2. It also denies edits to `.claude/settings.json` itself, so the session cannot repair it. Claude is locked out, and the user has to edit the JSON by hand (or explicitly authorize a shell write that bypasses the Edit/Write diff prompt).
3. The only feedback is the hook's own deny message; nothing points to a path-format mismatch, so it looks like a permissions failure.
Because the settings are shared across machines, path rules can only be portable if they are relative to the project, and a hook is the natural place to express that. On Windows, however, the hook sees paths in a different format than its own shell.
### Related
- #83877 (closed, docs): documents that `file_path` is backslash-separated on Windows and mentions the `$PWD` trap as a fail-*open* case. The mismatch itself remains; with allow-list guards it fails closed and self-locks.
- #76490, #64432: permission rules not matching Windows paths, i.e. the same missing path normalization on Windows.
### What should happen
A settings file that works on Linux/macOS should not silently change meaning on Windows. For example:
- pass hooks paths in the format of the shell that runs them (POSIX under Git Bash), or add normalized fields next to the raw ones (e.g. `file_path_posix`, `cwd_posix`);
- expose the project and scratchpad dirs (e.g. `CLAUDE_PROJECT_DIR`) in a form directly comparable with `tool_input.file_path`;
- offer a recovery path (e.g. from `/hooks`) when a hook blocks edits to the settings file that defines it.
### Steps to reproduce
1. Native Windows, Git Bash as hook shell.
2. Put the hook above in `/.claude/settings.json`.
3. Ask Claude to edit any file in the project: denied ("outside the project").
4. Ask Claude to fix `.claude/settings.json`: denied as well.
### Workaround
Normalize both sides with `cygpath` (on Linux it does not exist and the path is used as is):
```sh
f=$(jq -r '.tool_input.file_path // .tool_input.notebook_path // empty')
u() { cygpath -u "$1" 2>/dev/null || printf '%s' "$1"; }
f=$(u "$f"); p=$(u "${CLAUDE_PROJECT_DIR:-$PWD}")
case "$f" in "$p"/*|"$HOME"/.claude/*|/tmp/claude-*|/tmp/claude/*|/c/Users/*/AppData/Local/Temp/claude/*) exit 0;; *) printf '%s' '';; esac
```
Checked on Windows: project, memory and scratchpad paths are allowed; `D:\Dropbox\other\x.tex` and `D:\Dropbox\project-other\x.tex` are denied; POSIX-style paths behave the same.
Hướng dẫn đóng góp
Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này
Hướng nghiên cứu
Reproduce with the PreToolUse command in /.claude/settings.json under native Windows with Git Bash, then compare the Windows tool_input paths with the hook's $PWD/$HOME values. Check the /hooks recovery path described in the issue. Done means shared settings allow project, memory, and scratchpad edits while denying the two out-of-scope examples on Windows and Linux without locking edits to settings.json.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- bash
- Lĩnh vực
- cli, tooling
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Sôi nổi
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 48/100