Fetch PR Diff
Fetches a pull request diff and adds line numbers for easier review-comment placement. Auto-generated files (lock files, protobuf-generated Java) are shown with masked diffs so review focuses on hand-written changes.
Usage
uv run "${CLAUDE_SKILL_DIR}/scripts/fetch_diff.py" <pr_url> [--files <pattern> ...]
The script is a self-contained PEP 723 script — uv run resolves its
dependencies on demand; no install step is needed.
Examples
# Fetch the full diff
uv run "${CLAUDE_SKILL_DIR}/scripts/fetch_diff.py" https://github.com/owner/repo/pull/123
# Fetch only Python files
uv run "${CLAUDE_SKILL_DIR}/scripts/fetch_diff.py" https://github.com/owner/repo/pull/123 --files '*.py'
# Fetch only frontend files
uv run "${CLAUDE_SKILL_DIR}/scripts/fetch_diff.py" https://github.com/owner/repo/pull/123 --files 'src/server/js/*'
# Multiple patterns
uv run "${CLAUDE_SKILL_DIR}/scripts/fetch_diff.py" https://github.com/owner/repo/pull/123 --files '*.py' '*.ts'
The GitHub token is auto-detected from the GH_TOKEN environment variable or
gh auth token.
Inputs and outputs
scripts/fetch_diff.py takes:
pr_url(positional, required) — a GitHub PR URL of the formhttps://github.com/<owner>/<repo>/pull/<number>. Sub-paths like/filesare not accepted; use the bare/pull/<n>form.--files <pattern> ...(optional) — one or morefnmatchglobs matched against each file's new path. Files matching any pattern are kept; the rest are dropped. No match yields an empty diff (not an error).GH_TOKEN(env) — the token used to call the GitHub API. If unset, the script falls back togh auth token; if that also fails it exits with an error.
It prints the PR's unified diff to stdout, reorganized per file: each file
keeps its diff --git header, then either line-annotated hunks (see
Line Annotation) or a one-line mask message for
auto-generated and deleted files. A single diagnostic line goes to stderr
when a stacked-PR incremental diff is detected. See
references/output-format.md for the full
schema.
Output Example
Regular file:
diff --git a/path/to/file.py b/path/to/file.py
index abc123..def456 100644
--- a/path/to/file.py
+++ b/path/to/file.py
@@ -10,7 +10,7 @@
10 10 | import os
11 11 | import sys
12 12 | from typing import Optional
13 | -from old_module import OldClass
14 | +from new_module import NewClass
14 15 |
15 16 | def process_data(input_file: str) -> dict:
Auto-generated file (masked):
diff --git a/uv.lock b/uv.lock
index abc123..def456 100644
--- a/uv.lock
+++ b/uv.lock
[Auto-generated file - diff masked]
Deleted file (masked):
diff --git a/path/to/removed.py b/dev/null
index abc123..0000000 100644
--- a/path/to/removed.py
+++ /dev/null
[Deleted file - diff masked]
Line Annotation
Each line is annotated as old_line new_line | <marker> content:
-marker (left number only) -> deleted line; comment withside=LEFT,line=old_line+marker (right number only) -> added line; comment withside=RIGHT,line=new_line- No marker (both numbers) -> unchanged line; comment with
side=RIGHT,line=new_line
Reference Files
references/output-format.md— consult when parsing the annotated diff: the column schema, marker meanings, how masked and deleted files render, and how stacked-PR incremental diffs are signaled.references/troubleshooting.md— consult when the fetch fails or surprises you: auth errors, PR-not-found / private repos, large diffs,--filesglob behavior and no-match output, and line-anchoring pitfalls when the result feedsadd-review-comment.
Related skills
This skill is the first step of the PR-review family in agent-harness:
- fetch-diff (this skill) — get the diff annotated with old/new line numbers.
add-review-comment— post an inline comment using theside/lineanchors this skill produces.pr-review— review a whole PR end to end.fetch-unresolved-comments— pull back the review threads that still need a response.