How to Build a Claude-Powered Code Review Tool
Building a Claude-powered code review tool means connecting a diff or pull request to Claude's API, prompting it to analyze the code for bugs, style issues, and security risks, then posting the results back as comments. The core pieces are: fetching the diff, structuring a prompt that gives Claude enough context to reason well, calling the API, and parsing the response into something your CI pipeline or Git host can display.
This article walks through a working architecture you can ship this week — from pulling a GitHub diff to streaming review comments back into a pull request — along with the prompt patterns that make automated reviews actually useful instead of generic.
Why build this instead of using a generic linter
Static analyzers catch syntax patterns. They don't catch "this function silently swallows an error that the caller probably needs to know about" or "this SQL query concatenates user input." Claude reads code the way a senior engineer skims a diff: it understands intent, naming, and context across files, not just regex matches.
A Claude-powered review tool is useful as:
- A pre-merge gate that comments on PRs automatically
- A local CLI that reviews staged changes before you commit
- A bot that enforces team-specific conventions (error handling, logging, naming)
Step 1: Get the diff
Most teams start with GitHub or GitLab webhooks. On a pull_request event, fetch the diff via the API:
curl -s -H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3.diff" \
https://api.github.com/repos/OWNER/REPO/pulls/123 > pr.diff
For a local CLI tool, git diff --staged works just as well.
Step 2: Structure the prompt
The quality of the review depends almost entirely on the prompt. Give Claude a role, explicit review criteria, and the diff with file context — not just a raw patch blob with no file names.
const systemPrompt = `You are a senior code reviewer. Review the diff below for:
1. Bugs and logic errors
2. Security issues (injection, auth, secrets)
3. Error handling gaps
4. Naming and readability
5. Missing tests for new logic
For each issue, output:
- file path and line number if visible
- severity: high, medium, low
- a one-sentence explanation
- a suggested fix
Skip style nits unless they affect readability significantly.
If the diff is clean, say so explicitly — do not invent issues.`;
That last instruction matters. Without it, models will sometimes manufacture minor nitpicks just to seem thorough, which erodes trust in the tool fast.
Step 3: Call the API
Here's a minimal implementation using SubToAPI, which exposes your Claude access as a standard HTTPS API with an application key (sub_live_...) instead of juggling raw Anthropic credentials across CI runners:
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-opus-4",
max_tokens: 2000,
system: systemPrompt,
messages: [
{ role: "user", content: `Review this diff:\n\n${diffText}` }
]
})
});
const data = await res.json();
const review = data.content[0].text;
If you're new to the request format, the quickstart and messages docs cover authentication and payload structure in detail.
Step 4: Post results back to the PR
Parse Claude's structured output (ask it to return JSON for reliable parsing) and post as a PR comment:
const comment = `## Claude Code Review\n\n${review}`;
await fetch(`https://api.github.com/repos/OWNER/REPO/issues/123/comments`, {
method: "POST",
headers: { "Authorization": `token ${process.env.GITHUB_TOKEN}` },
body: JSON.stringify({ body: comment })
});
For more reliable parsing, ask Claude to return a JSON array of issue objects (file, line, severity, message, suggestion) instead of free text, then render the formatting yourself.
Handling large diffs
Large PRs can exceed what's useful to send in one call. Two practical approaches:
- Split by file: send each changed file as a separate review call with the surrounding diff context, then merge results.
- Prioritize by risk: run a cheap first pass to flag which files touch auth, payments, or data access, then only deep-review those with the full prompt.
If you want structured tool-based workflows — like having Claude call a function to fetch additional file context when it needs more than the diff shows — the tool use docs explain how to wire that up.
Streaming review output in CI
For CI jobs with a time budget, streaming lets you show partial output and fail fast if Claude flags a high-severity issue early:
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-opus-4", stream: true, messages: [...] })
});
Full streaming setup is in the streaming guide.
Keeping cost and access manageable
If more than one person on your team runs this tool — in CI, locally, and in a Slack bot — you don't want everyone sharing one raw API key with no visibility into who's calling what. SubToAPI issues scoped application keys per use case and tracks usage per key, which makes it straightforward to see that your nightly full-repo review job costs more than your PR-diff job, and to rotate a key without touching the others. Plans start at Solo (€9) for individual use, with Team (€19/seat) and Scale (€49/seat) tiers for shared CI pipelines — see pricing for details, or start with the free trial at signup.
Practical tips for better reviews
- Give it the full file, not just the hunk, when the diff touches logic that depends on surrounding code.
- Ask for severity levels so your CI can block only on "high" findings and comment-only on the rest.
- Cache reviews per commit SHA to avoid re-reviewing unchanged code on every CI rerun.
- Tune the prompt per repo — a Rails app and a Rust CLI need different review criteria.
questions
Does Claude replace static analyzers like ESLint or SonarQube? No. Use both — static tools catch mechanical patterns instantly and cheaply; Claude catches context-dependent issues like logic errors and unclear intent that pattern matching misses.
How do I avoid false positives in automated reviews? Explicitly instruct Claude to state when a diff is clean, give concrete severity criteria, and consider a second-pass prompt that re-checks flagged issues before posting them.
Can this run entirely in CI without a dashboard? Yes. A GitHub Action or GitLab CI job can call the API directly and post comments via the Git host's REST API — no separate server required, as shown in the examples above.