Skip to content

feat: add main branch protection hook with DRY instruction cleanup #13

@JacobPEvans-personal

Description

@JacobPEvans-personal

Problem

Claude Code agents can accidentally make changes directly on main worktrees despite documentation in CLAUDE.md stating:

  • "Worktrees required: Run /init-worktree before any work"
  • "No direct main commits: Always use feature branches"
  • "ALWAYS run /init-worktree before starting any new development work"

Documentation alone is not enforcement. The instructions exist but nothing prevents the mistake.

Proposed Solution

1. Create PreToolUse Hook for Main Branch Protection

Add hooks that block Edit, Write, and NotebookEdit operations when:

  • Working directory path ends in /main (worktree naming convention)
  • OR current git branch is main

Hook behavior:

  • BLOCK the operation
  • Output clear instructions to the AI on how to proceed:
    BLOCKED: Cannot modify files in main worktree/branch.
    
    Run /init-worktree to create a feature branch worktree, then retry your changes there.
    

Implementation location: hooks/ directory in superpowers or a new main-protection plugin

Example hook script:

#!/usr/bin/env bash
# PreToolUse:Edit, PreToolUse:Write, PreToolUse:NotebookEdit

# Check if in main worktree (path ends in /main)
if [[ "$PWD" == */main ]]; then
  echo "BLOCKED: Cannot modify files in main worktree."
  echo ""
  echo "Run /init-worktree to create a feature branch worktree, then retry."
  exit 1
fi

# Check if on main branch (fallback for non-worktree repos)
if [[ "$(git branch --show-current 2>/dev/null)" == "main" ]]; then
  echo "BLOCKED: Cannot modify files on main branch."
  echo ""
  echo "Run /init-worktree to create a feature branch worktree, then retry."
  exit 1
fi

exit 0

2. Additional Enforcement Mechanisms

Consider also adding:

  • PreToolUse:Bash hook: Block git commit commands when on main (but allow read-only git operations like git status, git log, git diff)
  • PostToolUse:ExitPlanMode hook: Warn if still in main worktree after planning completes

3. DRY Cleanup - Remove Redundant Instructions

Once the hook provides enforcement AND clear guidance, remove redundant instructions from:

agentsmd/rules/worktrees.md (or equivalent):

  • Remove verbose explanations about why main should not be touched
  • Keep only the structural information (worktree paths, naming conventions)

CLAUDE.md files across repos:

  • Remove: "Worktrees required: Run /init-worktree before any work"
  • Remove: "No direct main commits: Always use feature branches"
  • Remove: "ALWAYS run /init-worktree before starting any new development work"
  • The hook message now serves as the single source of truth

Rationale: The hook's BLOCKED message IS the instruction. Having the same information in CLAUDE.md, rules files, AND the hook message creates maintenance burden and drift risk.

Acceptance Criteria

  • Hook blocks Edit/Write/NotebookEdit on main worktree/branch
  • Hook outputs actionable message telling AI to run /init-worktree
  • Hook handles edge cases (not a git repo, detached HEAD, etc.)
  • Redundant instructions removed from CLAUDE.md and rules files
  • Single source of truth: hook message is the authoritative guidance

Files to Create/Modify

Action File Purpose
Create hooks/main-protection.sh (or similar) The enforcement hook
Create Plugin config registering the hook Hook registration
Modify CLAUDE.md (multiple repos) Remove redundant worktree instructions
Modify agentsmd/rules/worktrees.md Simplify to structural info only

Related

  • Triggered by: Direct commit to main in nix-config repo that was blocked by GitHub branch protection (but should have been caught locally first)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions