From a0650b5bde8df712b3f285ff03fda51e09d5bc7a Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 24 Jan 2026 18:53:55 +0000 Subject: [PATCH 1/3] feat: Add hook to block git commit and enforce /commit skill usage Add a PreToolUse hook that intercepts Bash commands and blocks direct git commit usage, directing users to use the /commit skill instead. This ensures all commits go through the proper workflow with code review, testing, and linting. Changes: - Add Block_Bash_With_Instructions.sh hook with configurable blocked commands - Add commit_job_git_commit.sh wrapper for the commit job to bypass the block - Register the hook in settings.json - Update commit_and_push.md to use the wrapper script --- .claude/hooks/Block_Bash_With_Instructions.sh | 76 +++++++++++++++++++ .claude/hooks/commit_job_git_commit.sh | 22 ++++++ .claude/settings.json | 14 +++- .../jobs/commit/steps/commit_and_push.md | 3 +- 4 files changed, 113 insertions(+), 2 deletions(-) create mode 100755 .claude/hooks/Block_Bash_With_Instructions.sh create mode 100755 .claude/hooks/commit_job_git_commit.sh diff --git a/.claude/hooks/Block_Bash_With_Instructions.sh b/.claude/hooks/Block_Bash_With_Instructions.sh new file mode 100755 index 00000000..96380da8 --- /dev/null +++ b/.claude/hooks/Block_Bash_With_Instructions.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# Block_Bash_With_Instructions.sh - Blocks specific bash commands and provides alternative instructions +# +# This hook intercepts Bash tool use calls and blocks commands that match +# specific patterns, providing alternative instructions to the agent. +# +# Usage: Registered as a PreToolUse hook in .claude/settings.json +# +# Input (stdin): JSON from Claude Code hook system containing tool_name and tool_input +# Output (stdout): JSON response with error message if blocked +# Exit codes: +# 0 - Success (allow action) +# 2 - Blocking error (prevent action with message) + +set -e + +# ============================================================================= +# BLOCKED COMMANDS CONFIGURATION +# ============================================================================= +# Format: Each entry is a regex pattern followed by a delimiter (|||) and instructions +# The regex is matched against the full bash command +# Add new blocked commands here: + +BLOCKED_COMMANDS=( + 'git[[:space:]]+commit|||All commits must be done via the `/commit` skill. Do not use git commit directly. Instead, run `/commit` to start the commit workflow which includes code review, testing, and linting before committing.' +) + +# ============================================================================= +# HOOK LOGIC - DO NOT MODIFY BELOW UNLESS NECESSARY +# ============================================================================= + +# Read stdin into variable +HOOK_INPUT="" +if [ ! -t 0 ]; then + HOOK_INPUT=$(cat) +fi + +# Exit early if no input +if [ -z "${HOOK_INPUT}" ]; then + exit 0 +fi + +# Extract tool_name from input +TOOL_NAME=$(echo "${HOOK_INPUT}" | jq -r '.tool_name // empty' 2>/dev/null) + +# Only process Bash tool calls +if [ "${TOOL_NAME}" != "Bash" ]; then + exit 0 +fi + +# Extract the command from tool_input +COMMAND=$(echo "${HOOK_INPUT}" | jq -r '.tool_input.command // empty' 2>/dev/null) + +# Exit if no command +if [ -z "${COMMAND}" ]; then + exit 0 +fi + +# Check each blocked pattern +for entry in "${BLOCKED_COMMANDS[@]}"; do + # Split entry by delimiter + pattern="${entry%%|||*}" + instructions="${entry##*|||}" + + # Check if command matches pattern (using extended regex) + if echo "${COMMAND}" | grep -qE "${pattern}"; then + # Output error message as JSON + cat << EOF +{"error": "${instructions}"} +EOF + exit 2 + fi +done + +# Command is allowed +exit 0 diff --git a/.claude/hooks/commit_job_git_commit.sh b/.claude/hooks/commit_job_git_commit.sh new file mode 100755 index 00000000..fa585032 --- /dev/null +++ b/.claude/hooks/commit_job_git_commit.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# commit_job_git_commit.sh - Wrapper for git commit used by the commit job +# +# This script is used by the commit job's commit_and_push step to perform +# git commits. It passes all arguments through to git commit. +# +# This script exists to allow the commit job to bypass the git commit block +# that is enforced for regular tool use. The block ensures that all commits +# go through the /commit skill workflow, but the commit job itself needs +# to be able to perform the actual commit. +# +# Usage: +# commit_job_git_commit.sh [git commit arguments...] +# +# Examples: +# commit_job_git_commit.sh -m "feat: add new feature" +# commit_job_git_commit.sh -m "$(cat <<'EOF' +# Multi-line commit message +# EOF +# )" + +exec git commit "$@" diff --git a/.claude/settings.json b/.claude/settings.json index 4fe6de01..2436ffdc 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -127,10 +127,22 @@ "Read(./.deepwork/**)", "Edit(./.deepwork/**)", "Write(./.deepwork/**)", - "Bash(deepwork:*)" + "Bash(deepwork:*)", + "Bash(.claude/hooks/commit_job_git_commit.sh:*)" ] }, "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": ".claude/hooks/Block_Bash_With_Instructions.sh" + } + ] + } + ], "SessionStart": [ { "matcher": "", diff --git a/.deepwork/jobs/commit/steps/commit_and_push.md b/.deepwork/jobs/commit/steps/commit_and_push.md index 86d996cc..cd45c43d 100644 --- a/.deepwork/jobs/commit/steps/commit_and_push.md +++ b/.deepwork/jobs/commit/steps/commit_and_push.md @@ -49,8 +49,9 @@ Check the list of changed files against what was modified during this session, e - The style of recent commits - Conventional commit format if the project uses it + **IMPORTANT:** Use the commit job script (not `git commit` directly): ```bash - git commit -m "commit message here" + .claude/hooks/commit_job_git_commit.sh -m "commit message here" ``` 7. **Push to remote** From 0aa9e2c91e0f047924f5bfc17ddc16fad265d168 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 24 Jan 2026 18:58:54 +0000 Subject: [PATCH 2/3] chore: rename hook script to lowercase --- ...ash_With_Instructions.sh => block_bash_with_instructions.sh} | 2 +- .claude/settings.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename .claude/hooks/{Block_Bash_With_Instructions.sh => block_bash_with_instructions.sh} (97%) diff --git a/.claude/hooks/Block_Bash_With_Instructions.sh b/.claude/hooks/block_bash_with_instructions.sh similarity index 97% rename from .claude/hooks/Block_Bash_With_Instructions.sh rename to .claude/hooks/block_bash_with_instructions.sh index 96380da8..387a0979 100755 --- a/.claude/hooks/Block_Bash_With_Instructions.sh +++ b/.claude/hooks/block_bash_with_instructions.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Block_Bash_With_Instructions.sh - Blocks specific bash commands and provides alternative instructions +# block_bash_with_instructions.sh - Blocks specific bash commands and provides alternative instructions # # This hook intercepts Bash tool use calls and blocks commands that match # specific patterns, providing alternative instructions to the agent. diff --git a/.claude/settings.json b/.claude/settings.json index 2436ffdc..6df2fb93 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -138,7 +138,7 @@ "hooks": [ { "type": "command", - "command": ".claude/hooks/Block_Bash_With_Instructions.sh" + "command": ".claude/hooks/block_bash_with_instructions.sh" } ] } From daf7b9f5dc65f07bbe211304cc04d0ce4f81f8a7 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 24 Jan 2026 19:01:34 +0000 Subject: [PATCH 3/3] chore: simplify commit script comment --- .claude/hooks/commit_job_git_commit.sh | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/.claude/hooks/commit_job_git_commit.sh b/.claude/hooks/commit_job_git_commit.sh index fa585032..5fe32679 100755 --- a/.claude/hooks/commit_job_git_commit.sh +++ b/.claude/hooks/commit_job_git_commit.sh @@ -1,22 +1,4 @@ #!/bin/bash -# commit_job_git_commit.sh - Wrapper for git commit used by the commit job -# -# This script is used by the commit job's commit_and_push step to perform -# git commits. It passes all arguments through to git commit. -# -# This script exists to allow the commit job to bypass the git commit block -# that is enforced for regular tool use. The block ensures that all commits -# go through the /commit skill workflow, but the commit job itself needs -# to be able to perform the actual commit. -# -# Usage: -# commit_job_git_commit.sh [git commit arguments...] -# -# Examples: -# commit_job_git_commit.sh -m "feat: add new feature" -# commit_job_git_commit.sh -m "$(cat <<'EOF' -# Multi-line commit message -# EOF -# )" +# commit_job_git_commit.sh - Wrapper for git commit invoked via the /commit skill exec git commit "$@"