Skip to content

Instantly share code, notes, and snippets.

@baelter
Created March 3, 2026 08:42
Show Gist options
  • Select an option

  • Save baelter/47841947c7e4f56422f75512aba4155a to your computer and use it in GitHub Desktop.

Select an option

Save baelter/47841947c7e4f56422f75512aba4155a to your computer and use it in GitHub Desktop.
Claude Code hook: require confirmation before pushing to main/master

Claude Code: Confirm before pushing to main

A Claude Code hook that intercepts any git push to main/master and shows Claude Code's native permission prompt — works even in --dangerously-skip-permissions (yolo) mode.

Setup

  1. Install jq if you don't have it:

    brew install jq        # macOS
    sudo apt install jq    # Debian/Ubuntu
  2. Save the hook script and make it executable:

    mkdir -p ~/.claude/hooks
    # copy block-push-main.sh from this gist to ~/.claude/hooks/
    chmod +x ~/.claude/hooks/block-push-main.sh
  3. Add to ~/.claude/settings.json under hooks.PreToolUse:

    {
      "hooks": {
        "PreToolUse": [
          {
            "matcher": "Bash",
            "hooks": [
              {
                "type": "command",
                "command": "bash ~/.claude/hooks/block-push-main.sh"
              }
            ]
          }
        ]
      }
    }

How it works

  • Claude attempts git push origin main (or any push to main/master)
  • Hook outputs permissionDecision: "ask" — Claude Code shows its native allow/deny prompt
  • User accepts → push proceeds
  • User rejects → push is cancelled

Requires jq and Claude Code with hooks support.

#!/bin/bash
# Require explicit user confirmation before each push to main/master.
# Uses the "ask" decision to trigger Claude Code's native permission prompt.
# Works even in --dangerously-skip-permissions (yolo) mode.
INPUT=$(cat 2>/dev/null) || INPUT=""
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null) || CMD=""
[ -z "$CMD" ] && exit 0
is_push_to_main() {
# Explicit: git push [remote] main|master
echo "$CMD" | grep -qE 'git[[:space:]]+push.*[[:space:]]+(main|master)\b' && return 0
# Bare: git push [remote] while on main/master
if echo "$CMD" | grep -qE '^[[:space:]]*git[[:space:]]+push([[:space:]]+[a-zA-Z0-9_.-]+)?[[:space:]]*$'; then
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) || BRANCH=""
[ "$BRANCH" = "main" ] || [ "$BRANCH" = "master" ] && return 0
fi
return 1
}
if is_push_to_main; then
jq -n '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "ask",
permissionDecisionReason: "Direct push to main/master requires your confirmation"
}
}'
fi
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment