PostToolUse hooks for Edit/Write never fire (v2.1.47)
Bug Description
PostToolUse hooks configured for Edit and Write tools never execute. The hook command is never invoked — confirmed via debug logging (log file is never created). SessionStart hooks in the same config file fire correctly.
Environment
- Claude Code version: 2.1.47
- OS: macOS (Darwin 25.3.0)
- Shell: zsh
- jq: 1.7.1-apple (installed)
Configuration
~/.claude/settings.json (relevant excerpt):
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit",
"hooks": [{ "type": "command", "command": "/Users/me/.claude/auto-commit.sh" }]
},
{
"matcher": "Write",
"hooks": [{ "type": "command", "command": "/Users/me/.claude/auto-commit.sh" }]
}
],
"SessionStart": [
{
"hooks": [{ "type": "command", "command": "node /Users/me/.claude/hooks/gsd-check-update.js" }]
}
]
},
"permissions": {
"defaultMode": "acceptEdits"
}
}
auto-commit.sh — reads tool_input.file_path from stdin JSON, resolves git root, runs git add -A. Script is executable (chmod +x), works perfectly when run manually.
Reproduction Steps
- Configure PostToolUse hooks for Edit and Write as shown above
- Start a new Claude Code session inside a git repository
- Ask Claude to edit or create a file (triggering Edit or Write tool)
- Check
git status --porcelain— file appears as??(untracked) orM(unstaged), neverA(staged)
Test Matrix
| # | Test | Permission Mode | CWD | Project Settings | Hook Fired? |
|---|------|----------------|-----|-----------------|-------------|
| 1 | Write new file | acceptEdits | inside repo | yes (with own PostToolUse) | NO |
| 2 | Edit tracked file | acceptEdits | inside repo | yes | NO |
| 3 | Write new file | acceptEdits | inside repo | none (dotfiles) | NO |
| 4 | Edit with debug log | acceptEdits | inside repo | none | NO (log file never created) |
| 5 | Write with debug log | acceptEdits | inside repo | none | NO (log file never created) |
| 6 | Edit with 3s delay | acceptEdits | inside repo | yes | NO |
| 7 | Write new file | default | ~ (not a repo) | n/a | NO |
| 8 | Write new file | default | test inside ~/dotfiles | none | NO |
| 9 | Manual script execution | n/a | inside repo | n/a | YES (stages correctly) |
Key Observations
- SessionStart hooks fire correctly — the hook system loads and executes
- PreToolUse hooks for Bash matchers appear to work (e.g.,
Bash(git commit:*)) - PostToolUse hooks for Edit/Write specifically never fire — the command is never invoked
- Debug logging confirms non-execution — a script that writes to
/tmp/hook-debug.logas its first line produces no log file - Not a permission mode issue — fails with both
acceptEditsanddefault - Not a CWD issue — fails inside and outside git repos
- Not a project settings override issue — fails with and without project-level
.claude/settings.json - The script itself works — manual execution with the expected JSON input stages files correctly
Expected Behavior
After Edit or Write tool completes, the PostToolUse hook command should execute with the tool input/output JSON on stdin.
Actual Behavior
The hook command is never executed. No side effects, no log output, no errors.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗