Hero image for Branch Protection & PR Workflows for AI Collaboration
2 min read

Branch Protection & PR Workflows for AI Collaboration

Part 3 of the Agent-Ready Development Series


The Trust Problem

“Should I let the AI push directly to main?”

I get this question constantly. And the answer is always the same: No. And also, no human should push directly to main either.

This isn’t about distrusting AI. It’s about creating an environment where:

  • Mistakes get caught before they cause problems
  • Every change is reviewable and reversible
  • Quality gates are automated, not optional
  • Both humans and AI can move fast with confidence

The paradox: More guardrails = More speed. Not less.


The Anatomy of a Protected Workflow

Here’s what a properly protected git workflow looks like:

main (protected)

  ├── develop (semi-protected)
  │     │
  │     ├── feature/user-auth
  │     ├── feature/dark-mode
  │     └── fix/login-bug

  └── release/v2.0 (protected)

main: Production code. Always deployable. Always protected. develop: Integration branch. PRs merge here first. feature/: Short-lived branches where work happens. release/: Preparation branches for releases.


Setting Up Branch Protection (GitHub)

Here’s the complete configuration I use:

Step 1: Navigate to Settings

Repository → Settings → Branches → Add branch protection rule

Step 2: Configure main Branch

Branch name pattern: main

✓ Require a pull request before merging
  ✓ Require approvals: 1
  ✓ Dismiss stale PR approvals when new commits are pushed
  ✓ Require review from Code Owners

✓ Require status checks to pass before merging
  ✓ Require branches to be up to date
  Status checks:
    - build
    - test
    - lint
    - typecheck

✓ Require conversation resolution before merging

✓ Require signed commits (optional but recommended)

✓ Require linear history

✓ Do not allow bypassing the above settings
  (Even for admins)

✗ Allow force pushes (NEVER on main)
✗ Allow deletions (NEVER on main)

Step 3: Configure develop Branch

Branch name pattern: develop

✓ Require a pull request before merging
  ✓ Require approvals: 1

✓ Require status checks to pass before merging
  Status checks:
    - build
    - test

✓ Require linear history

✓ Allow force pushes by actors
  - CI bot (for automated updates)

The CI Pipeline That Enables AI

Your CI pipeline is what makes branch protection actually useful. Here’s a complete GitHub Actions workflow:

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - run: npm run build

      - uses: actions/upload-artifact@v4
        with:
          name: build
          path: dist/

  test:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - run: npm run test:coverage

      - uses: codecov/codecov-action@v4
        with:
          files: ./coverage/lcov.info

  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - run: npm run lint

  typecheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - run: npm run typecheck

  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - run: npm audit --audit-level=high

      - uses: github/codeql-action/analyze@v3

Why This Matters for AI

When an AI assistant creates a PR:

  1. build - Confirms the code compiles
  2. test - Confirms existing functionality isn’t broken
  3. lint - Confirms code style is correct
  4. typecheck - Confirms types are valid
  5. security - Confirms no vulnerabilities introduced

If any check fails, the PR can’t merge. The AI knows immediately what to fix.


PR Templates That Guide AI

Create a PR template that structures information for both humans and AI:

<!-- .github/PULL_REQUEST_TEMPLATE.md -->

## Summary

<!-- 1-3 sentences: What does this PR do? -->

## Changes

<!-- Bullet list of specific changes -->
-
-
-

## Related

<!-- Link to issue, previous PRs, docs -->
Closes #

## Type of Change

<!-- Check all that apply -->
- [ ] Bug fix (non-breaking)
- [ ] New feature (non-breaking)
- [ ] Breaking change
- [ ] Documentation update
- [ ] Refactoring (no functional change)
- [ ] Performance improvement

## Testing

<!-- How was this tested? -->
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] Manual testing performed

### Test Commands

(bash commands to verify this PR)
npm run test

## Checklist

- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex logic
- [ ] Documentation updated if needed
- [ ] No console.logs or debugging code
- [ ] All tests passing

## Screenshots (if UI change)

(Before/after screenshots)

How AI Uses This

When you ask Claude to “create a PR for this feature,” it will:

  1. Fill in each section systematically
  2. Link to the relevant issue
  3. Check off applicable items
  4. Include appropriate test commands
  5. Provide a clear summary

The template is essentially a checklist for the AI.


The Commit Message Standard

Conventional Commits aren’t just for changelogs—they’re machine-parseable context:

<type>(<scope>): <description>

[optional body]

[optional footer(s)]

Types

feat:     New feature
fix:      Bug fix
docs:     Documentation only
style:    Code style (formatting, semicolons)
refactor: Neither feat nor fix
perf:     Performance improvement
test:     Adding/updating tests
chore:    Maintenance tasks
ci:       CI/CD changes

Examples

feat(auth): add passwordless login option

Implements magic link authentication as alternative to password.
Uses existing email service for delivery.

Closes #123

---

fix(dashboard): prevent crash when data is null

Added null check before accessing nested properties.
This was causing blank screens for new users.

Fixes #456

---

refactor(api): extract validation middleware

No functional change. Moved validation logic from individual
routes to reusable middleware for consistency.

Enforcing Commits

Add a commit-lint check to CI:

# .github/workflows/ci.yml (add this job)
commitlint:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0

    - uses: wagoid/commitlint-github-action@v5

And the config:

// commitlint.config.js
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'scope-enum': [2, 'always', [
      'auth', 'api', 'ui', 'db', 'docs', 'ci', 'config'
    ]],
    'subject-case': [2, 'always', 'lower-case'],
    'body-max-line-length': [0, 'always', Infinity]
  }
};

Code Owners: Who Reviews What

CODEOWNERS files route PRs to the right reviewers automatically:

# .github/CODEOWNERS

# Default owners
* @team-lead

# Frontend
/src/components/ @frontend-team
/src/styles/ @frontend-team

# Backend
/src/api/ @backend-team
/src/services/ @backend-team

# Security-sensitive
/src/auth/ @security-team @team-lead
/.env.example @security-team

# Infrastructure
/.github/ @devops-team
/Dockerfile @devops-team
/docker-compose.yml @devops-team

# Documentation
/docs/ @docs-team
*.md @docs-team

The AI Angle

When an AI creates a PR touching /src/auth/, it knows:

  • Security team will review
  • Higher scrutiny expected
  • Maybe add extra context about security implications

The Two-Branch Strategy (Simplified)

For smaller teams or solo developers, the full Git Flow is overkill. Here’s a simpler approach:

main (production, protected)

  └── feature branches
        ├── feature/new-feature
        ├── fix/bug-fix
        └── chore/update-deps

Rules

  1. main is always deployable
  2. All work happens in feature branches
  3. Feature branches are short-lived (days, not weeks)
  4. Merge via PR, always squash
  5. Delete branch after merge

Branch Naming Convention

feature/description-of-feature
fix/description-of-bug
docs/what-is-being-documented
refactor/what-is-being-refactored
chore/maintenance-task

AI assistants follow these conventions perfectly when you document them in CLAUDE.md.


Automating the Workflow

Auto-assign Reviewers

# .github/workflows/auto-assign.yml
name: Auto Assign

on:
  pull_request:
    types: [opened, ready_for_review]

jobs:
  assign:
    runs-on: ubuntu-latest
    steps:
      - uses: kentaro-m/auto-assign-action@v1
        with:
          configuration-path: .github/auto-assign.yml
# .github/auto-assign.yml
addReviewers: true
addAssignees: true
numberOfReviewers: 1
reviewers:
  - reviewer1
  - reviewer2
  - reviewer3

Auto-label PRs

# .github/workflows/labeler.yml
name: Labeler

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  label:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/labeler@v5
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
# .github/labeler.yml
frontend:
  - 'src/components/**'
  - 'src/styles/**'

backend:
  - 'src/api/**'
  - 'src/services/**'

documentation:
  - '**/*.md'
  - 'docs/**'

tests:
  - '**/*.test.ts'
  - '**/*.spec.ts'

The AI Workflow in Action

Here’s what happens when you tell Claude: “Fix the login bug in issue #47”

  1. Claude reads issue #47 for context
  2. Creates branch: fix/login-redirect-bug-47
  3. Makes changes following CLAUDE.md conventions
  4. Commits: fix(auth): prevent redirect loop on login (#47)
  5. Creates PR using the template
  6. CI runs automatically:
    • Build passes ✓
    • Tests pass ✓
    • Lint passes ✓
    • Types valid ✓
  7. CODEOWNERS routes to right reviewer
  8. Reviewer approves (or requests changes)
  9. Squash merge to main
  10. Branch auto-deleted

The entire process is structured, predictable, and safe.


Quick Wins: What to Do Today

Minimum Viable Protection (5 minutes)

  1. Go to Repository → Settings → Branches
  2. Add rule for main:
    • ✓ Require PR before merging
    • ✓ Require 1 approval
  3. Done.

Better Protection (30 minutes)

  1. Add basic CI workflow (build + test)
  2. Require status checks to pass
  3. Add PR template
  4. Document branch naming in CLAUDE.md

Full Protection (2 hours)

  1. Complete CI with lint, typecheck, security
  2. Add CODEOWNERS file
  3. Configure commit linting
  4. Set up auto-assignment and labeling
  5. Enable signed commits

Coming Next

In Part 4, we’ll dive into Issue Templates That Guide AI Assistants—structuring your issues so that AI agents have all the context they need to actually solve problems.


Branch protection and PR workflows are core to how PopKit manages development. The /popkit:git commands handle commit messages, PR creation, and branch management following these exact patterns—automatically generating conventional commits and properly structured PRs.


← Part 2: Foundation Files | Part 4: Issue Templates →