resolve-pr-feedback-bubbles
Scannednpx machina-cli add skill n1ddeh/fantastic-skills/resolve-pr-feedback-bubbles --openclawAddress PR Comments
Discover all active PRs with unresolved review comments, dispatch parallel agents to evaluate and resolve each PR's feedback, then present a summary with drafted replies for approval.
Options
--auto-reply— Skip all user confirmation prompts and automatically proceed at every step: PR list confirmation, reply approval (post all drafted replies including disagree), and summary comments. Bubbles handles everything end-to-end without pausing.
Process
Phase 1: Discovery
-
Find eligible PRs using
open-graphite-stacks:Invoke the
open-graphite-stacksskill to get all open PRs grouped by repo and stack. Filter to PRs whereresolvedThreads < totalThreads(i.e., unresolved threads exist). Skip draft PRs (marked[DRAFT]). -
Fetch unresolved review threads per PR via GraphQL:
{ repository(owner: "{owner}", name: "{repo}") { pullRequest(number: {number}) { body reviewThreads(first: 100) { nodes { id isResolved comments(first: 20) { nodes { id databaseId body author { login } path line } } } } } } }A PR is eligible if it has any
isResolved: falsereview threads. -
Detect local repo paths and extract owner/repo. Resolve repo paths using the following priority order:
- Automation clones (preferred — isolated from user's working tree):
~/.claude/repos/{repoName} - User working directories:
~/Documents/projects/**/{repoName},~/{repoName}
Always prefer automation clones when they exist. These are dedicated clones that the skill can modify freely without affecting the user's active work (uncommitted changes, current branch, mid-rebase state). Before using an automation clone, sync it:
cd {localRepoPath} git fetch --all --pruneIf an automation clone does not exist for a repo, fall back to the user working directory. If neither is found, skip the repo and report it in the summary.
For each found repo, extract the GitHub owner and repo name from the git remote:
git -C {localRepoPath} remote get-url origin # git@github.com:YourOrg/your-repo.git → owner=YourOrg, repo=your-repo # https://github.com/YourOrg/your-repo.git → owner=YourOrg, repo=your-repoParse the URL (SSH or HTTPS) to extract
{owner}and{repo}. Use these values in all subsequent GraphQL and REST API calls (gh api repos/{owner}/{repo}/...). - Automation clones (preferred — isolated from user's working tree):
-
Display the eligible PR list (number, title, repo, comment count) before proceeding. If
--auto-replyis set, proceed immediately. Otherwise, wait for user confirmation.
Phase 2: Agent Dispatch
Stacks and standalone PRs are handled differently. Dispatch all agents in parallel:
- One orchestrator agent per stack (sequential, trunk-to-tip)
- One agent per standalone PR (parallel, same as before)
Stack Orchestrator Workflow
Each stack orchestrator receives:
- The ordered list of eligible PRs in the stack (trunk-to-tip), each with unresolved comment details and branch name
- The local repo path
The orchestrator works through PRs sequentially, starting from position [1] (closest to trunk). For each PR in order:
Step 1 — Get branch:
cd {localRepoPath}
gt get {branchName}
Step 2 — Gather context:
- Extract Linear ticket ID from branch name (pattern:
[A-Z]+-\d+) - If found, use the Linear MCP
get_issuetool to fetch issue details andlist_comments - Read the PR description for requirements and scope
Step 3 — Evaluate each unresolved comment (same logic as standalone, see below)
Step 4 — Update and run tests:
- If any code changes were made, check for related test files and update them if needed
- Run the relevant tests and verify they pass before proceeding
- If tests fail, fix the implementation until they pass
Step 5 — Commit:
- If any code changes were made:
gt modify -c -m "[bot] 🐳 address review feedback on PR #{number}" - If no code changes, skip
Step 6 — Restack: After committing (or if no changes), run:
gt restack
This rebases all upstack branches onto the new commit. If merge conflicts arise, resolve them before continuing to the next PR.
Step 7 — Move to next PR and repeat Steps 1–6.
Step 8 — Submit the entire stack after all PRs are addressed:
gt submit --stack --no-interactive
Step 9 — Return structured report for all PRs in the stack (same format as standalone report below).
Standalone PR Agent Workflow
Dispatch one Task subagent per eligible standalone PR in parallel. Each agent receives:
- The PR number, repo, branch name, and local repo path
- The list of unresolved review thread comments
- The PR body/description
Step 1 — Create worktree:
cd {localRepoPath}
git fetch origin {branchName}
git worktree add .worktrees/pr-{number} origin/{branchName}
Verify .worktrees/ is gitignored with git check-ignore .worktrees. If not, add it to .gitignore first.
Step 2 — Gather context:
- Extract Linear ticket ID from branch name (pattern:
[A-Z]+-\d+) - If found, use the Linear MCP
get_issuetool to fetch issue details andlist_comments - Read the PR description for requirements and scope
Step 3 — Evaluate each unresolved comment:
- Read the file at the path referenced by the comment
- Read surrounding code — callers (1 level up), types, related files in the same module
- Understand the reviewer's intent: code fix request, question, style nit, or architectural concern
- Assess merit before acting. For every comment (including concrete code-fix requests), ask:
- Does this change improve correctness, readability, or safety?
- Does it align with the Linear ticket's scope and intent?
- Could it introduce regressions, over-engineering, or unnecessary churn?
- Is there existing code context the reviewer may not have seen?
- Categorize:
code-fix— reviewer's request is valid; implement itdiscussion— architectural concern, question, or open-ended topic that needs a thoughtful replyacknowledged— simple agreement ("good point, fixed")disagree— Bubbles believes the ask is incorrect, out of scope, or would make things worse after careful evaluation
- If
code-fix: Implement the change, stage it - If
disagree: Do NOT implement the change. Instead, draft a reply that:- Acknowledges the reviewer's perspective and the concern behind it ("Bubbles can see why this looks like X…")
- Explains the reasoning for disagreeing — citing specific code context, ticket scope, or downstream effects
- Offers an alternative if one exists, or explains why the current approach is preferable
- Keeps the door open ("happy to chat more if Bubbles is missing something!")
- Tone: warm, curious, never dismissive. Bubbles genuinely wants to understand the reviewer's angle, even when disagreeing.
- For all categories: Draft a reply in the voice of Bubbles 🐳. Always prefix with
[bot] 🐳 Bubblesand write in third person (e.g., "[bot] 🐳 Bubbles fixed the off-by-one error —inow starts at 0 instead of 1"). For code fixes, confirm what was changed. For discussion, form a position based on code understanding and Linear context. For disagree, follow the guidelines in step 7.
Step 4 — Update and run tests:
- If any code changes were made, check for related test files and update them if needed
- Run the relevant tests and verify they pass before proceeding
- If tests fail, fix the implementation until they pass
Step 5 — Commit and push:
- If any code changes were made:
git add -A && git commit -m "address review feedback on PR #{number}"thengit push origin {branchName} - If no code changes, skip
Step 6 — Return structured report:
PR #{number} — {title}
URL: {prUrl}
Commit: {sha or "no changes"}
⚠️ Disagreements (review before posting):
1. [disagree] {file}:{line} — @{reviewer}
Comment: {first 100 chars of body}...
Bubbles' reasoning: {why Bubbles disagrees}
Draft reply: [bot] 🐳 Bubbles {the drafted reply text}
Comments:
1. [{category}] {file}:{line} — @{reviewer}
Comment: {first 100 chars of body}...
Action: {what was done}
Draft reply: [bot] 🐳 Bubbles {the drafted reply text}
2. [{category}] ...
Step 7 — Cleanup worktree:
cd {localRepoPath}
git worktree remove .worktrees/pr-{number}
Phase 3: Summary and Approval
After all agents (stack orchestrators and standalone agents) complete:
-
Present per-PR summary:
- PR title + URL
- Comment breakdown: code-fix / discussion / acknowledged counts
- Commit SHA if code was pushed
- Each comment with reviewer, snippet, category, action, and draft reply
-
Reply approval flow:
- If
--auto-replyis set, skip the presentation and post all drafted replies immediately (including disagree) - Otherwise, present
disagreereplies first, grouped separately with a ⚠️ header — these need the most attention - Then present all other drafted replies grouped by PR
- Ask user to approve all, approve individually, edit, or skip
- Post approved replies (or all replies if
--auto-reply) via:gh api repos/{owner}/{repo}/pulls/{number}/comments -f body="{reply}" -F in_reply_to={commentDatabaseId} - After posting each reply, resolve the thread using the GraphQL thread node
id:gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: "{threadNodeId}"}) { thread { isResolved } } }'
- If
-
Post summary comment on each PR:
After posting replies for a PR, automatically post a top-level PR summary comment (no user confirmation needed). This gives reviewers a single place to see everything Bubbles did.
The comment must include:
- The
## [bot] 🐳 Bubbles' Summaryheading is always visible - Everything else is wrapped in a
<details>tag with<summary>What Bubbles did</summary>so it's collapsed by default - Stats: comment counts by category (code-fix / discussion / acknowledged / disagree)
- Commit SHA if code was pushed, or "no code changes" if not
- A list of each comment addressed with category, file:line, and a one-line summary of the action taken
- If any
disagreeitems exist, a separate subsection highlighting them with Bubbles' reasoning
gh api repos/{owner}/{repo}/issues/{number}/comments -f body="$(cat <<'EOF' ### [bot] 🐳 Bubbles' Summary <details> <summary>**What Bubbles did**</summary> | Stat | Count | |------|-------| | Code fixes | 2 | | Discussions | 1 | | Acknowledged | 0 | | ⚠️ Disagreements | 1 | **Commit:** `abc1234` — address review feedback on PR #2580 ### Changes made - [code-fix] `src/path/File.tsx:42` — Added null check on `user.profile` per @reviewer's catch - [discussion] `src/path/Service.ts:88` — Bubbles explained why the retry logic uses exponential backoff here - [disagree] `src/path/OtherFile.tsx:15` — Bubbles respectfully pushed back on extracting this to a util (see thread for reasoning) </details> EOF )" - The
-
Re-request reviews:
After posting replies and the summary comment for each PR, re-request review from the humans who left the addressed comments. This notifies them that Bubbles has responded.
Collect the unique reviewer logins from the addressed comment threads (exclude the PR author and bots like
coderabbitai,graphite-app,github-actions). Then:gh api repos/{owner}/{repo}/pulls/{number}/requested_reviewers \ -f 'reviewers[]=reviewer1' -f 'reviewers[]=reviewer2'If no human reviewers remain (e.g., all comments were from the PR author or bots), skip this step. Log which reviewers were re-requested in the final report.
-
Final report:
## PR Comments Addressed ### PR #2580 — PROJ-123 Refactor e2e tests - 4 comments: 2 code fixes (pushed abc1234), 1 discussion, ⚠️ 1 disagree - Replies: 4 posted - Summary comment: posted ### Skipped - PR #2587 — no unresolved comments - my-frontend — repo not found locally
Important Notes
- Filter comments by
isResolved: falseusing the GraphQL API (REST API does not expose resolution status) - Bot comments (coderabbitai, graphite-app, etc.) should be evaluated like human comments — they often contain valid code fixes
- Skip comments that are replies (non-root comments in a thread) — only evaluate the root comment of each thread
- When implementing code fixes, verify the suggestion makes sense in context before applying blindly
- The
in_reply_tofield for posting replies uses the REST APIdatabaseId, not the GraphQL nodeid - Stack ordering matters: Always address the trunk-most PR first. Changes to a lower PR affect all branches above it —
gt restackpropagates them upward - Do not post replies for stack PRs until after
gt submit --stack— submitting updates the remote branches; replies posted before that may reference stale diffs - Stack orchestrators use
gt checkoutto switch branches directly in the working tree — do NOT use worktrees for stack PRs, as Graphite tracks branch relationships in the repo root - Automation clones (
~/.claude/repos/{repoName}) are the preferred working directory. Alwaysgit fetch --all --prunebefore starting work in an automation clone. These clones exist specifically so that the skill can run without interfering with the user's active working tree, uncommitted changes, or current branch
Source
git clone https://github.com/n1ddeh/fantastic-skills/blob/main/resolve-pr-feedback-bubbles/SKILL.mdView on GitHub Overview
This skill automatically handles PR review feedback by drafting replies, applying code fixes, and pushing back when suggestions would worsen outcomes. It coordinates multiple agents in parallel, and can run end-to-end in auto mode to save time on PR back-and-forth.
How This Skill Works
It discovers open PRs with unresolved review threads using open-graphite-stacks and GraphQL, then resolves repo paths by preferring automation clones. It drafts replies, applies fixes via code changes, and uses REST calls to post updates, then dispatches stack orchestrators and per-PR agents to process PRs in trunk-to-tip order.
When to Use It
- You have a backlog of PRs with unresolved review comments across multiple repos
- You want end-to-end automation using --auto-reply to post replies and fixes without prompts
- You need drafted replies and potential code changes pushed back to PRs
- You manage multiple repos and need to derive owner/repo from git remotes for API calls
- You want a summarized report of addressed PR feedback after processing
Quick Start
- Step 1: Run the skill with optional --auto-reply to skip prompts
- Step 2: It discovers eligible PRs, drafts replies, and applies fixes in parallel
- Step 3: Review the generated summary or let it auto-post if --auto-reply is used
Best Practices
- Keep automation clones up to date by syncing before processing (git fetch --all --prune)
- Prefer automation clones over user working directories to avoid disrupting active work
- Review drafted replies and fixes before posting unless using --auto-reply
- Validate remote URL parsing to reliably extract owner and repo for API calls
- Test on a small set of PRs before scaling to a larger backlog
Example Use Cases
- Auto-resolve feedback on a frontend PR with multiple unresolved threads across files
- Process feedback across several repos in one stack and draft unified replies
- Draft replies and apply minor code fixes for a backend refactor with reviewer comments
- Generate a concise summary of PR feedback after batch processing
- Use --auto-reply to push all drafted replies and fixes without manual prompts