一键导入
fetch-pr-feedback
Fetch unresolved review comments from a PR and evaluate with receive-feedback skill
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Fetch unresolved review comments from a PR and evaluate with receive-feedback skill
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when you need a bite-sized, TDD-driven implementation plan but do NOT have a brainstorm-beagle spec to plan against. quick-plan reconstructs intent from the current conversation, fans out domain-expert exploration subagents across the codebase, and synthesizes the same plan format write-plan produces — without requiring `.beagle/concepts/<slug>/spec.md`. Triggers on: "quick plan", "plan this out", "plan what we just discussed", "turn this into an implementation plan", "plan this without a spec", "I don't have a spec, just plan it", "write-plan but no spec". Make sure to use this skill whenever the user wants an implementation or TDD plan and there is no spec to plan against — even if they just say "plan it" after discussing a feature. Writes to `.beagle/plans/<slug>/plan.md`. If a finalized spec already exists at `.beagle/concepts/<slug>/spec.md`, prefer write-plan. Does NOT brainstorm specs, write code, or execute the plan — produces the plan document (and an optional handoff prompt) only.
Use when the user has a fuzzy idea and wants to shape it into a concrete project spec before planning or building. Triggers on: "brainstorm this", "I have an idea for...", "help me think through this project", "what should I build", "spec this out". Also catches vague feature descriptions needing structured questioning to clarify scope. Does NOT write code, plan implementation, review strategy docs, or run strategy interviews — produces a WHAT/WHY spec through dialogue, not a HOW plan.
Use as the follow-up to brainstorm-beagle when a spec has an Open Questions section (or quietly carries latent gaps) that need closing before planning or implementation can begin. Triggers on: "resolve the open questions", "close the gaps in this spec", "research the open items", "finalize my spec", "make this spec implementation-ready", "answer the TBDs". Also triggers whenever the user points at a brainstorm-beagle spec and asks for research, proposals, or answers to unresolved items. Orchestrates parallel research subagents when available (falls back to inline sequential research otherwise), proposes answers one at a time for user approval, then rewrites the spec in place so it arrives at planning with no known gaps. Does NOT write code, design implementation, or create plans — it only produces a complete spec.
Use when you have a finalized brainstorm-beagle spec at `.beagle/concepts/<slug>/spec.md` and need a bite-sized, TDD-driven implementation plan before any code is written. Triggers on: "write a plan", "plan this spec", "turn the spec into a plan", "now plan the implementation", "write-plan". Reads the spec, designs the file structure, decomposes work into 2-5 minute TDD steps with exact paths and commands, self-reviews against the spec, gets user approval, then writes to `.beagle/concepts/<slug>/plan.md` and offers to generate an execution handoff prompt via the subagent-prompt skill. Does NOT brainstorm specs, write code, or execute the plan — produces the plan document (and an optional handoff prompt) only.
Core technical documentation writing principles for voice, tone, structure, and LLM-friendly patterns. Use when writing or reviewing any documentation.
Generate first-draft technical documentation from code analysis
| name | fetch-pr-feedback |
| description | Fetch unresolved review comments from a PR and evaluate with receive-feedback skill |
| disable-model-invocation | true |
Fetch review comments from all reviewers on the current PR, format them, and evaluate using the receive-feedback skill. Excludes the PR author and current user by default. Line-specific comments belonging to resolved review threads are also excluded by default.
Invoke the fetch-pr-feedback skill, optionally passing these flags:
fetch-pr-feedback [--pr <number>] [--include-author] [--include-resolved]
Flags:
--pr <number> - PR number to target (default: current branch's PR)--include-author - Include PR author's own comments (default: excluded)--include-resolved - Include line-specific comments from resolved review threads (default: excluded)Advance only after each Pass when is satisfied.
$PR_NUMBER is set to a positive integer and gh pr view / gh api for that PR completed with exit code 0, or you stop in Get PR Context with only the failure given there (“No PR found for current branch…”).--include-resolved) and both paginated gh api … | jq -s -f … runs (issue comments + review comments) exit 0 and parse as JSON (empty [] is valid). On non-zero exit or jq error, stop; surface command stderr—do not invent comments.# PR #$PR_NUMBER Review Feedback, per-reviewer ## Reviewer: … with Summary / Line-Specific sections), or (b) exactly: No review comments found on this PR (excluding PR author, current user, and resolved threads).Extract flags from $ARGUMENTS:
--pr <number> or detect from current branch--include-author flag (boolean, default false)--include-resolved flag (boolean, default false)# If --pr was specified, use that number directly
# Otherwise, get PR for current branch:
gh pr view --json number,headRefName,url,author --jq '{number, headRefName, url, author: .author.login}'
# Get repo owner/name
gh repo view --json owner,name --jq '{owner: .owner.login, name: .name}'
# Get current authenticated user
gh api user --jq '.login'
Store as $PR_NUMBER, $PR_AUTHOR, $OWNER, $REPO, $CURRENT_USER.
Note: $OWNER, $REPO, etc. are placeholders. Substitute actual values from previous steps.
If no PR exists for current branch, fail with: "No PR found for current branch. Use --pr to specify a PR number."
Fetch both types of comments, excluding $PR_AUTHOR and $CURRENT_USER (unless --include-author is set). Use --paginate with jq -s to combine paginated JSON arrays into one.
Unless --include-resolved is set, first fetch the databaseIds of every review comment that belongs to a resolved review thread. Issue comments (summary/walkthrough) aren't part of review threads, so this only affects line-specific review comments.
Resolved-thread comment IDs (skip this block entirely when --include-resolved is set; set RESOLVED_IDS='[]' instead):
RESOLVED_IDS=$(gh api graphql \
-F owner="$OWNER" -F repo="$REPO" -F pr="$PR_NUMBER" \
-f query='
query($owner: String!, $repo: String!, $pr: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
reviewThreads(first: 100) {
nodes {
isResolved
comments(first: 100) { nodes { databaseId } }
}
}
}
}
}
' \
--jq '[.data.repository.pullRequest.reviewThreads.nodes[]
| select(.isResolved)
| .comments.nodes[].databaseId
| select(. != null)]')
The first: 100 limits cover typical PRs. For very large PRs (>100 threads or >100 comments in a single thread), thread/comment-level pagination would need to be added; for now, that's a known limitation.
Write jq filters to temp files using heredocs with single-quoted delimiters (prevents shell escaping issues with !=, regex patterns, and angle brackets):
Issue comments (summary/walkthrough posts):
cat > /tmp/issue_comments.jq << 'JQEOF'
def clean_body:
gsub("<!-- suggestion_start -->.*?<!-- suggestion_end -->"; ""; "s")
| gsub("<!--.*?-->"; ""; "s")
| gsub("<details>\\s*<summary>\\s*🧩 Analysis chain[\\s\\S]*?</details>"; ""; "s")
| gsub("<details>\\s*<summary>\\s*🤖 Prompt for AI Agents[\\s\\S]*?</details>"; ""; "s")
| gsub("<details>\\s*<summary>\\s*📝 Committable suggestion[\\s\\S]*?</details>"; ""; "s")
| gsub("<details>\\s*<summary>Past reviewee.*?</details>"; ""; "s")
| gsub("<details>\\s*<summary>Recent review details[\\s\\S]*?</details>"; ""; "s")
| gsub("<details>\\s*<summary>\\s*Tips\\b.*?</details>"; ""; "s")
| gsub("\\n?\\n---\\n+(?=\\s*(?:✨\\s*Finishing Touches|🪧\\s*Tips?|🤖\\s*Generated|<sub>|_Generated by|Generated by Claude|Generated with))[\\s\\S]*$"; ""; "s")
| gsub("^\\s+|\\s+$"; "")
| if length > 4000 then .[:4000] + "\n\n[comment truncated]" else . end
;
[(add // []) | .[] | select(
.user.login != $pr_author and
.user.login != $current_user
)] |
map({id, user: .user.login, body: (.body | clean_body), created_at})
JQEOF
gh api --paginate "repos/$OWNER/$REPO/issues/$PR_NUMBER/comments" | \
jq -s --arg pr_author "$PR_AUTHOR" --arg current_user "$CURRENT_USER" \
-f /tmp/issue_comments.jq
Review comments (line-specific):
cat > /tmp/review_comments.jq << 'JQEOF'
def clean_body:
gsub("<!-- suggestion_start -->.*?<!-- suggestion_end -->"; ""; "s")
| gsub("<!--.*?-->"; ""; "s")
| gsub("<details>\\s*<summary>\\s*🧩 Analysis chain[\\s\\S]*?</details>"; ""; "s")
| gsub("<details>\\s*<summary>\\s*🤖 Prompt for AI Agents[\\s\\S]*?</details>"; ""; "s")
| gsub("<details>\\s*<summary>\\s*📝 Committable suggestion[\\s\\S]*?</details>"; ""; "s")
| gsub("<details>\\s*<summary>Past reviewee.*?</details>"; ""; "s")
| gsub("<details>\\s*<summary>Recent review details[\\s\\S]*?</details>"; ""; "s")
| gsub("<details>\\s*<summary>\\s*Tips\\b.*?</details>"; ""; "s")
| gsub("\\n?\\n---\\n+(?=\\s*(?:✨\\s*Finishing Touches|🪧\\s*Tips?|🤖\\s*Generated|<sub>|_Generated by|Generated by Claude|Generated with))[\\s\\S]*$"; ""; "s")
| gsub("^\\s+|\\s+$"; "")
| if length > 4000 then .[:4000] + "\n\n[comment truncated]" else . end
;
[(add // []) | .[] | select(
.user.login != $pr_author and
.user.login != $current_user and
(.id as $comment_id | ($resolved_ids | index($comment_id) | not))
)] |
map({
id,
user: .user.login,
path,
line_display: (
.line as $end | .start_line as $start |
if $start and $start != $end then "\($start)-\($end)"
else "\($end // .original_line)" end
),
body: (.body | clean_body),
created_at
})
JQEOF
gh api --paginate "repos/$OWNER/$REPO/pulls/$PR_NUMBER/comments" | \
jq -s --arg pr_author "$PR_AUTHOR" --arg current_user "$CURRENT_USER" \
--argjson resolved_ids "$RESOLVED_IDS" \
-f /tmp/review_comments.jq
If --include-author is set, omit the --arg pr_author parameter and the .user.login != $pr_author condition from both jq filter files. Keep the $current_user exclusion either way. The $resolved_ids filter naturally becomes a no-op when RESOLVED_IDS='[]' (the --include-resolved path), so leave it in place.
Noise stripping — handled by the clean_body jq function in Step 3. Order matters: <!-- suggestion_start -->...<!-- suggestion_end --> blocks are removed first, then remaining HTML comments, then known-noise <details> blocks (Analysis chain, Prompt for AI Agents, Committable suggestion, Past reviewee, Recent review details, Tips), and finally the --- footer boilerplate. The <details> blocks must be stripped before the --- footer pattern because bot analysis chains contain --- separators that would otherwise truncate the actual finding. Substantive <details> blocks (e.g. "Suggested fix", "Proposed fix") are preserved. Comments exceeding 4000 chars after stripping are truncated with a [comment truncated] marker.
Group by reviewer — organize the formatted output by reviewer username:
# PR #$PR_NUMBER Review Feedback
## Reviewer: coderabbitai[bot]
### Summary Comments
[Issue comments from this reviewer, each separated by ---]
### Line-Specific Comments
[Review comments from this reviewer, each formatted as:]
**File: `path/to/file.ts:42`**
[cleaned comment body]
---
## Reviewer: another-reviewer
### Summary Comments
...
### Line-Specific Comments
...
If no comments found from any reviewer, output: "No review comments found on this PR (excluding PR author, current user, and resolved threads)."
Load the receive-feedback skill.
Then process the formatted feedback document:
# Fetch unresolved reviewer comments on current branch's PR (default)
fetch-pr-feedback
# Fetch from a specific PR
fetch-pr-feedback --pr 123
# Include PR author's own comments
fetch-pr-feedback --include-author
# Include line-specific comments from resolved review threads
fetch-pr-feedback --include-resolved
# Combined
fetch-pr-feedback --pr 456 --include-author --include-resolved