Skip to content
X

Level 6 Practice: Automatically Review Every PR

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


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.


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 scripts

Create 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 --print

Grant execute permission:

chmod +x scripts/review_pr.sh

Switch to the feature/contact-form branch and run the script:

git checkout feature/contact-form
./scripts/review_pr.sh main

Example 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 with htmlFor and id.

No issues.

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/workflows

Contents 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:

NoteMitigation
Also grants file write permissionsCombine with --print to limit output only
Allows access to secretsRestrict the permissions block in GitHub Actions to minimum required
Risk of prompt injectionThe 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.


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)

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-form

Open 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._

  • scripts/review_pr.sh added — I can run diff reviews locally
  • .github/workflows/ai-review.yml added — all PRs now get an automatic review comment
  • ANTHROPIC_API_KEY set 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
│       └── ...
└── ...

Level 7 Practice: Auto-Collect Blog Ideas from Trending Articles