Orchestrates full PR workflow from local review through CI checks and external reviews to human sign-off readiness
Orchestrates the complete PR workflow from local review through CI checks and feedback resolution to sign-off readiness. Use this as a state machine that you can run repeatedly—it detects your current progress and continues from there, handling commits, PR creation, CI waiting, and feedback processing automatically.
/plugin marketplace add zookanalytics/claude-devcontainer/plugin install git-workflow@claude-devcontainerUser-provided context: $ARGUMENTS
--ready - Mark PR as ready for review and trigger CI.
Without this flag, PRs remain as drafts.By default, PRs are created and kept as drafts to conserve GitHub Action minutes during iteration.
Use --ready when confident the PR is ready for CI and review.
This command orchestrates the complete pull request workflow as an idempotent state machine. Run it multiple times - it detects current state and continues from where you left off.
Phases (without --ready): Self-Review → Draft PR Creation → Report (CI skipped)
Phases (with --ready): Self-Review → PR Creation → Mark Ready → CI + Copilot → External Feedback → Ready for Sign-off
Key loop: After addressing feedback, return to Phase 3 (CI + Copilot) for re-validation.
Use TodoWrite to create a checklist tracking workflow progress.
Example checklist items:
Run these commands in parallel (no dependencies between them):
# Group 1: Independent queries (run all in parallel)
git status --porcelain # Uncommitted changes
git branch --show-current # Current branch
git fetch origin # Fetch latest remote state
After fetch completes, run these in parallel:
# Group 2: Depends on fetch (run all in parallel)
git log origin/main..HEAD --oneline # Commits ahead of main
git merge-base --is-ancestor origin/main HEAD && echo "AHEAD_OR_EQUAL"
git merge-base --is-ancestor HEAD origin/main && echo "BEHIND_OR_EQUAL"
# Interpretation: both succeed = EQUAL, first only = AHEAD, second only = BEHIND, neither = DIVERGED
If on a feature branch, also run:
# Group 3: PR status (run in parallel with Group 2 if branch known)
gh pr list --head <branch-name> --json number,state,isDraft --jq '.[0]'
gh pr view <number> --json statusCheckRollup,reviews,comments,isDraft # If PR exists
State determination:
| Condition | State | Action |
|---|---|---|
| Uncommitted changes exist | uncommitted | Run /git:commit, then continue |
| No commits ahead of main | nothing-to-do | STOP - nothing to review |
| On main with commits, branches have diverged | needs-branch | Start at Phase 1 |
| On feature branch, no PR exists | needs-review | Start at Phase 1 |
PR exists, is draft, no --ready flag | draft | Self-review only, report draft status |
PR exists, is draft, --ready flag provided | draft-ready | Mark ready, proceed to Phase 3 |
| PR exists, not draft, CI/Copilot pending | checks-pending | Wait for CI and Copilot |
| PR exists, not draft, CI failed | ci-failed | Fix failures |
| PR exists, checks passed, unresolved threads | merge-blocked | Address ALL threads |
| PR exists, checks passed, no unresolved threads | ready | Report completion |
CRITICAL: The
merge-blockedstate means unresolved review threads block the merge. This is NOT about "requiring approving review" - it's about ALL review comments being resolved. GitHub branch protection rules require all Copilot (and other reviewer) threads to be resolved before merge is allowed.
After state detection, validate the session purpose matches the work being orchestrated.
Sources for purpose (in priority order):
feat/automerge-crdt-integration → "Automerge CRDT Integration"Check and update:
# Read current purpose
cat .claude-metadata.json 2>/dev/null | jq -r '.purpose // empty'
# If purpose is empty, stale, or doesn't match the work, update it
./scripts/claude-instance purpose "<derived-purpose>"
Keep purpose broad - describes the overall goal, not specific steps. Examples:
uncommitted StateWhen uncommitted changes exist (staged or unstaged):
/git:commit to commit the changes
pnpm fix, analyzes staging, creates atomic commitThis allows orchestrate to take over from any working state - user doesn't need to manually commit before running orchestrate.
needs-branch StateWhen on main with local commits and origin/main has diverged:
/git:create-pull-request) handles branch creation and rebaseThe needs-branch state does NOT skip self-review.
Phase 2 will:
draft State (no --ready flag)When PR is draft and --ready flag not provided:
Self-review complete. PR remains in draft mode.
PR: #<number> - <title>
URL: <url>
CI is skipped for draft PRs to conserve GitHub Action minutes.
When ready for CI and review:
- Run: /git:orchestrate --ready
- Or manually: gh pr ready <number>
Rationale: Allows frequent self-review cycles without burning CI minutes.
draft-ready State (--ready flag provided)When PR is draft and --ready flag provided:
gh pr ready <number>Entry: State is needs-review or needs-branch (committed but no PR yet)
Goal: Catch issues before external reviewers see them.
Use the slash command, not just a skill. The
/superpowers:review-branchcommand executes the full review workflow. You MUST run the command.
Run /superpowers:review-branch which will:
Exit criteria:
Transition: → Phase 2
Entry: Self-review complete, no PR exists
If --ready flag provided:
Run /git:create-pull-request --ready to:
Otherwise (default - create as draft):
Run /git:create-pull-request to:
Capture PR number and URL for tracking.
Transition:
--ready flag: → Phase 3 (Wait for CI)--ready flag: → Report draft status and STOPEntry: PR exists, awaiting CI completion and Copilot review
Use the timeline and requested_reviewers APIs to accurately detect Copilot status:
# Get Copilot events from timeline (review_requested and reviewed)
gh api repos/{owner}/{repo}/issues/{pr}/timeline --jq '
[.[] | select(
(.event == "review_requested" and .requested_reviewer.login == "Copilot") or
(.event == "reviewed" and .user.login == "Copilot")
)] | sort_by(if .event == "reviewed" then .submitted_at else .created_at end)'
# Check if Copilot is in pending reviewers
gh api repos/{owner}/{repo}/pulls/{pr}/requested_reviewers --jq '
.users[] | select(.login == "Copilot")'
Copilot Status Determination:
| Condition | Status | Action |
|---|---|---|
Copilot in requested_reviewers | In Progress | Wait for completion |
review_requested after latest reviewed | Re-reviewing | Wait for completion |
reviewed exists, not in requested_reviewers | Complete | Check for feedback |
No review_requested for Copilot | Not Triggered | Wait up to 5 min |
Poll CI and Copilot status every 30 seconds:
Get current PR state:
gh pr view <number> --json headRefOid,statusCheckRollup,reviews
Check CI status:
SUCCESS or SKIPPED → CI passedFAILURE → CI failedCheck Copilot status (using timeline + requested_reviewers as above)
Note:
statusCheckRollupcontainsCheckRun(.conclusion) andStatusContext(.state) - use.conclusion // .stateto handle both.
Timeouts:
review_requested (typical: 30s-5min)Decision Matrix:
| CI Status | Copilot Status | Timeout? | Action |
|---|---|---|---|
| ✅ Passed | ✅ Complete | Any | → Phase 4 (check feedback) |
| ✅ Passed | ⏳ In Progress | No | Continue waiting |
| ✅ Passed | ⏳ In Progress | Yes | → Phase 4 (proceed anyway) |
| ✅ Passed | ❓ Not Triggered | < 5 min | Wait for auto-trigger |
| ✅ Passed | ❓ Not Triggered | ≥ 5 min | → Phase 4 (no review expected) |
| ⏳ Pending | Any | Any | Continue waiting for CI |
| ❌ Failed | Any | Any | → Handle CI Failure |
Exit: CI passed AND (Copilot complete OR in-progress timeout OR not-triggered grace period)
If Copilot in-progress timeout reached:
If Copilot never triggered:
review_requested eventgh run view <run-id> --log-failed/git:commitgit pushRetry limit: 3 attempts per unique failure type. After limit: STOP and report to user.
Entry: CI passed and Copilot reviewed (or timeout)
Query GitHub for unresolved review threads:
gh api graphql -f query='...' --jq '...' # See /git:receiving-code-review for full query
CRITICAL: Unresolved threads block PR merges. You MUST resolve ALL threads before the PR can be merged.
Run /git:receiving-code-review <pr-number> to:
See /git:receiving-code-review for complete workflow details.
After command completes:
Verify all threads resolved (command should do this, but double-check):
gh api graphql ... | jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length'
If threads remain unresolved:
/git:receiving-code-review ORCommit any changes: /git:commit
Push to update PR: git push
→ Return to Phase 3 (wait for CI and Copilot to re-review)
Common mistake: Claiming work is "done" without verifying threads are resolved. Check unresolved thread count FIRST before diagnosing merge blocks.
Proceed to Phase 5 (Ready for Sign-off).
Entry: CI passing, all feedback addressed (or none received)
Final verification:
gh pr view <number> --json state,statusCheckRollup,reviews,mergeable
Completion criteria:
| Check | Required |
|---|---|
| PR state | OPEN |
| All CI checks | SUCCESS or SKIPPED |
| Mergeable | MERGEABLE |
| Unresolved threads | 0 (or escalated to user) |
Final Report:
## PR Ready for Sign-off
**PR:** #<number> - <title>
**URL:** <url>
**Branch:** <branch-name> → main
### Verification Complete
| Phase | Status |
| ----------------- | --------------------------- |
| Self-Review | ✓ Complete |
| CI + Copilot | ✓ All passing |
| External Feedback | ✓ Addressed / None received |
### Changes Summary
<1-3 sentence summary of what the PR accomplishes>
### Commits
<list of commits in PR>
### Escalated Items
<list any items that need human decision, or "None">
### Next Steps
Human review and approval, then:
- Merge: `/git:merge-pull-request`
Prevent infinite loops:
| Limit | Value | On Exceed |
|---|---|---|
| CI fix attempts | 3 per failure type | Ask user |
| Feedback cycles | 5 round-trips | Ask user |
| Copilot wait | 10 minutes | Proceed without |
| CI wait | None | Wait indefinitely |
This command is idempotent - run it multiple times safely.
On re-run:
Example re-run scenarios:
If PR merge fails, diagnose in priority order:
Common mistake: Assuming "requires approving review" without checking unresolved threads first. Copilot review comments are the most common merge blocker.
After 3 fix attempts for same failure:
CI continues to fail after 3 fix attempts.
Failure: <check name>
Error: <error summary>
Options:
1. Show full error log
2. I'll investigate manually
3. Skip this check (not recommended)
If feedback requires architectural decisions: