Level 6 Practice: Automatically Review Every PR
About This Tutorial
Section titled “About This Tutorial”If you want to understand the concepts and mechanics first, see the Level 6 concept guide.
I’ll build a system where Claude automatically posts a code review comment every time a PR arrives. This eliminates the overhead of manually requesting reviews and makes review quality consistent across the entire project.
Who this is for: Anyone who has completed up to Level 5 and understands the basics of GitHub Actions (editing YAML, setting secrets).
Estimated time: 10 min read + 40 min hands-on
Carrying Over from the Previous Level
Section titled “Carrying Over from the Previous Level”In Level 5, a PR for the feature/contact-form branch was automatically created on GitHub. Reviews are currently requested manually, which adds overhead on every cycle.
Step 1: Create the Script
Section titled “Step 1: Create the Script”Create a scripts/ directory at the root of my-portfolio and place a shell script for local reviews there. This script targets .tsx, .ts, and .css files and reviews them for TypeScript type safety, React best practices, and accessibility.
mkdir -p scriptsCreate scripts/review_pr.sh with the following content:
#!/usr/bin/env bash
# scripts/review_pr.sh
# Review the diff between the current branch and main using Claude
set -euo pipefail
BASE_BRANCH="${1:-main}"
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
echo "=== Claude PR Review ==="
echo "Base : ${BASE_BRANCH}"
echo "Branch: ${CURRENT_BRANCH}"
echo ""
# List of changed files (.tsx .ts .css only)
CHANGED_FILES=$(git diff --name-only "${BASE_BRANCH}...HEAD" \
| grep -E '\.(tsx|ts|css)$' || true)
if [ -z "${CHANGED_FILES}" ]; then
echo "No files to review (.tsx/.ts/.css)."
exit 0
fi
echo "Files to review:"
echo "${CHANGED_FILES}"
echo ""
# Get the diff and request a review
DIFF=$(git diff "${BASE_BRANCH}...HEAD" -- ${CHANGED_FILES})
PROMPT="The following is a PR diff for my-portfolio (Next.js 14 + TypeScript).
Please review it from these angles:
1. TypeScript type safety (use of any, type inference usage, type guard validity)
2. React best practices (useEffect dependency arrays, need for memoization, component design)
3. Accessibility (aria attributes, form labels, keyboard navigation)
4. Tailwind CSS class consistency
If there are issues, list them as bullet points in the format: 'filename + approximate line + description + suggested fix'.
If there are no issues, respond with 'LGTM'.
--- DIFF ---
${DIFF}"
echo "Requesting review from Claude..."
echo ""
echo "${PROMPT}" | claude --printGrant execute permission:
chmod +x scripts/review_pr.shStep 2: Test Locally
Section titled “Step 2: Test Locally”Switch to the feature/contact-form branch and run the script:
git checkout feature/contact-form
./scripts/review_pr.sh mainExample output:
=== Claude PR Review ===
Base : main
Branch: feature/contact-form
Files to review:
src/components/Contact.tsx
src/app/contact/page.tsx
src/components/__tests__/Contact.test.tsx
Requesting review from Claude...
## Review Results
### src/components/Contact.tsx
- **L23 — Type safety**: You're casting `e.target.value` with `as string`, but
using `React.ChangeEvent<HTMLInputElement>` makes the cast unnecessary.
```tsx
// Before
const value = (e.target as HTMLInputElement).value as string
// After
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setValue(e.target.value)}- L45 — Accessibility: There is no
<label>corresponding to<input>. Link them withhtmlForandid.
src/app/contact/page.tsx
Section titled “src/app/contact/page.tsx”No issues.
Overall
Section titled “Overall”2 issues found. Both are minor and straightforward to fix.
---
## Step 3: Create the GitHub Actions Workflow
Create `.github/workflows/ai-review.yml`. This workflow runs automatically whenever a PR is opened or synchronized, and posts the review as a PR comment.
```bash
mkdir -p .github/workflowsContents of .github/workflows/ai-review.yml:
name: AI Code Review
on:
pull_request:
types: [opened, synchronize]
paths:
- "src/**/*.tsx"
- "src/**/*.ts"
- "src/**/*.css"
permissions:
contents: read
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install Claude Code
run: npm install -g @anthropic-ai/claude-code
- name: Get PR diff
id: diff
run: |
BASE="${{ github.event.pull_request.base.sha }}"
HEAD="${{ github.event.pull_request.head.sha }}"
DIFF=$(git diff "${BASE}...${HEAD}" -- 'src/**/*.tsx' 'src/**/*.ts' 'src/**/*.css' || true)
# Write the diff to an env file (it contains newlines)
echo "DIFF<<EOF" >> $GITHUB_ENV
echo "${DIFF}" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Run Claude review
id: review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
PROMPT="The following is a PR diff for my-portfolio (Next.js 14 + TypeScript).
Please review it from these angles:
1. TypeScript type safety
2. React best practices (useEffect dependency arrays, memoization)
3. Accessibility (aria attributes, form labels)
4. Tailwind CSS class consistency
If there are issues, list them as bullet points: 'filename + approximate line + description + suggested fix'.
If there are no issues, respond with LGTM.
--- DIFF ---
${{ env.DIFF }}"
REVIEW=$(echo "${PROMPT}" | claude --print --dangerously-skip-permissions)
echo "REVIEW<<EOF" >> $GITHUB_ENV
echo "${REVIEW}" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Post review comment
uses: actions/github-script@v7
with:
script: |
const review = process.env.REVIEW;
const body = [
'## Claude AI Review',
'',
review,
'',
'---',
'_This comment was automatically generated by Claude Code._',
].join('\n');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
env:
REVIEW: ${{ env.REVIEW }}Step 4: Notes on —dangerously-skip-permissions
Section titled “Step 4: Notes on —dangerously-skip-permissions”--dangerously-skip-permissions is a flag that skips interactive confirmation prompts. It’s required in CI environments where interaction is impossible, but keep these points in mind:
| Note | Mitigation |
|---|---|
| Also grants file write permissions | Combine with --print to limit output only |
| Allows access to secrets | Restrict the permissions block in GitHub Actions to minimum required |
| Risk of prompt injection | The PR diff is included directly in the prompt — be careful of malicious diffs from external contributors |
For public production repositories, using pull_request instead of pull_request_target prevents secret leakage from forks.
Step 5: Set the Secret
Section titled “Step 5: Set the Secret”In the GitHub repository, go to Settings > Secrets and variables > Actions and add ANTHROPIC_API_KEY.
Settings
└── Secrets and variables
└── Actions
└── New repository secret
Name: ANTHROPIC_API_KEY
Value: sk-ant-...(key issued from Anthropic Console)Step 6: Create a PR and Confirm It Works
Section titled “Step 6: Create a PR and Confirm It Works”Commit and push the workflow file:
git add scripts/review_pr.sh .github/workflows/ai-review.yml
git commit -m "Add Claude AI auto-review workflow"
git push origin feature/contact-formOpen the Pull Requests tab on GitHub and check the feature/contact-form PR. In the Actions tab, the AI Code Review job runs, and after it completes, a comment is posted to the PR.
Example posted comment:
## Claude AI Review
### src/components/Contact.tsx
- **L23 — Type safety**: Using `React.ChangeEvent<HTMLInputElement>`
eliminates the need for type casting.
- **L45 — Accessibility**: `<input id="email">` does not have a
corresponding `<label htmlFor="email">`.
### src/app/contact/page.tsx
No issues.
### Overall
2 issues found. Both are minor and straightforward to fix.
---
_This comment was automatically generated by Claude Code._The my-portfolio at This Point
Section titled “The my-portfolio at This Point”scripts/review_pr.shadded — I can run diff reviews locally.github/workflows/ai-review.ymladded — all PRs now get an automatic review commentANTHROPIC_API_KEYset in GitHub secrets
my-portfolio/
├── scripts/
│ └── review_pr.sh # ← newly added
├── .github/
│ └── workflows/
│ └── ai-review.yml # ← newly added
├── src/
│ ├── components/
│ │ ├── About.tsx
│ │ ├── Skills.tsx
│ │ └── Contact.tsx
│ └── app/
│ ├── contact/
│ │ └── page.tsx
│ └── ...
└── ...Next Level
Section titled “Next Level”Level 7 Practice: Auto-Collect Blog Ideas from Trending Articles