GitHub Action that Reviews Every PR
Advanced
- Wire Claude Code headless into a pull_request workflow that reviews the diff and comments
- Set the permissions block to comment-only, and say why contents: write is the line you do not cross
- Treat pull request content as untrusted input, because that is exactly what it is
- Keep the cost of a review bounded as diffs grow
- Write the prompt so the comment gets read instead of collapsed
A classic high-value automation: have Claude review every pull request and post its findings as a comment — running headless in CI. Here's the shape, with the guardrails that keep it safe.
What it does
On each PR: check out the diff, ask Claude to review it for bugs/edge-cases/convention issues, and post a comment. Humans still decide; Claude just gives a fast first pass.
Guided walkthrough1 of 4
- A shallow clone cannot see the base branch, so the diff comes out empty and the review reads as a confident sign-off on nothing. Fetch full depth.
- Diff the base ref against HEAD and write it to disk. Keeping it as an artifact rather than a shell variable keeps very large diffs from breaking the command line.
- One prompt, one pass, output captured as Markdown. No tools, no repo writes — this step only needs to read and produce text.
- With the gh CLI or an action. This is the only step that needs write permission of any kind, and the only write it needs is pull-requests.
The workflow (sketch)
name: Claude PR review
on: pull_request
permissions:
contents: read
pull-requests: write # to comment — NOT write to code
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- name: Review the diff
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
git diff origin/${{ github.base_ref }}...HEAD > /tmp/diff.patch
claude -p "Review this diff for correctness bugs, missing edge cases, and
security issues. Report ONLY high-confidence findings as a Markdown
checklist with file:line. Diff:" < /tmp/diff.patch > /tmp/review.md
# then post /tmp/review.md as a PR comment (e.g. with the gh CLI or an action)
(Exact headless invocation may differ — see the docs. The principle is: feed the diff, capture Markdown, post it.)
The guardrails (read Hardening Autonomous Runs)
Least privilege in CI
- Comment only. Grant
pull-requests: write, notcontents: write— the bot shouldn't push code. - Scope the token; never expose deploy/secret access to a job that reads untrusted PR content.
- Treat PR content as untrusted — it can carry prompt injection; don't let the job take consequential actions.
- Cap cost — large diffs cost tokens; consider reviewing changed files only.
Make it useful, not noisy
- Ask for high-confidence findings only — a wall of nitpicks gets ignored.
- Keep it as a first pass, with humans making the merge call.
The review prompt — tuned for a comment people actually read
Review this diff for correctness bugs, missing edge cases, and security issues. Rules for your output: - Report ONLY high-confidence findings. If you are unsure, leave it out. - One Markdown checklist item per finding, each starting with file:line. - State the concrete failure: what input or state leads to what wrong result. - No style nitpicks, no praise, no summary of what the diff does. - If you find nothing high-confidence, say exactly that in one line. Diff:
Check yourself
0/3- The whole job is: full-depth checkout, diff to a file, one headless pass, post the Markdown. Four steps, one of which needs write access.
- pull-requests: write and contents: read. Never contents: write in a job that reads contributor-authored content.
- fetch-depth: 0, or the diff is empty and the review reads like a clean bill of health.
- PR content is untrusted and can carry prompt injection. Least privilege is the control; prompt wording is not a boundary.
- Ask for high-confidence findings only, with file:line. A wall of nitpicks gets collapsed and the automation dies of being ignored.
- Cap the cost as diffs grow — reviewing changed files only is the usual lever.
- It is a first pass. Humans still make the merge call.