From 4425b5d2d80783fc1182d93ee44822d08f3ef087 Mon Sep 17 00:00:00 2001 From: Miyamura80 Date: Sun, 15 Mar 2026 01:08:12 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=94=A8=20add=20PreToolUse=20hook=20to?= =?UTF-8?q?=20block=20direct=20AI=20writing=20check=20invocation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/hooks/enforce-makefile.sh | 24 ++++++++++++++++++++++++ .claude/settings.json | 16 ++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100755 .claude/hooks/enforce-makefile.sh create mode 100644 .claude/settings.json diff --git a/.claude/hooks/enforce-makefile.sh b/.claude/hooks/enforce-makefile.sh new file mode 100755 index 0000000..9702f3d --- /dev/null +++ b/.claude/hooks/enforce-makefile.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -euo pipefail + +# PreToolUse hook: intercept commands that should use Makefile targets instead. +# Exit 0 with JSON deny = block the command and suggest an alternative. +# Exit 0 with no output = allow the command. + +INPUT=$(cat) +COMMAND=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty') + +# Block direct invocation of the AI writing check script +if [[ "$COMMAND" == *"check_ai_writing"* ]]; then + jq -n '{ + hookSpecificOutput: { + hookEventName: "PreToolUse", + permissionDecision: "deny", + permissionDecisionReason: "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." + } + }' + exit 0 +fi + +# Allow everything else +exit 0 diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..6c478d6 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,16 @@ +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/enforce-makefile.sh\"", + "timeout": 5 + } + ] + } + ] + } +} From 979cfdedf96bf5775f4ec1a17bd24664a5953a7a Mon Sep 17 00:00:00 2001 From: Miyamura80 Date: Sun, 15 Mar 2026 01:08:56 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=90=9B=20tighten=20hook=20pattern=20t?= =?UTF-8?q?o=20only=20match=20script=20execution,=20not=20string=20mention?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/hooks/enforce-makefile.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.claude/hooks/enforce-makefile.sh b/.claude/hooks/enforce-makefile.sh index 9702f3d..8c10e72 100755 --- a/.claude/hooks/enforce-makefile.sh +++ b/.claude/hooks/enforce-makefile.sh @@ -9,7 +9,8 @@ INPUT=$(cat) COMMAND=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty') # Block direct invocation of the AI writing check script -if [[ "$COMMAND" == *"check_ai_writing"* ]]; then +# Match only actual script execution (uv run python / python), not mentions in strings +if [[ "$COMMAND" =~ (uv\ run\ python|python3?|\./).*check_ai_writing\.py ]]; then jq -n '{ hookSpecificOutput: { hookEventName: "PreToolUse", From 349a88c71180d9c5bbad38a1495ce866a90cfcab Mon Sep 17 00:00:00 2001 From: Miyamura80 Date: Sun, 15 Mar 2026 01:11:42 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=94=A8=20rewrite=20enforce-makefile?= =?UTF-8?q?=20hook=20from=20shell=20to=20native=20scripting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/hooks/enforce-makefile.py | 37 +++++++++++++++++++++++++++++++ .claude/hooks/enforce-makefile.sh | 25 --------------------- .claude/settings.json | 2 +- 3 files changed, 38 insertions(+), 26 deletions(-) create mode 100755 .claude/hooks/enforce-makefile.py delete mode 100755 .claude/hooks/enforce-makefile.sh diff --git a/.claude/hooks/enforce-makefile.py b/.claude/hooks/enforce-makefile.py new file mode 100755 index 0000000..9c4c282 --- /dev/null +++ b/.claude/hooks/enforce-makefile.py @@ -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): + 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() diff --git a/.claude/hooks/enforce-makefile.sh b/.claude/hooks/enforce-makefile.sh deleted file mode 100755 index 8c10e72..0000000 --- a/.claude/hooks/enforce-makefile.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# PreToolUse hook: intercept commands that should use Makefile targets instead. -# Exit 0 with JSON deny = block the command and suggest an alternative. -# Exit 0 with no output = allow the command. - -INPUT=$(cat) -COMMAND=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty') - -# Block direct invocation of the AI writing check script -# Match only actual script execution (uv run python / python), not mentions in strings -if [[ "$COMMAND" =~ (uv\ run\ python|python3?|\./).*check_ai_writing\.py ]]; then - jq -n '{ - hookSpecificOutput: { - hookEventName: "PreToolUse", - permissionDecision: "deny", - permissionDecisionReason: "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." - } - }' - exit 0 -fi - -# Allow everything else -exit 0 diff --git a/.claude/settings.json b/.claude/settings.json index 6c478d6..84b6f67 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -6,7 +6,7 @@ "hooks": [ { "type": "command", - "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/enforce-makefile.sh\"", + "command": "uv run python \"$CLAUDE_PROJECT_DIR/.claude/hooks/enforce-makefile.py\"", "timeout": 5 } ]