The Human-Agent Collaboration Workflow
Practical patterns for working alongside AI assistants day-to-day
Part 3 of the Agent-Ready Development Series
“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:
The paradox: More guardrails = More speed. Not less.
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.
Here’s the complete configuration I use:
Repository → Settings → Branches → Add branch protection rule
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)
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)
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
When an AI assistant creates a PR:
If any check fails, the PR can’t merge. The AI knows immediately what to fix.
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)
When you ask Claude to “create a PR for this feature,” it will:
The template is essentially a checklist for the AI.
Conventional Commits aren’t just for changelogs—they’re machine-parseable context:
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
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
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.
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]
}
};
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
When an AI creates a PR touching /src/auth/, it knows:
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
main is always deployablefeature/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.
# .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
# .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'
Here’s what happens when you tell Claude: “Fix the login bug in issue #47”
fix/login-redirect-bug-47fix(auth): prevent redirect loop on login (#47)The entire process is structured, predictable, and safe.
main:
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.