← The Tickd Guide

Tutorials & Guides

How to Build a Custom GitHub Action for Automated Code Reviews Using Claude 3.5 Sonnet

Tired of noisy, useless automated code reviews? Learn how to build a lightweight, highly specific GitHub Action that uses Claude 3.5 Sonnet to catch actual logic bugs without the fluff.

Updated 8/21/2026

We have all been there. You open a pull request, and within thirty seconds, a generic automated bot leaves nineteen comments pointing out missing semicolons or minor style inconsistencies. It is noise. It does not help you ship faster; it just makes you want to close your laptop and walk away.

But code review is still a bottleneck. If you are running a lean team or building solo, you do not have hours to spend parsing every single line of a dependency upgrade or a refactor.

By leveraging the reasoning capabilities of Claude 3.5 Sonnet, you can build an automated reviewer that actually acts like a senior engineer. We are going to build a custom, lightweight GitHub Action that triggers on every pull request, analyzes only the git diff, and posts targeted, high-value code reviews directly back to the pull request.

No bloated third-party platforms. No excessive subscription fees. Just a clean, customisable workflow you control.

The Architecture: Keeping It Lean

Many developers make the mistake of using heavy orchestration frameworks just to send a git diff to an LLM. We do not need any of that. To keep our Action incredibly fast and cheap to run, we will write a simple Python runner script that runs inside a standard GitHub runner.

Here is how the workflow behaves: 1. A developer opens or updates a Pull Request. 2. Our GitHub Action triggers, using the GitHub API to fetch the raw code changes (the diff). 3. The Python script packages the diff, applies a strict system prompt, and sends it to Claude 3.5 Sonnet. 4. Claude returns a structured list of critical issues (security flaws, logic bugs, or performance bottlenecks). 5. The script posts these issues back to the PR as comments.

Step 1: Writing the Workflow File

First, we need to define our GitHub Actions workflow. Create a file in your repository at .github/workflows/claude-review.yml.

`yaml name: Claude Code Review

on: pull_request: types: [opened, synchronize]

jobs: review: runs-on: ubuntu-latest permissions: pull-requests: write contents: read

steps: - name: Checkout repository uses: actions/checkout@v4

- name: Set up Python uses: actions/setup-python@v5 with: python-node-version: '3.11'

- name: Install dependencies run: | pip install anthropic requests

- name: Run Review Script env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} REPO: ${{ github.repository }} run: python .github/scripts/review.py `

This workflow sets up the basic environment, configures the necessary permissions to write comments back to the PR, and passes the required secrets (your Anthropic API key and the automatic GitHub token) to our runner script.

Step 2: The Review Python Script

Next, we need to write the script that does the heavy lifting. Create a new folder structure: .github/scripts/ and place a file named review.py inside it.

We will use the standard requests library to fetch the diff from GitHub's REST API and the official anthropic client to query Claude. By fetching the raw diff directly, we avoid having to pull down the entire git history, keeping our runner execution time well under a minute.

`python import os import sys import requests from anthropic import Anthropic

def main(): # Grab environment variables passed from the GitHub workflow api_key = os.getenv("ANTHROPIC_API_KEY") github_token = os.getenv("GITHUB_TOKEN") pr_number = os.getenv("PR_NUMBER") repo = os.getenv("REPO")

if not all([api_key, github_token, pr_number, repo]): print("Missing required configuration. Exiting.") sys.exit(1)

1. Fetch the pull request diff diff_url = f"https://api.github.com/repos/{repo}/pulls/{pr_number}" headers = { "Authorization": f"token {github_token}", "Accept": "application/vnd.github.v3.diff" } response = requests.get(diff_url, headers=headers) if response.status_code != 200: print(f"Failed to fetch diff: {response.status_code}") sys.exit(1) git_diff = response.text

If the diff is empty or too massive, we should gracefully exit if not git_diff.strip(): print("Empty diff detected.") return if len(git_diff) > 100000: # Protect against massive dependency lockfile updates print("Diff too large, skipping review to save API tokens.") return

2. Query Claude 3.5 Sonnet client = Anthropic(api_key=api_key) system_prompt = ( "You are an elite senior software engineer with deep expertise in security, performance, and clean code. " "Your job is to review the git diff of a pull request. " "Be exceptionally concise. Do NOT comment on formatting, styling, missing documentation, or trivialities. " "Only comment on serious logic flaws, security vulnerabilities, edge-case failures, or massive performance regressions. " "If you find issues, format your response as a single markdown comment containing a bulleted list of actionable suggestions. " "If the code looks clean and well-written, simply reply with the exact phrase: 'LGTM'." )

try: message = client.messages.create( model="claude-3-5-sonnet-20241022", max_tokens=1500, temperature=0.1, # Keep output deterministic and focused system=system_prompt, messages=[ { "role": "user", "content": f"Please review the following git diff:\n\n{git_diff}" } ] ) review_output = message.content[0].text.strip() except Exception as e: print(f"Error communicating with Anthropic API: {e}") sys.exit(1)

3. Post the review back to the PR if review_output == "LGTM": print("No major issues found. Skipping PR comment.") return

comment_url = f"https://api.github.com/repos/{repo}/issues/{pr_number}/comments" comment_payload = { "body": f"### 🤖 Claude 3.5 Sonnet - Automated Code Review\n\n{review_output}" } comment_headers = { "Authorization": f"token {github_token}", "Accept": "application/vnd.github.v3+json" }

post_response = requests.post(comment_url, json=comment_payload, headers=comment_headers) if post_response.status_code == 201: print("Review comment posted successfully.") else: print(f"Failed to post comment: {post_response.status_code} - {post_response.text}")

if __name__ == "__main__": main() `

Step 3: Dialling in the Prompts

The magic here lies entirely in the prompt. Standard LLMs love to chat; they will happily output paragraph after paragraph of praise before pointing out a single, optional refactoring tip. In a real-world development loop, this behaviour is incredibly frustrating.

We set our temperature to 0.1 to minimise the creative fluff, and we explicitly instruct Claude to ignore styling. If you want to refine this prompt further for your team's specific stack, you can head over to our prompt generator to craft custom rules—such as forcing Claude to look specifically for React rendering bugs or SQL injection hazards.

Step 4: Testing Your Action

To make this live: 1. Head to your GitHub repository settings. 2. Navigate to Secrets and variables > Actions and add your ANTHROPIC_API_KEY. 3. Make sure your repository allows actions to write to pull requests (under Settings > Actions > General > Workflow permissions, select Read and write permissions). 4. Push your changes to your main branch.

Now, open a quick test pull request. Introduce a subtle error—like a potential division-by-zero or a hardcoded token—and watch the runner do its thing. Within seconds, Claude will post a tidy, bulleted list of actual warnings without cluttering your timeline.

If you run into issues with the Anthropic API returning rate limits or authentication issues, check the official troubleshooting paths on the Claude Support Portal.

By keeping your tooling simple and avoiding heavy dependencies, you have built a custom, production-grade review engine that runs on your own terms. Adjust the prompts as your repository grows, and watch your pull requests clear up without the usual automated noise.

github-actionsclaude-3-5-sonnetautomationdev-workflowpython

Keep going

Build something with the prompt generator, decode the jargon in the glossary, or compare the tools on our platform deep-dives.