process-pr
Process PR
Autonomous loop that picks up ai-approved PRs, performs a final verification pass, and either merges them or sends them back to process-issues for rework.
This is the last gate before code lands. The two checks are intentionally narrow — the heavy review already happened in code-review. This skill only verifies:
- Issue resolution — does the PR actually address what the linked issue asked for?
- Merge readiness — is the PR free of merge conflicts and has CI passed?
If both pass, merge. If either fails, send the PR back with a clear explanation so process-issues can fix it.
Comment Authorship
All comments posted by this workflow run under the same GitHub account as the user. To distinguish AI comments from human comments, every comment posted by AI MUST start with **[AI]**. When reading comments, use this rule:
- Starts with
**[AI]**→ posted by AI (previous runs) - Does NOT start with
**[AI]**→ posted by a human
Worktree Isolation
This skill MUST run in its own git worktree to avoid conflicts with other parallel Claude instances.
Before starting, check if already in a worktree:
git rev-parse --show-toplevel
If NOT already in a worktree for this skill, create one and switch to it using the EnterWorktree tool (if available). If EnterWorktree is not available, create one manually and prefix ALL subsequent commands with cd <worktree-path> &&:
WORKTREE=$(git rev-parse --show-toplevel)/../$(basename "$(git rev-parse --show-toplevel)")-merge
git worktree add --detach "$WORKTREE" main 2>/dev/null || true
Using --detach is important because main is typically already checked out in the primary worktree — git worktree add "$WORKTREE" main will silently fail in that case.
Then for every command in this skill, prefix with:
cd $WORKTREE && <command>
This is necessary because cd does not persist between Bash calls.
Loop Cycle
Each cycle:
- Pre-flight checks — verify the environment is ready
- Find PRs labeled
ai-approved - Verify each PR (issue resolution + merge readiness)
- Act — merge or send back
- Report what happened
Phase 0: Pre-flight Checks
Run these before every cycle. If any fail, stop and report the problem.
# Clean up stale worktrees
git worktree prune
# Check gh is authenticated
gh auth status
# Check working tree is clean
git status --porcelain
If git status --porcelain produces output, stop: "Working tree is dirty. Commit or stash changes before running."
If gh auth status fails, stop: "GitHub CLI is not authenticated. Run gh auth login."
Ensure required labels exist:
for label in ai-ready ai-in-progress ai-done ai-blocked ai-needs-input needs-ai-review ai-changes-requested ai-approved prd; do
gh label create "$label" 2>/dev/null || true
done
Check for the ai-pause label — create it to pause, delete it (gh label delete ai-pause -y) to resume:
gh label list --search "ai-pause" --json name --jq '.[].name' | grep -qx "ai-pause"
The --search flag is a fuzzy substring match (it returns labels like ai-ready, ai-done too), so pipe through grep -qx for an exact match. If grep matches, the label exists — stop. If grep exits non-zero, no exact match — proceed.
If the ai-pause label exists, stop: "ai-pause label detected. Stopping gracefully. Delete the label (gh label delete ai-pause -y) to resume."
Set up the repo variable for API calls used later:
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
Phase 1: Find PRs to process
gh pr list --state open --label "ai-approved" --json number,title,url,isDraft,headRefName --limit 50
Filter out draft PRs. Process up to 5 PRs per cycle — if more remain, they'll be handled in the next cycle.
If no PRs are found, report "No ai-approved PRs to process" and stop (or loop back if running with /loop).
Phase 2: Verify each PR
For each PR, run two checks. Both must pass for the PR to be merged.
2A. Check issue resolution
Extract the linked issue number from the PR body. Look for Closes #N, Fixes #N, or Resolves #N:
gh pr view <number> --json body --jq '.body'
If no linked issue is found, the PR cannot be verified — send it back:
gh pr comment <number> --body "$(cat <<'EOF'
**[AI]** Cannot verify this PR — no linked issue found in the PR body.
Please add `Closes #<issue-number>` to the PR description so I can verify the changes match the requirements.
EOF
)"
gh pr edit <number> --remove-label "ai-approved" --add-label "ai-changes-requested"
Skip to the next PR.
If a linked issue is found, read both the issue and the PR diff:
gh issue view <issue-number> --json title,body
gh pr diff <number>
Compare the issue requirements against the actual changes. This is a focused check — the full code review already happened. You're answering one question: do these changes address what the issue asked for?
Things that indicate the issue is NOT resolved:
- The issue asked for feature X, but the PR implements something different
- The issue lists multiple requirements and one or more are missing from the changes
- The PR only partially implements what was asked (e.g., backend done but frontend missing, when both were required)
Things that are fine and should NOT block merge:
- Minor implementation differences from the issue description (the issue describes the "what", not the "how")
- Additional improvements beyond what the issue asked for
- Style differences from what the issue suggested
If the changes don't resolve the issue, send the PR back with specifics about what's missing.
2B. Check merge readiness
Check the PR's merge status via the GitHub API:
gh pr view <number> --json mergeable,mergeStateStatus,statusCheckRollup
Interpret the results:
Merge conflicts (mergeable is CONFLICTING):
The PR has conflicts with the base branch. Send it back — process-issues will need to rebase or resolve conflicts.
CI failing (mergeStateStatus is UNSTABLE or check rollup shows failures):
Check the specific failures:
gh pr checks <number> --json name,state,bucket
If checks are failing, send the PR back — process-issues will need to fix the failures.
Behind base branch (mergeStateStatus is BEHIND):
This is not a blocker if there are no conflicts. GitHub will handle the merge. Proceed.
No CI checks (statusCheckRollup is empty []):
The repo has no CI configured. This is not a blocker — proceed if mergeable is MERGEABLE.
Clean (mergeStateStatus is CLEAN and mergeable is MERGEABLE):
Ready to merge.
Unknown (mergeable is UNKNOWN):
GitHub hasn't computed the merge status yet. Wait a few seconds and retry once:
sleep 5
gh pr view <number> --json mergeable,mergeStateStatus
If still unknown after retry, skip this PR for now — it will be picked up in the next cycle.
Phase 3: Act
If both checks pass → Merge
Use the --repo flag to avoid failures when the worktree is in detached HEAD state (which is the common case — gh pr merge without --repo fails with "not on any branch"):
gh pr merge <number> --squash --delete-branch --repo $REPO
If the merge command exits non-zero, check whether the PR was actually merged (GitHub may have completed the server-side merge before the local error):
gh pr view <number> --json state --jq '.state'
If the state is MERGED, the merge succeeded despite the error — proceed normally. If it's still OPEN, the merge truly failed — send the PR back with the error message.
The Closes #N in the PR body will automatically close the linked issue when the PR is merged.
After merging, check the issue state:
gh issue view <issue-number> --json state --jq '.state'
If the issue was auto-closed by the merge, no label cleanup is needed. If it's still open for some reason, update it:
gh issue edit <issue-number> --remove-label "ai-done"
gh issue close <issue-number>
Update local state to stay current:
git fetch origin main
git reset --hard origin/main
If either check fails → Send back
Remove ai-approved and add ai-changes-requested so process-issues picks it up in its Phase A:
gh pr edit <number> --remove-label "ai-approved" --add-label "ai-changes-requested"
Post a comment explaining exactly what failed. The comment should be actionable — process-issues will read it to understand what to fix:
If issue not resolved:
gh pr comment <number> --body "$(cat <<'EOF'
**[AI]** Final verification failed — PR does not fully resolve the linked issue.
**Issue:** #<issue-number> — <issue-title>
**What's missing:**
- <specific requirement from the issue that isn't addressed>
Sending back for rework.
EOF
)"
If merge conflict:
gh pr comment <number> --body "$(cat <<'EOF'
**[AI]** Final verification failed — merge conflict detected.
Please rebase onto main and resolve conflicts.
Sending back for rework.
EOF
)"
If CI failing:
gh pr comment <number> --body "$(cat <<'EOF'
**[AI]** Final verification failed — CI checks are failing.
**Failing checks:**
- <check name>: <failure summary>
Sending back for rework.
EOF
)"
Also update the linked issue label back to ai-ready so process-issues treats it as actionable (it won't pick up the PR feedback otherwise since the issue would still be labeled ai-done):
gh issue edit <issue-number> --remove-label "ai-done" --add-label "ai-ready"
gh issue comment <issue-number> --body "**[AI]** PR #<number> sent back for rework: <brief reason>. Resetting to ai-ready."
Phase 4: Report
After processing all PRs in this cycle, report a summary:
Processed N PRs:
- #123 "Add user auth" → merged
- #456 "Fix pagination" → sent back (merge conflict)
- #789 "Update docs" → sent back (missing requirement: API docs not updated)
Then loop back to Phase 0 for the next cycle.
Usage with /loop
/loop 10m /process-pr
Safety Rails
- Only merge PRs that are labeled
ai-approved— never merge PRs that haven't been through code review - Always use
--squashmerge to keep history clean - Always
--delete-branchafter merge to clean up - If a
ghcommand fails with HTTP 403 or "rate limit exceeded", stop the current cycle and report: "GitHub API rate limit hit. Wait before retrying." Do not retry immediately. - Never force push
- If the merge command fails, check
gh pr view --json statebefore giving up — the merge may have completed server-side despite the local error. Only send back if the PR is stillOPEN - Skip draft PRs even if labeled
ai-approved
More from hifisaputra/skills
brainstorm-to-issues
Interactive brainstorming session that refines an idea into a PRD and breaks it into GitHub issues labeled ai-ready. Use when user wants to brainstorm, plan a feature, has an idea to discuss, says "brainstorm", "let's plan", "I have an idea", or wants to break work into issues.
15code-review
Thorough code review of a PR — checks correctness, security, performance, style consistency, test coverage, and verifies the PR addresses its linked issue. Use when user says "review this PR", "check this PR", "look at this diff", or any request to review code changes.
11process-issues
Autonomous loop that picks up ai-ready GitHub issues, handles PR feedback, and asks clarifying questions when blocked. Use when user says "work issues", "start working", "process backlog", or wants AI to autonomously implement GitHub issues.
9process-reviews
Autonomous loop that finds PRs needing AI review and delegates to the code-review skill. Use when user says "review PRs", "start reviewing", "check for PRs to review", "process reviews", or wants AI to continuously monitor and review PRs.
9code-implementation
Implements a code task using a structured plan-first approach with TDD when tests exist, or direct implementation for docs/config changes. Use when user says "implement this", "build this feature", "fix this bug", or any request to write code for a well-defined task.
9work-issues
Autonomous loop that implements ai-ready GitHub issues, handles PR feedback, and asks clarifying questions when blocked. Use when user says "work issues", "start working", "process backlog", or wants AI to autonomously implement GitHub issues.
5