Skip to content
LinkedInX

Level 6 Practice: Automatically Review Every PR

Target audience: Anyone who has completed up to Level 5 and understands the basics of GitHub Actions (editing YAML, setting secrets).
Prerequisites: Read Level 5

About This Tutorial

This tutorial focuses on the practice steps and completion checks for this level.


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.


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

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

Step 2: Test Locally

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.

src/app/contact/page.tsx

No issues.

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

--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
This table scrolls horizontally. Keyboard users can focus the table and use the left and right arrow keys.

For public production repositories, using pull_request instead of pull_request_target prevents secret leakage from forks.


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

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

The my-portfolio at This Point

  • 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
│       └── ...
└── ...

Next Level

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

The non-interactive Claude Code flow follows Anthropic documentation, and the PR automation flow follows GitHub Actions documentation.[1][2]

References

  1. Anthropic, Claude Code documentation
  2. Anthropic, Claude API documentation
Quiz