The Mistake That Made This Necessary
Today, an AI agent working on the .pip repository committed directly to main and pushed to GitHub—violating one of our most fundamental rules: NEVER work directly on main.
The rule was clearly documented in WARP.md:
IMPORTANT: All changes MUST be made on feature branches. NEVER commit directly to main, even for small documentation updates.
Yet when the agent created the ROADMAP.md file, it worked directly on main instead of creating a feature branch. The violation was caught immediately by the user, but the damage was done—the commit was already on GitHub.
The Problem
Documentation alone isn’t enough. Even with clear rules and prominent warnings, mistakes happen:
- Humans forget in the moment
- AI agents may not internalize rules deeply enough
- Muscle memory can override conscious thought
- Time pressure leads to shortcuts
The solution? Make the wrong thing hard to do.
The Solution: Defense in Depth
We implemented a two-layer protection system:
Layer 1: Local Git Hooks
A pre-commit hook that runs before any commit:
#!/usr/bin/env bash
branch="$(git rev-parse --abbrev-ref HEAD)"
if [ "$branch" = "main" ]; then
echo ""
echo "❌ ERROR: Direct commits to 'main' branch are not allowed!"
echo ""
echo "Please use a feature branch instead:"
echo " git checkout -b feat/your-feature"
echo ""
exit 1
fi
Benefits:
- ⚡ Instant feedback - Catches mistakes immediately
- 📝 Clear guidance - Shows exactly what to do instead
- 🔒 Local enforcement - Works even without network connection
- 🎯 Zero friction - One command to install:
./hooks/install-hooks.sh
Layer 2: GitHub Branch Protection
Configured via GitHub API with these rules:
- ✅ Enforce admins - Even repository owners must follow the process
- ✅ Require pull requests - No direct pushes to main
- ✅ Required linear history - Enforces squash merge for clean git history
- ✅ Block force pushes - Prevents history rewriting
- ✅ Block deletions - Protects main branch from accidental removal
Benefits:
- 🌐 Remote enforcement - Catches bypasses (
--no-verify) - 👥 Team-wide - Protects even when hooks aren’t installed
- 📊 Audit trail - All changes tracked through PRs
- 🛡️ Immutable - Can’t be circumvented without administrative action
Installation
For all contributors (takes 10 seconds):
cd /path/to/pip
./hooks/install-hooks.sh
Output:
Installing git hooks...
✅ Installed pre-commit hook (blocks commits to main)
These hooks will:
- Block direct commits to main branch
- Check for secrets (if git-secrets is installed)
For repository administrators, GitHub protection is configured via API and documented in docs/github-branch-protection.md.
How It Works in Practice
Before (wrong way):
git checkout main
# make changes
git commit -m "quick fix" # ❌ Used to work (BAD!)
After (enforced workflow):
git checkout main
# make changes
git commit -m "quick fix"
# Output:
# ❌ ERROR: Direct commits to 'main' branch are not allowed!
#
# Please use a feature branch instead:
# git checkout -b feat/your-feature
Correct workflow (what you should do):
git checkout -b fix/quick-fix
# make changes
git commit -m "fix: quick fix"
git push origin fix/quick-fix
gh pr create
gh pr merge --squash
Why This Matters
Branch protection isn’t just process bureaucracy—it serves real purposes:
1. Code Review Quality
Pull requests force a moment of reflection:
- Does this change make sense?
- Is the code clean and tested?
- Are docs updated?
- Should anyone else review this?
Even solo developers benefit from the pause.
2. History Clarity
Squash merging via PRs creates clean, semantic git history:
6107df6 Add git hooks and branch protection (#10)
0ac2e70 Add roadmap for agentic system transformation
dce0da0 Add .cursorrules.example template (#9)
Instead of:
abc1234 WIP
def5678 fix typo
ghi9012 actually fix typo
jkl3456 merge
3. CI/CD Integration
PRs are the perfect place to run:
- Automated tests
- Linting and type checking
- Security scans
- Deployment previews
Committing directly to main bypasses all of this.
4. Rollback Safety
If a PR causes issues, you can:
- Revert the single squash commit
- See exactly what changed in the PR diff
- Identify who reviewed and approved it
With direct commits, rollback is messier and riskier.
The Learning
This implementation came directly from an AI agent’s mistake. Instead of just scolding the agent, we asked: “How can we make this mistake impossible?”
The answer:
- ✅ Local hooks catch mistakes early
- ✅ GitHub protection catches bypasses
- ✅ Clear error messages guide correct behavior
- ✅ Documentation explains the “why”
Now, even if an agent (or human) tries to commit to main, the system gently but firmly redirects them to the correct workflow.
For Solo Developers
“But I’m the only person working on this repo—why do I need branch protection?”
Valid question. Here’s the configuration we landed on for solo repos:
Strict protection (what we tried first):
- Require 1 approval from someone other than author
- Problem: Can’t self-approve, blocks all work
Solo-friendly protection (what we use):
- Require pull requests (enforced)
- No approval required (allows self-merge)
- Squash merge enforced
- Force push blocked
This gives you:
- ✅ Process discipline
- ✅ Clean git history
- ✅ CI/CD integration
- ✅ Ability to work independently
Emergency Override
In rare emergencies where direct push is absolutely necessary:
# Bypass local hook
git commit --no-verify
# Then temporarily disable GitHub protection
# (documented in docs/github-branch-protection.md)
⚠️ WARNING: This should be extremely rare—perhaps once or twice per year at most. If you’re doing this regularly, something else is wrong.
Resources
- hooks/README.md - Local hook documentation
- docs/github-branch-protection.md - GitHub settings guide
- WARP.md - Complete workflow documentation
What’s Next
With branch protection in place, we can confidently move forward with:
- More AI agent automation
- Complex multi-step workflows
- Collaborative development
- Production deployments
All with the confidence that mistakes will be caught before they cause problems.
Key Takeaway: The best process enforcement is the kind you don’t have to think about—it just prevents mistakes automatically while guiding you to the right path.
Previous: Interactive Bootstrap
Next: Agentic System Transformation Plan