Complete reference for all GitHub Actions workflows in the Blueprint
This guide documents all 8 core workflows that automate your development lifecycle from planning to deployment.
The GitHub Workflow Blueprint includes 8 specialized workflows that work together to automate your complete development lifecycle:
┌─────────────────────────────────────────────────────────────┐
│ SETUP PHASE │
└─────────────────────────────────────────────────────────────┘
│
└──> bootstrap.yml (manual, one-time)
│
└──> Creates labels, validates project board, sets up repo
│
│
┌─────────────────────────────────────────────────────────────┐
│ PLANNING PHASE │
└─────────────────────────────────────────────────────────────┘
│
└──> claude-plan-to-issues.yml (manual)
│
└──> Creates max 10 issues with labels + milestone
│
│
┌─────────────────────────────────────────────────────────────┐
│ DEVELOPMENT PHASE │
└─────────────────────────────────────────────────────────────┘
│
└──> create-branch-on-issue.yml (on label)
│
└──> Auto-creates feature/fix/hotfix branch
└──> Updates project status: In Progress
│
└──> Developer commits to branch
│
└──> Creates PR to dev
│
┌─────────────────────────────────────────────────────────────┐
│ REVIEW PHASE │
└─────────────────────────────────────────────────────────────┘
│
└──> pr-into-dev.yml (on PR open)
├──> Validates branch name
├──> Validates PR title (conventional)
├──> Validates linked issues
└──> Calls reusable-pr-checks.yml
├──> Lint
├──> Type check
├──> Unit tests
└──> Integration tests (optional)
│
└──> pr-status-sync.yml (on PR events)
└──> Updates issues: In Review
│
└──> PR merged to dev
├──> Deletes source branch
└──> Updates issues: To Deploy
│
┌─────────────────────────────────────────────────────────────┐
│ RELEASE PHASE │
└─────────────────────────────────────────────────────────────┘
│
└──> Create release PR (dev → main)
│
└──> dev-to-main.yml (on PR open)
├──> Production build
├──> Smoke tests
├──> Security scan
└──> Deployment readiness
│
└──> PR merged to main
│
└──> release-status-sync.yml (on merge)
├──> Closes all linked issues
├──> Updates project: Done
├──> Creates GitHub release
└──> Adds release comments
| Workflow | Trigger | Purpose | Duration |
|---|---|---|---|
| bootstrap.yml | Manual (workflow_dispatch) |
One-time repository setup | ~30s |
| reusable-pr-checks.yml | Called by other workflows | DRY quality checks (lint, test, typecheck) | 1-2 min |
| pr-into-dev.yml | PR opened to dev |
Validate feature/fix PRs | 1-3 min |
| dev-to-main.yml | PR opened to main |
Release gates for production | 2-5 min |
| claude-plan-to-issues.yml | Manual (workflow_dispatch) |
Convert Claude plans to issues | 10-30s |
| create-branch-on-issue.yml | Issue labeled | Auto-create feature branches | 5-10s |
| pr-status-sync.yml | PR events (open, close, draft) | Sync PR lifecycle with issues | 5-10s |
| release-status-sync.yml | PR merged to main |
Close issues and update project | 10-20s |
One-time repository setup
Initializes your repository with all required labels, validates project board configuration, and verifies secrets are properly set.
on:
workflow_dispatch:
inputs:
create_milestone:
description: 'Create initial milestone (optional)'
required: false
type: boolean
default: false
milestone_title:
description: 'Milestone title (if creating)'
required: false
type: string
default: 'Sprint 1'
milestone_due_date:
description: 'Milestone due date (YYYY-MM-DD, optional)'
required: false
type: string
How to trigger: Go to Actions → Bootstrap Repository → Run workflow
permissions:
contents: read
issues: write
pull-requests: write
ANTHROPIC_API_KEY - Claude Code API keyPROJECT_URL - GitHub Projects v2 board URLGITHUB_TOKEN - Automatically providedstatus:to-triage, status:ready, status:in-progress, status:in-review, status:to-deploytype:feature, type:fix, type:hotfix, type:docs, type:refactor, type:testplatform:web, platform:mobile, platform:fullstackpriority:critical, priority:high, priority:medium, priority:lowclaude-code, automerge, dependenciesPROJECT_URLStatus field existscreate_milestone input is truemilestone_title and milestone_due_dateBasic setup (no milestone):
# Via GitHub Actions UI
Actions → Bootstrap Repository → Run workflow
With milestone:
# Inputs in GitHub Actions UI
create_milestone: true
milestone_title: "Sprint 1 - MVP Features"
milestone_due_date: "2025-12-31"
Via GitHub CLI:
gh workflow run bootstrap.yml \
-f create_milestone=true \
-f milestone_title="Sprint 1" \
-f milestone_due_date="2025-12-31"
Required Secrets (in repository settings):
ANTHROPIC_API_KEY=sk-ant-...
PROJECT_URL=https://github.com/users/USERNAME/projects/1
# or
PROJECT_URL=https://github.com/orgs/ORGNAME/projects/1
Setting secrets:
# Via GitHub CLI
gh secret set ANTHROPIC_API_KEY
# Paste your API key when prompted
gh secret set PROJECT_URL
# Paste your project board URL when prompted
Problem: ❌ ANTHROPIC_API_KEY is not set
Solution:
ANTHROPIC_API_KEYProblem: ❌ Invalid PROJECT_URL format
Solution: PROJECT_URL must match one of these formats:
https://github.com/users/USERNAME/projects/NUMBER
https://github.com/orgs/ORGNAME/projects/NUMBER
To find your project URL:
Problem: ❌ 'Status' field not found in project board
Solution:
StatusProblem: Label already exists warnings
Solution: This is normal and safe. The workflow is idempotent - it skips existing labels and only creates missing ones. No action needed.
✅ All secrets validated ✅ 23 labels created (or already exist) ✅ Project board validated ✅ Status field found ✅ Milestone created (if requested)
plan-task or manual-task templateclaude-code + status:ready to trigger auto-branch creationdev branchReusable quality gates workflow (DRY)
Provides a centralized, reusable workflow for running quality checks (lint, typecheck, tests) on pull requests. Used by other workflows to avoid code duplication.
on:
workflow_call:
inputs:
mobile_check:
description: 'Run mobile platform checks (iOS/Android)'
type: boolean
default: false
integration_tests:
description: 'Run integration tests'
type: boolean
default: false
node_version:
description: 'Node.js version to use'
type: string
default: '20'
pnpm_version:
description: 'pnpm version to use'
type: string
default: '9'
working_directory:
description: 'Working directory for checks'
type: string
default: '.'
Not triggered directly - called by other workflows like pr-into-dev.yml.
permissions:
contents: read
pull-requests: read
node_modules based on lock file hashCalled from another workflow:
jobs:
quality-checks:
uses: ./.github/workflows/reusable-pr-checks.yml
with:
mobile_check: false
integration_tests: false
node_version: '20'
pnpm_version: '9'
With mobile checks enabled:
jobs:
quality-checks:
uses: ./.github/workflows/reusable-pr-checks.yml
with:
mobile_check: true
integration_tests: true
node_version: '20'
pnpm_version: '9'
Required package.json scripts:
{
"scripts": {
"lint": "eslint .",
"type-check": "tsc --noEmit",
"test": "jest",
"test:unit": "jest --testPathIgnorePatterns=integration",
"test:integration": "jest --testPathPattern=integration",
"format:check": "prettier --check ."
}
}
Optional scripts (auto-detected):
{
"scripts": {
"prettier:check": "prettier --check .",
"typecheck": "tsc --noEmit",
"ios:build": "react-native build-ios",
"android:build": "cd android && ./gradlew assembleRelease"
}
}
The workflow uses smart path filtering to skip unnecessary checks:
| Category | Paths | Checks Run |
|---|---|---|
| Web | src/, lib/, *.ts, *.tsx, package.json |
Lint, TypeCheck, Tests |
| Mobile | mobile/, ios/, android/, *.swift, *.kt |
Mobile Build |
| Tests | **/*.test.ts, **/*.spec.ts, __tests__/ |
Tests Only |
| Docs Only | **.md, docs/ |
All Skipped |
Problem: ❌ ESLint not found
Solution: Add ESLint to your project:
pnpm add -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser
Create .eslintrc.json:
{
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"]
}
Problem: ❌ Type check failed
Solution: Fix TypeScript errors or adjust tsconfig.json:
{
"compilerOptions": {
"strict": false,
"noEmit": true
}
}
Problem: Cache not working (slow installs)
Solution: Verify pnpm-lock.yaml is committed:
git add pnpm-lock.yaml
git commit -m "chore: add pnpm lock file"
Problem: Mobile checks failing
Solution: Ensure mobile setup is correct or disable mobile checks:
with:
mobile_check: false
First run (no cache):
Subsequent runs (with cache):
90%+ improvement with caching!
Feature/fix PR validation before merging to dev
Validates all pull requests into the dev branch to ensure they meet quality standards, follow conventions, and have proper issue linking before merge.
on:
pull_request:
types:
- opened
- synchronize
- ready_for_review
branches:
- dev
Triggers when: A PR targeting dev is opened, updated, or marked ready for review.
permissions:
contents: read
pull-requests: write
issues: read
statuses: write
feature/, fix/, or hotfix/feature/issue-123-add-user-authtype(scope): Subjectfeat, fix, docs, style, refactor, perf, test, build, ci, chore, revertCloses #123, Fixes #456, Resolves #789, Relates to #101reusable-pr-checks.ymlValid PR:
Title: feat(auth): Add user authentication
Body:
## Summary
This PR implements user authentication with JWT tokens.
## Changes
- Add login endpoint
- Add JWT middleware
- Add user model
Closes #123
Fixes #124
✅ Result: All checks pass, ready to merge
Invalid PR (wrong title):
Title: added authentication
Body:
Implemented auth system
❌ Result: PR title validation fails, bot comments with help
Invalid PR (no linked issue):
Title: feat(auth): Add authentication
Body:
Implemented auth system
❌ Result: Linked issue validation fails, bot comments with help
Enable/disable mobile checks:
Edit .github/workflows/pr-into-dev.yml:
uses: ./.github/workflows/reusable-pr-checks.yml
with:
mobile_check: true # Set to false to disable
integration_tests: true # Set to false to disable
Change Node.js version:
with:
node_version: '18' # or '20', '21'
pnpm_version: '8' # or '9'
Problem: ❌ Invalid branch name: my-feature
Solution: Rename your branch to follow convention:
git branch -m feature/issue-123-my-feature
git push origin -d my-feature # Delete old branch
git push origin feature/issue-123-my-feature
Problem: ❌ PR title doesn't follow conventional commit format
Solution: Edit your PR title to match format:
feat: Add new feature
feat(auth): Add user authentication
fix(api): Resolve null pointer exception
docs: Update README
See bot comment for full list of valid types.
Problem: ❌ No linked issues found
Solution: Edit your PR description and add:
Closes #123
or
Fixes #456
Relates to #789
Problem: Fork PR not running checks
Solution: This is expected behavior for security. Fork PRs run read-only checks but skip write operations. If you’re a maintainer, you can manually approve workflow runs for fork PRs.
✅ DO:
❌ DON’T:
Release gates for production deployment
Validates release pull requests (dev → main) to ensure production readiness with additional checks beyond regular PRs.
on:
pull_request:
types:
- opened
- synchronize
- reopened
branches:
- main
Triggers when: A PR targeting main is opened or updated.
permissions:
contents: read
pull-requests: write
statuses: write
dev branch onlydev → main release flownpm run build:prodnpm run test:smoke, npm run test:e2e:smokenpm audit for vulnerabilitiesconsole.log and debugger statementspackage.jsonCreate release PR:
# From dev branch
git checkout dev
git pull origin dev
# Create PR to main
gh pr create \
--base main \
--head dev \
--title "release: Version 1.2.0" \
--body "$(cat CHANGELOG.md | head -50)"
Or use the /release slash command:
/release
Required package.json scripts:
{
"scripts": {
"build": "next build",
"build:prod": "NODE_ENV=production next build"
}
}
Optional scripts:
{
"scripts": {
"test:smoke": "jest --testNamePattern='smoke'",
"test:e2e:smoke": "playwright test smoke/"
}
}
The workflow checks for build outputs in these directories (in order):
dist/ - Vite, Rollup, esbuildbuild/ - Create React App, Parcelout/ - Next.js (static export).next/ - Next.js (server)What are smoke tests? Smoke tests are critical path tests that verify the most important features work:
Example smoke tests:
describe('smoke tests', () => {
it('should load the homepage', async () => {
const response = await fetch('http://localhost:3000');
expect(response.status).toBe(200);
});
it('should authenticate user', async () => {
const result = await login('test@example.com', 'password');
expect(result.success).toBe(true);
});
it('should process payment', async () => {
// Critical payment flow test
});
});
If no smoke tests exist, workflow validates build artifacts as basic sanity.
What it checks:
API_KEY, password, tokenconsole.log, debuggerNote: This is informational only and does not block the release. Review warnings and address before deploying.
Before merging release PR, ensure:
package.jsonProblem: ❌ Invalid source branch: feature/my-feature
Solution: Only dev → main PRs are allowed for releases:
# Close current PR
gh pr close
# Create correct release PR from dev
git checkout dev
gh pr create --base main --head dev
Problem: ❌ Production build failed
Solution: Fix build errors locally first:
npm run build:prod
# Fix any errors
npm run build:prod # Verify it works
git add .
git commit -m "fix: resolve production build issues"
git push
Problem: ❌ Smoke tests failed
Solution: Run smoke tests locally:
npm run test:smoke
# Fix failing tests
npm run test:smoke # Verify they pass
git add .
git commit -m "fix: resolve smoke test failures"
git push
Problem: ⚠️ No smoke tests found
Solution: This is not an error. The workflow will validate build artifacts instead. To add smoke tests:
# Install playwright (or use jest)
pnpm add -D @playwright/test
# Create smoke test
mkdir -p tests/smoke
cat > tests/smoke/critical-paths.spec.ts << EOF
import { test, expect } from '@playwright/test';
test('homepage loads', async ({ page }) => {
await page.goto('http://localhost:3000');
await expect(page).toHaveTitle(/My App/);
});
EOF
# Add script
# package.json:
# "test:e2e:smoke": "playwright test tests/smoke"
Problem: Security scan shows warnings
Solution: Review warnings in workflow logs:
# Check npm audit
npm audit
# Fix vulnerabilities
npm audit fix
# Or ignore false positives
npm audit --production # Only check production deps
For hardcoded secrets/debug statements, search and remove:
grep -r "console.log" src/
grep -r "debugger" src/
✅ DO:
dev branch❌ DON’T:
Convert Claude Code plans (JSON) to GitHub issues
Transforms Claude Code planning output (JSON format) into organized GitHub issues with proper labels, milestones, dependencies, and project board integration.
on:
workflow_dispatch:
inputs:
plan_json:
description: 'Claude plan in JSON format'
required: true
type: string
milestone_title:
description: 'Milestone for these issues (optional)'
required: false
type: string
create_milestone:
description: 'Create milestone if it doesnt exist'
required: false
type: boolean
default: true
How to trigger:
# Via GitHub Actions UI
Actions → Convert Claude Plan to Issues → Run workflow
# Or use /plan-to-issues slash command
/plan-to-issues path/to/plan.json
permissions:
contents: read
issues: write
pull-requests: read
create_milestone: truemilestone_title or extracts from planDepends on #123)claude-code (all issues)status:ready (all issues)type:* (feature/fix/docs/refactor/test)platform:* (web/mobile/fullstack)priority:* (critical/high/medium/low)dependencies arraySimple plan (3 tasks):
{
"milestone": "Sprint 1 - Authentication",
"tasks": [
{
"title": "Add login endpoint",
"description": "Create POST /api/auth/login endpoint with JWT token generation",
"acceptanceCriteria": [
"Accepts email and password",
"Returns JWT token on success",
"Returns 401 on invalid credentials"
],
"type": "feature",
"platform": "web",
"priority": "high",
"dependencies": []
},
{
"title": "Add user authentication middleware",
"description": "Create Express middleware to validate JWT tokens",
"acceptanceCriteria": [
"Validates JWT signature",
"Attaches user object to request",
"Returns 401 on invalid token"
],
"type": "feature",
"platform": "web",
"priority": "high",
"dependencies": [1]
},
{
"title": "Add logout endpoint",
"description": "Create POST /api/auth/logout endpoint",
"acceptanceCriteria": [
"Invalidates JWT token",
"Returns 200 on success"
],
"type": "feature",
"platform": "web",
"priority": "medium",
"dependencies": [1, 2]
}
]
}
Trigger via GitHub Actions:
# Save plan to file
cat > plan.json << EOF
{
"milestone": "Sprint 1",
"tasks": [...]
}
EOF
# Trigger workflow
gh workflow run claude-plan-to-issues.yml \
-f plan_json="$(cat plan.json)" \
-f milestone_title="Sprint 1" \
-f create_milestone=true
Or use the /plan-to-issues slash command:
/plan-to-issues plan.json
JSON Schema (required fields):
interface ClaudePlan {
milestone?: string;
tasks: Task[]; // Max 10
}
interface Task {
title: string; // Required
description: string; // Required
acceptanceCriteria: string[]; // Required
type: 'feature' | 'fix' | 'docs' | 'refactor' | 'test'; // Required
platform: 'web' | 'mobile' | 'fullstack'; // Required
priority: 'critical' | 'high' | 'medium' | 'low'; // Required
dependencies?: number[]; // Optional, array of task indices
}
Required repository secrets:
PROJECT_URL=https://github.com/users/USERNAME/projects/1
Why 10?
If you have >10 tasks:
Problem: ❌ Invalid JSON format
Solution: Validate JSON syntax:
# Validate locally
cat plan.json | jq .
# If error, fix JSON syntax
# Common issues: missing commas, trailing commas, unquoted keys
Problem: ❌ Too many tasks (limit: 10)
Solution: Split into multiple plans:
// plan-part1.json (tasks 1-10)
{
"milestone": "Sprint 1 - Part 1",
"tasks": [...] // First 10 tasks
}
// plan-part2.json (tasks 11-20)
{
"milestone": "Sprint 1 - Part 2",
"tasks": [...] // Next 10 tasks
}
Problem: ❌ Missing required field: type
Solution: Ensure all tasks have required fields:
{
"title": "My task", // ✅ Required
"description": "Details", // ✅ Required
"acceptanceCriteria": ["..."], // ✅ Required
"type": "feature", // ✅ Required
"platform": "web", // ✅ Required
"priority": "high" // ✅ Required
}
Problem: ⚠️ Rate limit low (10 remaining)
Solution: Wait and retry:
# Check rate limit
gh api rate_limit
# Wait for reset (shown in response)
# Then retry workflow
Problem: ❌ PROJECT_URL not set
Solution: Set project board URL secret:
gh secret set PROJECT_URL
# Paste: https://github.com/users/USERNAME/projects/1
✅ DO:
❌ DON’T:
Auto-create feature branches from labeled issues
Automatically creates properly-named feature branches when issues are marked as ready to work on, streamlining the development workflow.
on:
issues:
types:
- labeled
Triggers when: An issue receives ANY label. Workflow then checks if BOTH required labels are present.
permissions:
contents: write
issues: write
pull-requests: read
claude-code AND status:ready labelstype:* labelfeature/, fix/, hotfix/, etc.feature/ if no type labeldev branchmain if dev doesn’t existbase:staging or base:main label{type}/issue-{number}-{slug}feature/issue-123-add-user-authenticationScenario: Issue created from plan
claude-code, status:ready, type:feature, platform:webfeature/issue-123-add-user-authenticationManual scenario:
# Create issue
gh issue create \
--title "Fix navigation bug" \
--body "Navigation crashes on mobile" \
--label "type:fix" \
--label "platform:mobile"
# Add required labels to trigger branch creation
gh issue edit 123 \
--add-label "claude-code" \
--add-label "status:ready"
# Branch automatically created: fix/issue-123-fix-navigation-bug
Branch naming patterns:
| Type Label | Branch Prefix | Example |
|---|---|---|
type:feature |
feature/ |
feature/issue-123-add-auth |
type:fix |
fix/ |
fix/issue-456-resolve-crash |
type:hotfix |
hotfix/ |
hotfix/issue-789-security-patch |
type:refactor |
refactor/ |
refactor/issue-101-clean-code |
type:docs |
docs/ |
docs/issue-202-update-readme |
type:test |
test/ |
test/issue-303-add-unit-tests |
Base branch detection (in order):
base:* label (e.g., base:staging)dev branchmain branchCustom base branch:
# Force branch to be created from staging
gh issue edit 123 --add-label "base:staging"
After branch is created, the bot comments:
## 🎉 Branch Created!
Your branch is ready: `feature/issue-123-add-user-authentication`
### Get Started
```bash
# Fetch and checkout the branch
git fetch origin
git checkout feature/issue-123-add-user-authentication
# Or create and track in one command
git checkout -b feature/issue-123-add-user-authentication origin/feature/issue-123-add-user-authentication
# Start working!
# Commit your changes
git add .
git commit -m "feat(auth): implement user authentication"
# Push to remote
git push origin feature/issue-123-add-user-authentication
# Create PR
gh pr create --base dev --fill
Remember to link this issue in your PR description!
#### Troubleshooting
**Problem**: Branch not created after labeling
**Solution**: Check both required labels are present:
```bash
# View issue labels
gh issue view 123
# Should show BOTH:
# - claude-code
# - status:ready
# Add missing label
gh issue edit 123 --add-label "claude-code"
gh issue edit 123 --add-label "status:ready"
Problem: ❌ Base branch 'dev' not found
Solution: Create dev branch or use main:
# Option 1: Create dev branch
git checkout -b dev main
git push origin dev
# Option 2: Use main as base
gh issue edit 123 --add-label "base:main"
# Then remove and re-add status:ready to retrigger
gh issue edit 123 --remove-label "status:ready"
gh issue edit 123 --add-label "status:ready"
Problem: Branch name too long or weird characters
Solution: This is automatic slug generation. The workflow:
If you need a different name, create branch manually:
git checkout -b feature/custom-name
git push origin feature/custom-name
Problem: ❌ Branch already exists
Solution: This is normal - workflow is idempotent. The branch was already created. Just checkout:
git fetch origin
git checkout feature/issue-123-whatever
✅ DO:
❌ DON’T:
claude-code label (breaks workflow)Sync PR lifecycle events with linked issues
Automatically updates issue status and project board as pull requests move through their lifecycle (opened, review, merged, closed).
on:
pull_request:
types:
- opened
- closed
- converted_to_draft
- ready_for_review
- reopened
branches:
- dev
pull_request_review:
types:
- submitted
branches:
- dev
Triggers when: PR events occur on PRs targeting dev branch.
permissions:
contents: write
pull-requests: write
issues: write
concurrency:
group: pr-sync-$
cancel-in-progress: true
Prevents: Multiple syncs running simultaneously for same PR.
Closes #123, Fixes #456, Resolves #789, Relates to #101PR Draft → Issues: "In Progress"
↓
PR Ready for Review → Issues: "In Review"
↓
PR Merged → Issues: "To Deploy" + Delete Branch
↓
(Later: main merge) → Issues: "Done" (via release-status-sync)
PR Closed (not merged) → Issues: "In Progress"
↓
PR Reopened → Issues: "In Review"
Scenario 1: Feature PR lifecycle
# Day 1: Create draft PR
gh pr create \
--draft \
--title "feat(auth): Add user authentication" \
--body "Closes #123"
# → Workflow runs
# → Issue #123 status: "In Progress" (draft PR)
# Day 2: Mark ready for review
gh pr ready
# → Workflow runs
# → Issue #123 status: "In Review"
# → Issue #123 comment: "PR ready for review"
# Day 3: PR approved and merged
gh pr merge --squash
# → Workflow runs
# → Issue #123 status: "To Deploy"
# → Branch deleted: feature/issue-123-add-auth
# → Issue #123 comment: "PR merged to dev"
Scenario 2: PR closed without merge
# Close PR
gh pr close 456
# → Workflow runs
# → Linked issues status: "In Progress"
# → Issue comment: "PR closed without merging"
# → Branch NOT deleted (can reopen)
Enable/disable branch deletion:
Edit .github/workflows/pr-status-sync.yml:
delete-merged-branch:
if: |-
always() &&
needs.fork-check.outputs.should-skip-writes != 'true' &&
github.event.pull_request.merged == true
&& false # ← Add this to disable
Protected branches (never deleted):
protected_branches:
- main
- master
- dev
- develop
- staging
- production
Adjust debounce delay:
- name: Wait 10 seconds to debounce automation loops
run: sleep 10 # ← Change to 5, 15, 20, etc.
Problem: Status not updating after PR merge
Solution: Check for linked issues in PR body:
# PR body must contain:
Closes #123
# or
Fixes #456
# or
Resolves #789
If missing, edit PR description and add.
Problem: ⚠️ No linked issues found
Solution: Edit PR description:
# Edit PR
gh pr edit 456 --body "$(cat << EOF
## Summary
This PR adds authentication.
Closes #123
Fixes #124
EOF
)"
Problem: Branch not deleted after merge
Solution: Check protected branch list. If your branch name matches a protected pattern, it won’t be deleted (this is by design). For feature branches, ensure they follow feature/*, fix/*, or hotfix/* pattern.
Problem: ❌ Infinite loop detected (rare)
Solution: The 10-second debounce prevents this, but if it occurs:
✅ DO:
❌ DON’T:
Close issues and create releases on production deployment
Automatically closes all linked issues, updates project board to “Done”, and creates GitHub releases when changes are deployed to production (merged to main).
on:
pull_request:
types:
- closed
branches:
- main
Triggers when: A PR targeting main is closed (checks for merge status internally).
permissions:
contents: write
issues: write
pull-requests: read
Closes #123, Fixes #456, Resolves #789package.jsonv{version}dev...main for changesIssues receive this comment when closed:
## 🚀 Released to Production!
This issue has been released to production in **v1.2.0**.
### 📋 Release Details
- **Release PR:** #456
- **Version:** 1.2.0
- **Released at:** 2025-11-06T10:30:00Z
- **Branch:** main
### 🎉 What's Next?
- Verify the fix/feature in production
- Monitor for any issues
- Close related tickets if applicable
---
🤖 _This issue was automatically closed by the release workflow_
Standard release flow:
# On dev branch - all features merged
git checkout dev
git pull origin dev
# Create release PR
gh pr create \
--base main \
--head dev \
--title "release: Version 1.2.0" \
--body "$(cat << EOF
## 🚀 Release v1.2.0
### Features
- User authentication (#123)
- Password reset (#124)
- Profile page (#125)
### Bug Fixes
- Navigation crash (#126)
- API timeout (#127)
Closes #123
Closes #124
Closes #125
Closes #126
Closes #127
EOF
)"
# After approval and merge:
gh pr merge 456 --squash
# → Workflow automatically:
# → Closes issues #123-127
# → Updates project board to "Done"
# → Creates GitHub release v1.2.0
# → Adds release comments to all issues
Using /release command:
# Simplified release command
/release
# → Prompts for version
# → Generates changelog
# → Creates release PR
# → Monitors merge
# → Triggers release-status-sync automatically
Version detection (in order):
package.json → version fieldCustomize version source:
Edit .github/workflows/release-status-sync.yml:
- name: Detect version from package.json
if: [ -f "package.json" ]; then
VERSION=$(jq -r '.version' package.json)
# Add custom version detection:
elif [ -f "VERSION" ]; then
VERSION=$(cat VERSION)
elif git describe --tags >/dev/null 2>&1; then
VERSION=$(git describe --tags --abbrev=0)
else
VERSION="unknown"
fi
Disable GitHub release creation:
Set version to “unknown” to skip:
- name: Create GitHub release
if: |-
needs.validate-release.outputs.version != 'unknown' &&
needs.close-issues.result == 'success'
&& false # ← Add to disable
Automatic changelog (generated from commits):
## 🚀 Release v1.2.0
This release includes changes from PR #456.
### 🎯 Changes
- feat(auth): add user authentication (abc1234)
- feat(auth): add password reset (def5678)
- fix(nav): resolve navigation crash (ghi9012)
- docs: update README (jkl3456)
### 🔗 Links
- **Release PR:** #456
- **Full Changelog:** [Compare view](../../compare/v1.1.0...v1.2.0)
---
🤖 _Release notes generated automatically_
Customize release notes:
Edit PR description with custom release notes - they’ll appear in the release.
Problem: ⏭️ PR was closed without merging
Solution: This is expected. Only merged PRs trigger releases. If you closed by accident:
# Reopen PR
gh pr reopen 456
# Merge it
gh pr merge 456 --squash
Problem: ⚠️ Source branch is not 'dev'
Solution: This workflow expects dev → main releases. If you use a different branching strategy, edit the workflow:
if [[ "$SOURCE_BRANCH" != "dev" ]]; then
echo "⚠️ Source branch is not 'dev' (got: $SOURCE_BRANCH)"
# Remove these lines to allow other branches:
# echo "is-release=false" >> $GITHUB_OUTPUT
# exit 0
fi
Or create a separate release workflow for your branching strategy.
Problem: ⏭️ Release v1.2.0 already exists
Solution: Version has already been released. Bump version:
// package.json
{
"version": "1.2.1" // ← Increment
}
Commit and push:
git add package.json
git commit -m "chore: bump version to 1.2.1"
git push
Problem: Issues not closing
Solution: Check for linked issues in release PR body:
# Must include:
Closes #123
Closes #124
Closes #125
Edit PR description if missing:
gh pr edit 456 --body "Closes #123\nCloses #124"
Problem: ❌ package.json not found - version unknown
Solution: This is not an error - release will still work, just without a version tag. To fix:
Option 1: Add package.json:
npm init -y
# Edit version
git add package.json
git commit -m "chore: add package.json"
Option 2: Use VERSION file:
echo "1.2.0" > VERSION
git add VERSION
git commit -m "chore: add VERSION file"
# Then update workflow to read VERSION file (see Configuration)
✅ DO:
❌ DON’T:
bootstrap.yml (one-time setup)
↓
├─→ Labels created
├─→ Project validated
└─→ Secrets validated
↓
└─→ claude-plan-to-issues.yml
↓
├─→ Creates issues (max 10)
├─→ Assigns labels
└─→ Adds to project board
↓
└─→ create-branch-on-issue.yml
↓
└─→ Auto-creates branches
↓
└─→ Developer works on branch
↓
└─→ Creates PR to dev
↓
├─→ pr-into-dev.yml (validation)
│ └─→ reusable-pr-checks.yml
│
└─→ pr-status-sync.yml (lifecycle)
↓
└─→ PR merged to dev
↓
└─→ Create release PR (dev → main)
↓
├─→ dev-to-main.yml (release gates)
│
└─→ PR merged to main
↓
└─→ release-status-sync.yml
↓
├─→ Closes issues
├─→ Updates project
└─→ Creates release
| Workflow | Triggers | Depends On | Modifies |
|---|---|---|---|
| bootstrap.yml | Manual | None | Labels, secrets validation |
| reusable-pr-checks.yml | Called | None | PR status checks |
| pr-into-dev.yml | PR opened to dev | reusable-pr-checks | PR status, comments |
| dev-to-main.yml | PR opened to main | None | PR status, artifacts |
| claude-plan-to-issues.yml | Manual | bootstrap | Issues, project board, milestone |
| create-branch-on-issue.yml | Issue labeled | bootstrap | Branches, issue comments, project |
| pr-status-sync.yml | PR events | None | Issues, project board, branches |
| release-status-sync.yml | PR merged to main | None | Issues, project board, releases |
✅ DO:
bootstrap.yml first thing❌ DON’T:
✅ DO:
❌ DON’T:
✅ DO:
❌ DON’T:
✅ DO:
❌ DON’T:
✅ DO:
❌ DON’T:
Change max 10 to max 15:
Edit .github/workflows/claude-plan-to-issues.yml:
- name: Validate plan
run: |
TASK_COUNT=$(echo "$PLAN_JSON" | jq '.tasks | length')
if [ "$TASK_COUNT" -gt 15 ]; then # ← Change from 10
echo "❌ Too many tasks: $TASK_COUNT (max: 15)"
exit 1
fi
Note: Higher limits consume more API calls.
Add custom prefixes:
Edit .github/workflows/create-branch-on-issue.yml:
case "$ISSUE_TYPE" in
"type:feature") BRANCH_PREFIX="feature" ;;
"type:fix") BRANCH_PREFIX="fix" ;;
"type:enhancement") BRANCH_PREFIX="enhance" ;; # ← Add custom
"type:experimental") BRANCH_PREFIX="exp" ;; # ← Add custom
*) BRANCH_PREFIX="feature" ;;
esac
Keep branches after merge:
Edit .github/workflows/pr-status-sync.yml:
delete-merged-branch:
if: |-
false # ← Disable completely
Or keep branches for specific types:
- name: Delete source branch
run: |
# Don't delete hotfix branches (for audit trail)
if [[ "$BRANCH_NAME" == hotfix/* ]]; then
echo "Keeping hotfix branch for audit"
exit 0
fi
Notify on releases:
Add to .github/workflows/release-status-sync.yml:
- name: Notify Slack
uses: slackapi/slack-github-action@v1
with:
webhook-url: $
payload: |
{
"text": "🚀 Released v$ to production!",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Released <https://github.com/$/releases/tag/v$|v$>"
}
}
]
}
Add performance tests:
Edit .github/workflows/reusable-pr-checks.yml:
performance-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-node-pnpm
- name: Run performance tests
run: pnpm run test:perf
- name: Check bundle size
run: |
BUNDLE_SIZE=$(du -sh dist | cut -f1)
echo "Bundle size: $BUNDLE_SIZE"
# Add size limit check here
Add staging environment:
Create .github/workflows/dev-to-staging.yml:
# Copy from dev-to-main.yml
# Change:
# - branches: main → branches: staging
# - Adjust quality gates as needed
Create .github/workflows/staging-to-main.yml:
# Minimal final checks before production
Update pr-status-sync and release-status-sync for new flow.
View workflow run logs:
# List recent runs
gh run list --limit 10
# View specific run
gh run view 1234567890
# Watch live
gh run watch 1234567890
Check rate limit:
gh api rate_limit
View repository secrets:
gh secret list
Test workflow locally (using act):
# Install act
brew install act
# Run bootstrap workflow
act workflow_dispatch -W .github/workflows/bootstrap.yml
Error: Resource not accessible by integration
Cause: Insufficient permissions in workflow.
Solution: Check permissions: block matches workflow needs:
permissions:
contents: write # For creating branches
issues: write # For updating issues
pull-requests: write # For PR comments
Error: GraphQL: Field 'Status' doesn't exist on type 'ProjectV2'
Cause: Project board doesn’t have a Status field.
Solution: Add Status field to your project board:
Error: API rate limit exceeded
Cause: Too many API calls in short time.
Solution:
gh api rate_limit)Error: Reference does not exist
Cause: Trying to create branch from non-existent base.
Solution: Ensure base branch exists:
# Check branches
git branch -a
# Create missing branch
git checkout -b dev main
git push origin dev
See individual workflow documentation above for specific troubleshooting scenarios.
✅ Workflows documented! You now understand all 8 automation workflows.
Continue Learning:
Get Started:
/blueprint-init to set up your repository/plan-to-issues to create issuesDocument Version: 1.0.0 Last Updated: 2025-11-06 Workflows Version: Phase 1 Complete