-
Notifications
You must be signed in to change notification settings - Fork 1
Add PreToolUse hook to block AI writing check #144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,37 @@ | ||||||
| #!/usr/bin/env python3 | ||||||
| """PreToolUse hook: intercept commands that should use Makefile targets instead.""" | ||||||
|
|
||||||
| import json | ||||||
| import re | ||||||
| import sys | ||||||
|
|
||||||
|
|
||||||
| def deny(reason: str) -> None: | ||||||
| json.dump( | ||||||
| { | ||||||
| "hookSpecificOutput": { | ||||||
| "hookEventName": "PreToolUse", | ||||||
| "permissionDecision": "deny", | ||||||
| "permissionDecisionReason": reason, | ||||||
| } | ||||||
| }, | ||||||
| sys.stdout, | ||||||
| ) | ||||||
|
|
||||||
|
|
||||||
| def main() -> None: | ||||||
| hook_input = json.loads(sys.stdin.read()) | ||||||
| command = hook_input.get("tool_input", {}).get("command", "") | ||||||
|
|
||||||
| # Block direct invocation of the AI writing check script | ||||||
| # Match only actual script execution, not mentions in strings | ||||||
| if re.search(r"(uv\s+run\s+python|python3?|\./).*check_ai_writing\.py", command): | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regex The To fix this, tighten the
Suggested change
This ensures Prompt To Fix With AIThis is a comment left during a code review.
Path: .claude/hooks/enforce-makefile.py
Line: 28
Comment:
**Regex `\./ ` alternative causes false positives**
The `\./ ` branch in `(uv\s+run\s+python|python3?|\./)` will match any `./` occurrence anywhere in the command string, and `.*` is then free to span across unrelated tokens until `check_ai_writing\.py` is found. For example, a legitimate command like `./lint.sh && echo "check_ai_writing.py passed"` would be incorrectly blocked because `./` matches at the start, and `.*check_ai_writing\.py` swallows the rest of the string.
To fix this, tighten the `\./ ` branch so it only matches when `check_ai_writing.py` directly follows, without any directory separator in between:
```suggestion
if re.search(r"(uv\s+run\s+python\s+|python3?\s+|\./)check_ai_writing\.py", command):
```
This ensures `./` is only matched when it immediately precedes `check_ai_writing.py`, preventing false positives from commands that happen to start with `./` and separately mention the script name.
How can I resolve this? If you propose a fix, please make it concise. |
||||||
| deny( | ||||||
| "Do not run the AI writing check script directly. " | ||||||
| "Instead, avoid using em dashes (U+2014) in any code or text you write. " | ||||||
| "The check runs automatically via pre-commit hooks." | ||||||
| ) | ||||||
|
|
||||||
|
|
||||||
| if __name__ == "__main__": | ||||||
| main() | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| { | ||
| "hooks": { | ||
| "PreToolUse": [ | ||
| { | ||
| "matcher": "Bash", | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "uv run python \"$CLAUDE_PROJECT_DIR/.claude/hooks/enforce-makefile.py\"", | ||
| "timeout": 5 | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unhandled exception on malformed stdin
json.loads(sys.stdin.read())will raise ajson.JSONDecodeError(orValueError) if Claude Code sends empty or malformed input, causing the hook to crash with a non-zero exit code. Depending on how Claude Code handles a hook subprocess failure, this could inadvertently block all Bash commands rather than failing open. Wrapping this in atry/exceptand exiting cleanly when input is unexpected would make the hook resilient:Prompt To Fix With AI