← Blog

How to Build a Code Review Bot With the Claude API

2026-10-28 · 5 min read · SubToAPI Team

Building a code review bot with the Claude API means wiring three pieces together: a trigger that fires on pull requests, a payload that sends the diff and relevant context to Claude, and a handler that posts the model's feedback back to your git host. The actual AI logic is a single API call — the engineering work is in formatting the diff well and handling the response reliably.

This guide walks through the full pipeline: fetching the diff, building a prompt that produces useful review comments (not generic praise), calling the API, and posting results to GitHub or GitLab. It also covers the operational details people skip — rate limits, large diffs, and keeping the bot's opinions consistent across runs.

The Architecture

A code review bot needs four components:

  1. Webhook listener — receives pull_request events from GitHub/GitLab
  2. Diff fetcher — pulls the changed files and diff content via the git host's API
  3. Claude call — sends the diff with a review-focused system prompt
  4. Comment poster — writes Claude's output back as a PR comment or inline review

The simplest version runs as a serverless function or small Node service that your CI pipeline calls after tests pass.

Step 1: Fetch the Diff

Use the GitHub API to get the PR's diff. For GitHub Actions, you already have the PR number and repo in the event payload:

const { Octokit } = require("@octokit/rest");
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });

async function getDiff(owner, repo, pull_number) {
  const { data } = await octokit.pulls.get({
    owner,
    repo,
    pull_number,
    mediaType: { format: "diff" },
  });
  return data;
}

Truncate or chunk diffs over a few thousand lines — Claude can handle large context windows, but a 10,000-line diff rarely produces a useful review. It's better to split by file and review the files that changed most, or exclude generated files, lockfiles, and vendored code before sending anything.

Step 2: Write a Prompt That Produces Useful Reviews

The quality of a review bot comes almost entirely from the system prompt. Vague prompts like "review this code" produce vague output. Be specific about what you want flagged and in what format:

You are a senior engineer doing a pull request review. Review the diff below.

Focus only on:
- Bugs, logic errors, and edge cases
- Security issues (injection, auth, secrets)
- Breaking changes to public APIs
- Missing error handling

Do NOT comment on:
- Code style or formatting
- Naming preferences
- Anything a linter would already catch

For each issue, output:
FILE: <filename>
LINE: <line number if identifiable>
ISSUE: <one sentence>
SUGGESTION: <concrete fix>

If there are no issues, say "No blocking issues found."

This constrains Claude to actionable feedback and gives you a predictable format you can parse into inline PR comments instead of one giant text blob.

Step 3: Call the API

Here's a minimal call using the SubToAPI endpoint, which wraps Claude access behind a standard HTTPS API with an application key (sub_live_...) instead of managing provider credentials directly:

async function reviewDiff(diff) {
  const res = await fetch("https://api.subtoapi.app/v1/messages", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.SUBTOAPI_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "claude-3-7-sonnet",
      max_tokens: 2000,
      system: REVIEW_SYSTEM_PROMPT,
      messages: [
        { role: "user", content: `Review this diff:\n\n${diff}` },
      ],
    }),
  });

  const data = await res.json();
  return data.content[0].text;
}

If your bot runs across multiple repos or a team shares usage, routing through /pricing-based seats instead of a single raw API key makes it easier to track who's consuming tokens and set per-seat limits. The /docs/quickstart walks through getting a key and making your first call.

Step 4: Post the Review Back

Parse the structured output and post it as a PR comment:

async function postComment(owner, repo, pull_number, body) {
  await octokit.issues.createComment({
    owner,
    repo,
    issue_number: pull_number,
    body: `## Claude Review\n\n${body}`,
  });
}

For inline comments tied to specific lines, use octokit.pulls.createReviewComment with the path and line fields parsed from Claude's structured output.

Handling Large PRs and Streaming

Large diffs can push you close to token limits or take longer to generate. If you want to show progress in CI logs instead of waiting on one blocking response, use streaming — see /docs/streaming for how SubToAPI exposes server-sent events on the same endpoint. For a code review bot, streaming is mostly useful for logging progress; the final comment still gets posted once the full response completes.

Tool Use for Richer Reviews

A more advanced bot can give Claude tools to fetch additional context — for example, a get_file_contents tool so it can pull the full file instead of just the diff hunk, which helps it avoid flagging issues that are actually handled a few lines outside the diff context. See /docs/tools for how tool calls work against the SubToAPI endpoint; the pattern is the same multi-turn tool loop you'd use for any agentic Claude integration, just scoped to git operations.

Keeping It Reliable in CI

A few practical notes from running this in production pipelines:

Frequently Asked Questions

Does the bot need access to my full codebase, or just the diff? For most reviews, the diff plus a few lines of surrounding context is enough. Full-file access via a tool call helps with cases where logic spans outside the diff hunk, but it increases token usage, so add it selectively rather than by default.

Can this run as a GitHub Action instead of a separate server? Yes. The entire flow — fetch diff, call Claude, post comment — fits in a single GitHub Actions job using actions/github-script or a small Node script, with your API key stored as a repository secret.

How do I avoid the bot repeating the same comments every time someone pushes? Track which issues you've already posted (by file + line + issue text) and skip duplicates on subsequent runs, or only run the full review once per PR and use lighter incremental checks on later commits.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →