Comprehensive guide to customizing the GitHub Workflow Blueprint for your team’s needs
The GitHub Workflow Blueprint is designed to be flexible and customizable. This guide covers all customization points, from simple configuration changes to advanced workflow modifications.
⚠️ Important Guidelines:
DO:
DON’T:
Level 1: Configuration (Beginner-friendly)
Level 2: Workflow Enhancement (Intermediate)
Level 3: Architectural Changes (Advanced)
Default: 10 tasks per plan
Location: .github/workflows/claude-plan-to-issues.yml:78
Current Configuration:
# Enforce max 10 tasks limit
if [[ $TASK_COUNT -gt 10 ]]; then
echo "❌ Too many tasks: $TASK_COUNT (max 10 allowed)"
exit 1
fi
To Customize:
# Option 1: Increase limit to 15 tasks
if [[ $TASK_COUNT -gt 15 ]]; then
echo "❌ Too many tasks: $TASK_COUNT (max 15 allowed)"
exit 1
fi
# Option 2: Decrease limit to 5 tasks (better focus)
if [[ $TASK_COUNT -gt 5 ]]; then
echo "❌ Too many tasks: $TASK_COUNT (max 5 allowed)"
exit 1
fi
# Option 3: Remove limit (not recommended)
# Comment out the entire check (lines 78-87)
# ⚠️ Warning: May cause API rate limit issues
Considerations:
Recommended: Keep at 10 for most teams, reduce to 5 for solo developers
Default:
claude-plan-to-issues.yml: 100 minimum API callspr-into-dev.yml: 50 minimum API callsLocation: .github/workflows/claude-plan-to-issues.yml:162
Current Configuration:
- name: Check rate limit
uses: ./.github/actions/rate-limit-check
with:
minimum-remaining: 100
github-token: $
To Customize:
# Conservative (recommended for high-activity repos)
minimum-remaining: 200
# Moderate (default)
minimum-remaining: 100
# Aggressive (only if you understand the risks)
minimum-remaining: 25
Impact:
Recommendation: Increase to 150-200 for organizations with many repositories
Default: feature/*, fix/*, hotfix/*
Location: .github/workflows/pr-into-dev.yml:80
Current Configuration:
if [[ ! "$BRANCH_NAME" =~ ^(feature|fix|hotfix)/ ]]; then
echo "❌ Invalid branch name: $BRANCH_NAME"
exit 1
fi
To Customize:
# Add custom branch types
if [[ ! "$BRANCH_NAME" =~ ^(feature|fix|hotfix|chore|docs|refactor)/ ]]; then
echo "❌ Invalid branch name: $BRANCH_NAME"
exit 1
fi
# Different naming convention (e.g., Jira-style)
if [[ ! "$BRANCH_NAME" =~ ^(PROJ-[0-9]+|feature|fix)/ ]]; then
echo "❌ Branch must start with PROJ-XXX, feature/, or fix/"
exit 1
fi
# Relaxed (any branch name allowed)
# Comment out the check entirely
# ⚠️ Warning: Loses consistency and automation benefits
Common Patterns:
# GitHub Flow (minimal)
^(feature|fix)/
# GitFlow (standard)
^(feature|fix|hotfix|release|support)/
# Jira Integration
^(PROJ-[0-9]+|feature|fix)/
# Ticket System
^(ticket-[0-9]+|feature|fix)/
Default: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
Location: .github/workflows/pr-into-dev.yml:107-117
Current Configuration:
types: |
feat
fix
docs
style
refactor
perf
test
build
ci
chore
revert
To Customize:
# Minimal set (simpler for small teams)
types: |
feat
fix
docs
# Extended set (more granular)
types: |
feat
fix
docs
style
refactor
perf
test
build
ci
chore
revert
hotfix
security
deps
# Custom business types
types: |
feature
bugfix
improvement
documentation
Make Scope Required:
requireScope: true # Change from false to true
Default: Lint, typecheck, unit tests
Location: .github/workflows/pr-into-dev.yml:295-300
Current Configuration:
uses: ./.github/workflows/reusable-pr-checks.yml
with:
mobile_check: false
integration_tests: false
node_version: '20'
pnpm_version: '9'
To Customize:
# Enable mobile checks for mobile/fullstack projects
uses: ./.github/workflows/reusable-pr-checks.yml
with:
mobile_check: true # ← Enable mobile validation
integration_tests: true # ← Enable integration tests
node_version: '20'
pnpm_version: '9'
# Use different Node.js/pnpm versions
uses: ./.github/workflows/reusable-pr-checks.yml
with:
mobile_check: false
integration_tests: false
node_version: '22' # ← Latest Node.js
pnpm_version: '10' # ← Latest pnpm
Per-Project Configuration:
Create .github/workflow-config.json:
{
"quality_checks": {
"mobile_check": true,
"integration_tests": true,
"node_version": "20",
"pnpm_version": "9",
"custom_checks": [
"npm run lint:security",
"npm run check:licenses"
]
}
}
Default: Run checks only when relevant files change
Location: .github/workflows/reusable-pr-checks.yml (uses dorny/paths-filter@v3)
Current Configuration:
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
frontend:
- 'src/**'
- 'public/**'
- 'package.json'
backend:
- 'server/**'
- 'api/**'
mobile:
- 'mobile/**'
- 'android/**'
- 'ios/**'
To Customize:
# Monorepo with multiple projects
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
web-app:
- 'apps/web/**'
- 'packages/shared/**'
mobile-app:
- 'apps/mobile/**'
- 'packages/shared/**'
backend:
- 'apps/api/**'
- 'packages/shared/**'
infra:
- 'infrastructure/**'
- '.github/**'
# Documentation-only changes (skip CI)
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
docs-only:
- '**/*.md'
- 'docs/**'
# Then skip checks if only docs changed:
if: steps.filter.outputs.docs-only != 'true'
Skip CI for Specific Files:
Add to any workflow:
on:
pull_request:
paths-ignore:
- '**.md'
- 'docs/**'
- 'LICENSE'
- '.gitignore'
Default: Specific events and branches
To Customize:
# Add schedule trigger (daily checks)
on:
pull_request:
branches: [dev]
schedule:
- cron: '0 0 * * *' # Daily at midnight UTC
# Add manual trigger
on:
pull_request:
branches: [dev]
workflow_dispatch:
inputs:
skip_tests:
type: boolean
default: false
# Add push trigger (immediate feedback)
on:
pull_request:
branches: [dev]
push:
branches: [dev]
Default: Cancel in-progress runs for the same PR
Current Configuration:
concurrency:
group: pr-dev-$
cancel-in-progress: true
To Customize:
# Don't cancel (run all checks)
concurrency:
group: pr-dev-$
cancel-in-progress: false
# Group by branch (cancel old runs on same branch)
concurrency:
group: branch-$
cancel-in-progress: true
# No concurrency control (all runs execute)
# Remove the concurrency block entirely
Location: .claude/commands/github/blueprint-init.md
Default Branching Strategy:
2. Standard: feature → dev → main (RECOMMENDED)
To Customize:
# Change recommended strategy
2. Simple: feature → main (RECOMMENDED for solo developers)
# Or
3. Complex: feature → dev → staging → main (RECOMMENDED for enterprises)
Add Pre-Configured Options:
### Step 2.5: Use Pre-Configured Template? (NEW)
**Ask user**:
Would you like to use a pre-configured template?
Enter 1, 2, 3, or 4:
Location: .claude/commands/github/commit-smart.md
Default Checks: Lint, typecheck, secret scan
To Customize:
Add to the workflow section:
### Step 3.5: Run Custom Pre-Commit Checks (NEW)
**Run additional checks**:
```bash
# Security vulnerability scan
npm audit --audit-level=moderate
# License compliance
npm run check:licenses
# Bundle size check
npm run analyze:bundle
# Accessibility lint
npm run lint:a11y
If any check fails:
Location: .claude/commands/github/plan-to-issues.md
Default: Validates JSON schema, enforces max 10 tasks
To Customize:
### Step 1.5: Custom Validation Rules (NEW)
**Additional validations**:
1. **Estimate Required**:
- Each task must have `estimatedHours` field
- Reject tasks without estimates
2. **Priority Distribution**:
- At least 1 task must be high/critical priority
- No more than 70% of tasks can be low priority
3. **Platform Balance**:
- For fullstack projects, require mix of web + backend tasks
- Warn if all tasks are single-platform
4. **Dependency Validation**:
- Check that dependency issue numbers exist
- Warn about circular dependencies
Location: .claude/commands/github/create-pr.md
Default Template: Standard PR template
To Customize:
### Step 6: Generate Custom PR Body (ENHANCED)
**Build PR body with custom sections**:
```markdown
## 📝 Summary
[Auto-generated from commit messages]
## 🎯 Motivation
[Why was this change needed?]
## 🔧 Implementation Details
[Key technical decisions]
## 📸 Visual Changes
[Screenshots if UI changed]
## ✅ Testing
- [ ] Unit tests added/updated
- [ ] Integration tests pass
- [ ] Manual testing completed
- [ ] Accessibility tested
- [ ] Performance tested
## 🔒 Security
- [ ] No secrets committed
- [ ] No new vulnerabilities
- [ ] Dependencies updated
## 📊 Metrics
- **Files Changed**: X files
- **Lines Added**: +XXX
- **Lines Removed**: -XXX
- **Test Coverage**: XX%
## 🔗 Links
- Issue: #XXX
- Figma: [Design Link]
- Docs: [Documentation]
Closes #XXX
---
## Custom Labels and Status Workflow
### 1. Default Label Scheme
**Status Labels**:
- `status:ready` - Ready to start
- `status:in-progress` - Currently being worked on
- `status:in-review` - In code review
- `status:to-deploy` - Merged to dev, awaiting production
**Type Labels**:
- `type:feature`, `type:fix`, `type:hotfix`, `type:docs`, `type:refactor`, `type:test`
**Platform Labels**:
- `platform:web`, `platform:mobile`, `platform:fullstack`
**Priority Labels**:
- `priority:critical`, `priority:high`, `priority:medium`, `priority:low`
---
### 2. Custom Label Colors
**Location**: `.github/workflows/bootstrap.yml` (label creation section)
**Current Colors**:
```yaml
# Status labels (blue shades)
status:ready → 0e8a16 (green)
status:in-progress → fbca04 (yellow)
status:in-review → d4c5f9 (purple)
status:to-deploy → 1d76db (blue)
# Type labels (color-coded)
type:feature → 0e8a16 (green)
type:fix → d73a4a (red)
type:hotfix → b60205 (dark red)
To Customize:
# Create labels with custom colors
gh label create "status:ready" \
--color "00ff00" \
--description "Ready to start work" \
--force
# Brand colors
gh label create "priority:critical" \
--color "FF0000" \ # Your brand red
--description "Critical priority"
# Semantic colors
gh label create "type:security" \
--color "FFA500" \ # Orange for security
--description "Security-related issue"
Common Extensions:
# Size labels
gh label create "size:xs" --color "c2e0c6" --description "Extra small (< 10 lines)"
gh label create "size:s" --color "bfe5bf" --description "Small (< 50 lines)"
gh label create "size:m" --color "7bc96f" --description "Medium (< 200 lines)"
gh label create "size:l" --color "6fba72" --description "Large (< 500 lines)"
gh label create "size:xl" --color "3d8f4d" --description "Extra large (> 500 lines)"
# Team labels
gh label create "team:frontend" --color "5319e7" --description "Frontend team"
gh label create "team:backend" --color "0052cc" --description "Backend team"
gh label create "team:mobile" --color "00875a" --description "Mobile team"
# Business labels
gh label create "business:revenue" --color "ffd700" --description "Revenue impact"
gh label create "business:ux" --color "ff69b4" --description "User experience"
gh label create "business:tech-debt" --color "8b4513" --description "Technical debt"
Default Flow: ready → in-progress → in-review → to-deploy → done
To Customize:
Option 1: Add Testing Phase
ready → in-progress → in-review → in-testing → to-deploy → done
Update Project Board:
Update Workflow (.github/workflows/pr-status-sync.yml):
# Add testing status transition
- name: Set status to In Testing
if: github.event.label.name == 'status:in-testing'
run: |
# GraphQL mutation to set status
Option 2: Add Approval Phase
ready → in-progress → in-review → approved → to-deploy → done
Simple → Standard:
# Create dev branch
git checkout -b dev
git push -u origin dev
# Update PR workflows to target dev
# Update /blueprint-init to recommend standard
Standard → Complex:
# Create staging branch
git checkout -b staging
git push -u origin staging
# Add staging → main workflow
# Update PR workflows for staging
Default: feature/issue-123-description
To Customize:
Option 1: Jira-Style
# Pattern: PROJ-123-description
^(PROJ-[0-9]+)/
Update .github/workflows/create-branch-on-issue.yml:
# Extract Jira ticket from issue title
JIRA_TICKET=$(echo "$ISSUE_TITLE" | grep -oE 'PROJ-[0-9]+' || echo "")
if [[ -n "$JIRA_TICKET" ]]; then
BRANCH_NAME="$JIRA_TICKET-$SLUG"
else
BRANCH_NAME="feature/issue-$ISSUE_NUMBER-$SLUG"
fi
Option 2: Username Prefix
# Pattern: username/feature/description
git checkout -b "$USERNAME/feature/$DESCRIPTION"
Option 3: Date-Based
# Pattern: 2025-11/feature/description
MONTH=$(date +%Y-%m)
git checkout -b "$MONTH/feature/$DESCRIPTION"
To Customize:
# Require 2 approvals instead of 1
gh api repos/:owner/:repo/branches/main/protection \
--method PUT \
--field required_pull_request_reviews='{"required_approving_review_count":2}'
# Require specific reviewers (CODEOWNERS)
gh api repos/:owner/:repo/branches/main/protection \
--method PUT \
--field required_pull_request_reviews='{"require_code_owner_reviews":true}'
# Require all status checks to pass
gh api repos/:owner/:repo/branches/main/protection \
--method PUT \
--field required_status_checks='{"strict":true,"contexts":["lint","test","build"]}'
# Allow force push for admins only
gh api repos/:owner/:repo/branches/dev/protection \
--method PUT \
--field enforce_admins=false \
--field allow_force_pushes=true
ESLint Configuration:
Location: .eslintrc.json or .eslintrc.js
Strict Configuration:
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended"
],
"rules": {
"no-console": "error", // Block console.log
"no-debugger": "error", // Block debugger
"@typescript-eslint/no-explicit-any": "error", // Strict typing
"react/prop-types": "error" // Require prop types
}
}
Relaxed Configuration:
{
"rules": {
"no-console": "warn", // Allow with warning
"no-debugger": "warn",
"@typescript-eslint/no-explicit-any": "off" // Allow any type
}
}
Jest Configuration:
Location: jest.config.js or package.json
module.exports = {
collectCoverageFrom: [
'src/**/*.{js,jsx,ts,tsx}',
'!src/**/*.d.ts',
'!src/**/*.stories.tsx'
],
coverageThresholds: {
global: {
statements: 80, // 80% statement coverage
branches: 75, // 75% branch coverage
functions: 80, // 80% function coverage
lines: 80 // 80% line coverage
},
// Per-directory thresholds
'./src/components/': {
statements: 90 // Higher for critical code
},
'./src/utils/': {
statements: 95 // Even higher for utilities
}
}
};
Add Security Audit to Quality Checks:
Location: .github/workflows/reusable-pr-checks.yml
Add Job:
security-audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run npm audit
run: |
npm audit --audit-level=moderate
continue-on-error: true # Don't block on vulnerabilities
- name: Check for secrets
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: $
head: $
- name: SAST scan with Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: auto
Bundle Size Check:
bundle-size-check:
name: Check Bundle Size
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-node-pnpm
- name: Build production bundle
run: npm run build
- name: Check bundle size
run: |
MAX_SIZE=500000 # 500KB max
ACTUAL_SIZE=$(stat -f%z dist/bundle.js)
if [ $ACTUAL_SIZE -gt $MAX_SIZE ]; then
echo "❌ Bundle too large: $ACTUAL_SIZE bytes (max: $MAX_SIZE)"
exit 1
fi
echo "✅ Bundle size OK: $ACTUAL_SIZE bytes"
On PR Created:
Location: .github/workflows/pr-into-dev.yml
Add Step:
- name: Notify Slack
if: github.event.action == 'opened'
uses: slackapi/slack-github-action@v1
with:
webhook-url: $
payload: |
{
"text": "New PR opened: $",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*New Pull Request*\n<$|$>"
}
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "Author: $"
}
]
}
]
}
Setup:
gh secret set SLACK_WEBHOOK_URL- name: Notify Discord
if: github.event.action == 'opened'
uses: Ilshidur/action-discord@master
env:
DISCORD_WEBHOOK: $
with:
args: |
**New PR**: $
By: $
Link: $
Auto-Link Jira Issues:
- name: Link to Jira
uses: atlassian/gajira-transition@master
with:
issue: $
transition: "In Progress"
env:
JIRA_BASE_URL: $
JIRA_USER_EMAIL: $
JIRA_API_TOKEN: $
JIRA_ISSUE: $
Extract Jira Key from PR Title:
JIRA_KEY=$(echo "$PR_TITLE" | grep -oE '[A-Z]+-[0-9]+')
Auto-Deploy Previews:
deploy-preview:
name: Deploy Preview to Vercel
runs-on: ubuntu-latest
if: github.event.action == 'opened' || github.event.action == 'synchronize'
steps:
- uses: actions/checkout@v4
- uses: amondnet/vercel-action@v25
with:
vercel-token: $
vercel-org-id: $
vercel-project-id: $
github-comment: true
- name: Deploy to Netlify
uses: nwtgck/actions-netlify@v2
with:
publish-dir: './dist'
production-branch: main
github-token: $
deploy-message: "Deploy from PR #$"
env:
NETLIFY_AUTH_TOKEN: $
NETLIFY_SITE_ID: $
Setup:
feature → dev → staging → production
↓ ↓ ↓
dev.app staging.app app.com
Workflow:
.github/workflows/dev-to-staging.yml).github/workflows/staging-to-production.yml)# Staging
gh secret set STAGING_API_KEY --env staging
# Production
gh secret set PRODUCTION_API_KEY --env production
Integrate LaunchDarkly/ConfigCat:
- name: Evaluate Feature Flags
uses: launchdarkly/find-code-references@v2
with:
access-token: $
project-key: 'default'
Use in Code:
if (await featureFlags.isEnabled('new-feature')) {
// New feature code
}
Beyond Dependabot - Auto-Merge Safe Updates:
name: Auto-Merge Dependabot
on:
pull_request:
branches: [main, dev]
jobs:
auto-merge:
if: github.actor == 'dependabot[bot]'
runs-on: ubuntu-latest
steps:
- name: Check if safe to merge
id: check
run: |
# Only auto-merge patch and minor updates
if [[ "$" =~ "Bump.*from.*to.*[0-9]+\.[0-9]+\.[0-9]+" ]]; then
echo "safe=true" >> $GITHUB_OUTPUT
fi
- name: Auto-merge
if: steps.check.outputs.safe == 'true'
run: |
gh pr merge --auto --squash "$PR_URL"
env:
PR_URL: $
GITHUB_TOKEN: $
Path-Based Workflows:
# Only run frontend checks if frontend changed
frontend-checks:
name: Frontend Quality Checks
runs-on: ubuntu-latest
steps:
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
frontend:
- 'packages/frontend/**'
- name: Run frontend checks
if: steps.filter.outputs.frontend == 'true'
run: |
cd packages/frontend
npm run lint
npm run test
Always Document Custom Changes:
Create docs/CUSTOM_CONFIG.md:
# Custom Configuration
## Changes Made
### 1. Increased Task Limit to 15
- **Date**: 2025-11-06
- **Reason**: Large sprint planning needs
- **Impact**: May hit API rate limits more often
- **Rollback**: Change line 78 back to 10
### 2. Added Slack Notifications
- **Date**: 2025-11-06
- **Webhook**: #engineering-prs channel
- **Trigger**: All PR events
Use Feature Branches for Workflow Changes:
# Create feature branch
git checkout -b config/increase-task-limit
# Make changes
# Test thoroughly
# Create PR
/create-pr
Tag Major Changes:
git tag -a v1.1.0-custom -m "Custom configuration: increased task limit to 15"
git push origin v1.1.0-custom
Test Workflow Changes:
# Test locally with act (GitHub Actions local runner)
act pull_request -j validate-pr-title
# Test in non-production branch first
git checkout dev
gh workflow run pr-into-dev.yml
Validate YAML Syntax:
# Install yamllint
pip install yamllint
# Validate all workflows
yamllint .github/workflows/*.yml
Keep Backup:
# Before modifying workflow
cp .github/workflows/pr-into-dev.yml .github/workflows/pr-into-dev.yml.backup
# If issues occur
mv .github/workflows/pr-into-dev.yml.backup .github/workflows/pr-into-dev.yml
git commit -m "rollback: revert PR workflow changes"
Before Committing Workflow Changes:
yamllint)Test Complete Flow:
# 1. Create test issue
gh issue create --title "test: workflow validation" --body "Test issue"
# 2. Verify branch auto-creation
git fetch
git branch -r | grep feature/issue-
# 3. Create test changes
git checkout feature/issue-XXX
echo "test" > test.txt
git add test.txt
git commit -m "test: validation"
git push
# 4. Create PR
gh pr create --title "test: workflow validation" --body "Closes #XXX"
# 5. Monitor workflow
gh run list --workflow=pr-into-dev.yml --limit 1
# 6. Check PR status
gh pr view
# 7. Clean up
gh pr close
git checkout main
git branch -D feature/issue-XXX
Problem: Workflow doesn’t run after PR creation
Solutions:
# Check trigger configuration
on:
pull_request:
types:
- opened # ← Ensure correct event types
- synchronize
branches:
- dev # ← Match your branch name exactly
Debug:
# Check workflow runs
gh run list --workflow=pr-into-dev.yml
# View workflow file
gh workflow view pr-into-dev.yml
Problem: “Rate limit exceeded” errors
Solutions:
minimum-remaining threshold# Use GitHub App token
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: $
private-key: $
Problem: “Label ‘custom-label’ not found”
Solutions:
# Create missing label
gh label create "custom-label" --color "0e8a16" --description "Custom label"
# Or update bootstrap.yml to create it
Problem: Workflow can’t update PR/issue due to branch protection
Solutions:
GITHUB_TOKEN with elevated permissionspermissions:
contents: write # ← Add required permissions
pull-requests: write
issues: write
Resources:
Debug Mode:
# Enable debug logging
- name: Debug step
run: |
set -x # Enable bash debug mode
echo "Variable: $MY_VAR"
env:
ACTIONS_STEP_DEBUG: true
| Need | Complexity | Risk | Recommendation |
|---|---|---|---|
| Change task limit | Low | Low | Safe, document reason |
| Add custom labels | Low | Low | Safe, update bootstrap |
| Modify branch names | Medium | Medium | Test thoroughly |
| Change quality checks | Medium | Low | Start conservative |
| Add external tools | Medium | Medium | Use secrets, test |
| Modify workflow logic | High | High | Expert only, backup |
Remember: Start small, test thoroughly, document everything, and you’ll have a perfectly customized workflow system that scales with your team!
Last Updated: 2025-11-06 Version: 1.0.0