feat: add Claude Code hook to block git commands
Enforces the jj-only rule at the tool level — bare git commands
are rejected with a pointer to the jj skill. Commands like gh,
gitea, and jj git pass through.

Assisted-by: Claude Opus 4.6 via pi
change ulyysopwwkzxqztpltssmwnvxwlkvxpw
commit b3a2efa6b9886db05c7b52d3d4e025f7830f6463
author Alpha Chen <alpha@kejadlen.dev>
date
parent ytrwwluo
diff --git a/ai/claude/hooks/no-git.sh b/ai/claude/hooks/no-git.sh
new file mode 100755
index 00000000..e22cd861
--- /dev/null
+++ b/ai/claude/hooks/no-git.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+# Block bare `git` commands — use jj instead.
+# Allows commands that happen to contain "git" (e.g., gh, gitea, git.kejadlen.dev).
+
+command=$(jq -r '.tool_input.command // ""')
+
+# Strip leading whitespace and env assignments, then check for `git` as the first word.
+bare_command=$(echo "$command" | sed 's/^[[:space:]]*//' | sed 's/^[A-Za-z_][A-Za-z_0-9]*=[^ ]* *//')
+
+if [[ "$bare_command" =~ ^git($|[[:space:]]) ]]; then
+  echo "Use jj, not git. See the jj skill for command reference." >&2
+  exit 2
+fi
diff --git a/ai/claude/settings.json b/ai/claude/settings.json
index e971d54f..401ff494 100644
--- a/ai/claude/settings.json
+++ b/ai/claude/settings.json
@@ -33,6 +33,19 @@
     "type": "command",
     "command": "~/.claude/statusline.sh"
   },
+  "hooks": {
+    "PreToolUse": [
+      {
+        "matcher": "Bash",
+        "hooks": [
+          {
+            "type": "command",
+            "command": "~/.claude/hooks/no-git.sh"
+          }
+        ]
+      }
+    ]
+  },
   "enabledPlugins": {
     "claude-md-management@claude-plugins-official": true,
     "elements-of-style@superpowers-marketplace": true,