Summary
The settings.local.json template installed by install.py registers four hooks under a PreCommit event key:
auto_test.py
security_scan.py
validate_claude_md_size.py
enforce_regression_test.py
Claude Code does NOT recognize PreCommit as a valid hook event. The entry is rejected on load, and because "Files with errors are skipped entirely, not just the invalid settings", the whole settings.local.json is dropped — so every other valid hook in the file also stops firing.
Version
- autonomous-dev: 3.51.0
- Claude Code: 2.1.144 (native installer on Ubuntu/WSL2)
Reproduction
- Fresh install via the documented one-liner:
bash <(curl -sSL https://raw.githubusercontent.com/akaszubski/autonomous-dev/master/install.sh)
- Open Claude Code in the project directory.
- Observe the startup warning:
.claude/settings.local.json
└ hooks
└ PreCommit: Unknown hook event "PreCommit" was ignored.
Valid events: PreToolUse, PostToolUse, PostToolUseFailure,
PostToolBatch, Notification, UserPromptSubmit, UserPromptExpansion,
SessionStart, SessionEnd, Stop, StopFailure, SubagentStart,
SubagentStop, PreCompact, PostCompact, PermissionRequest,
PermissionDenied, Setup, TeammateIdle, TaskCreated, TaskCompleted,
Elicitation, ElicitationResult, ConfigChange, WorktreeCreate,
WorktreeRemove, InstructionsLoaded, CwdChanged, FileChanged
Expected behaviour
The four scripts under PreCommit should run before git commit operations, as their names and docs suggest.
Actual behaviour
They never fire. The hooks exist on disk but Claude Code does not dispatch them, because PreCommit is not in the supported event list.
Suggested fix
Claude Code has no native pre-commit lifecycle (git owns commits, not Claude). Two valid alternatives:
(A) PreToolUse with Bash matcher + script filter — intercept Bash invocations, check whether the command is git commit, and run the gates only then:
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "python .claude/hooks/precommit_dispatcher.py"
}]
}]
The dispatcher reads tool_input.command from stdin and exits non-zero when the command is a git commit that fails one of the four gates.
(B) Classic git hook in .git/hooks/pre-commit installed by install.py. This lives outside Claude Code entirely; git invokes it. Less elegant for multi-user repos but technically robust.
Impact
Users relying on the documented behaviour (auto_test.py blocks broken tests, security_scan.py blocks committed secrets, etc.) get zero enforcement today. Combined with the related matcher issue, the whole settings.local.json is dropped, so even unrelated hooks stop working.
Happy to submit a PR with the PreToolUse + Bash dispatcher approach if that direction is acceptable.
Summary
The
settings.local.jsontemplate installed byinstall.pyregisters four hooks under aPreCommitevent key:auto_test.pysecurity_scan.pyvalidate_claude_md_size.pyenforce_regression_test.pyClaude Code does NOT recognize
PreCommitas a valid hook event. The entry is rejected on load, and because "Files with errors are skipped entirely, not just the invalid settings", the wholesettings.local.jsonis dropped — so every other valid hook in the file also stops firing.Version
Reproduction
bash <(curl -sSL https://raw.githubusercontent.com/akaszubski/autonomous-dev/master/install.sh)Expected behaviour
The four scripts under
PreCommitshould run beforegit commitoperations, as their names and docs suggest.Actual behaviour
They never fire. The hooks exist on disk but Claude Code does not dispatch them, because
PreCommitis not in the supported event list.Suggested fix
Claude Code has no native pre-commit lifecycle (git owns commits, not Claude). Two valid alternatives:
(A)
PreToolUsewithBashmatcher + script filter — intercept Bash invocations, check whether the command isgit commit, and run the gates only then:The dispatcher reads
tool_input.commandfrom stdin and exits non-zero when the command is agit committhat fails one of the four gates.(B) Classic git hook in
.git/hooks/pre-commitinstalled byinstall.py. This lives outside Claude Code entirely; git invokes it. Less elegant for multi-user repos but technically robust.Impact
Users relying on the documented behaviour (
auto_test.pyblocks broken tests,security_scan.pyblocks committed secrets, etc.) get zero enforcement today. Combined with the relatedmatcherissue, the wholesettings.local.jsonis dropped, so even unrelated hooks stop working.Happy to submit a PR with the
PreToolUse + Bashdispatcher approach if that direction is acceptable.