fetch-pr-feedback
Fetch unresolved review comments from a PR and evaluate with receive-feedback skill
git clone --depth 1 https://github.com/existential-birds/beagle /tmp/fetch-pr-feedback && cp -r /tmp/fetch-pr-feedback/plugins/beagle-core/skills/fetch-pr-feedback ~/.claude/skills/fetch-pr-feedbackSKILL.md
# Fetch PR Feedback
Fetch review comments from all reviewers on the current PR, format them, and evaluate using the [receive-feedback](../receive-feedback/SKILL.md) skill. Excludes the PR author and current user by default. Line-specific comments belonging to resolved review threads are also excluded by default.
## Usage
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)
## Instructions
### Gates (sequence; do not skip)
Advance only after each **Pass when** is satisfied.
1. **PR context** — **Pass when:** `$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…”).
2. **Fetch** — **Pass when:** the resolved-thread GraphQL call (skipped if `--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.
3. **Formatted artifact** — **Pass when:** output is either (a) markdown matching **Format Feedback Document** (header `# 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).`
4. **Load receive-feedback** — **Pass when:** the [receive-feedback](../receive-feedback/SKILL.md) skill is loaded; only then run that skill’s verify → evaluate → execute loop on that formatted document.
### 1. Parse Arguments
Extract flags from `$ARGUMENTS`:
- `--pr <number>` or detect from current branch
- `--include-author` flag (boolean, default false)
- `--include-resolved` flag (boolean, default false)
### 2. Get PR Context
```bash
# 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."
### 3. Fetch Comments
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):
```bash
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):
```bash
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):
```bash
cat > /tmp/review_comments.jq << 'JQEOF'
def clean_body:
gsub("<!-- suggestion_start -->.*?<!-- suggestion_end -->"; ""; "s")
| gsub("<!--.*?-->"; ""; "s")
| gsub("<details>\\s*<summary>\\s*🧩 Analysistag and push a release after the release PR is merged
create a release PR (auto-detects previous tag)
Guides architectural decisions for Deep Agents applications. Use when deciding between Deep Agents vs alternatives, choosing backend strategies, designing subagent systems, or selecting middleware approaches.
Reviews Deep Agents code for bugs, anti-patterns, and improvements. Use when reviewing code that uses create_deep_agent, backends, subagents, middleware, or human-in-the-loop patterns. Catches common configuration and usage mistakes.
Implements agents using Deep Agents. Use when building agents with create_deep_agent, configuring backends, defining subagents, adding middleware, or setting up human-in-the-loop workflows.
Guides architectural decisions for LangGraph applications. Use when deciding between LangGraph vs alternatives, choosing state management strategies, designing multi-agent systems, or selecting persistence and streaming approaches.
Reviews LangGraph code for bugs, anti-patterns, and improvements. Use when reviewing code that uses StateGraph, nodes, edges, checkpointing, or other LangGraph features. Catches common mistakes in state management, graph structure, and async patterns.
Implements stateful agent graphs using LangGraph. Use when building graphs, adding nodes/edges, defining state schemas, implementing checkpointing, handling interrupts, or creating multi-agent systems with LangGraph.