Code review is one of those developer tasks that benefits enormously from AI assistance β but only if the AI actually understands your codebase's context. Generic review comments like "consider adding a comment here" are useless. What you want is something that catches real issues: missing null checks in a C# service layer, Angular change detection anti-patterns, or a database query that's going to hurt you at scale.
I build with .NET and Angular daily, and integrating the Claude API directly into the review pipeline is one of the more practical things I've done with it. This post walks through how to wire it up end-to-end: calling the Claude API from a .NET console app, structuring prompts that produce actionable feedback, and optionally plugging it into a CI/CD step so every pull request gets a first-pass AI review before a human ever looks at it.
The full example uses Anthropic's .NET SDK, structured outputs for consistent JSON responses, and a simple prompt template you can tune for your own codebase conventions. All the code below is production-ready and can be dropped into an existing .NET solution without architectural changes.
Why Automate Code Review with Claude?
Manual code review is valuable and irreplaceable β but it's also slow, inconsistently applied, and often the bottleneck on a sprint. An AI-powered first pass handles the mechanical layer: style violations, obvious logic errors, missing error handling, and basic security smells. That frees human reviewers to focus on design decisions, business logic, and architectural trade-offs.
Per Anthropic's documentation, Claude models support up to 200,000 tokens of context, which means you can comfortably feed in a full feature branch diff, a relevant portion of your domain model, and your team's coding standards document all in one request. For most .NET pull requests, that's more than enough headroom to get meaningful, context-aware feedback.
The cost math also works out. Per Anthropic's published pricing for Claude Sonnet 4, you're looking at roughly $3 per million input tokens and $15 per million output tokens. A typical .NET code diff with 500 lines comes to about 4,000β6,000 tokens. At that rate, a few hundred automated reviews per month runs well under $10 β significantly cheaper than the engineering time saved on a single senior developer cycle.
If you're already using the Claude API in other parts of your stack, adding a code review pipeline is a natural extension. I use it alongside n8n automations and in Claude Code directly, so having the API available in a .NET utility project makes it easy to integrate with existing tooling. If you're new to the Claude API, the Claude API Tool Use Tutorial is a solid starting point before diving into this one.
Setting Up the Anthropic .NET SDK
Anthropic publishes an official .NET SDK on NuGet. As of this writing, it supports all current Claude models, streaming, tool use, and structured outputs. Add it to your project with:
dotnet add package Anthropic.SDK
Create a .NET console project (or add to an existing utility project) and wire up a simple client. Store your API key in an environment variable β never hardcode it in source:
using Anthropic.SDK;
using Anthropic.SDK.Messaging;
var apiKey = Environment.GetEnvironmentVariable("ANTHROPIC_API_KEY")
?? throw new InvalidOperationException("ANTHROPIC_API_KEY is not set.");
var client = new AnthropicClient(apiKey);
The SDK follows the same patterns as the REST API, so if you've already read the Structured Outputs tutorial, the request/response model will feel familiar. The main difference is you're working with typed C# objects instead of raw JSON payloads.
For managing secrets in a CI/CD environment, use your pipeline's secret store (GitHub Actions secrets, Azure Key Vault, or AWS Secrets Manager) and inject the API key as an environment variable at runtime. Never commit it to source or bake it into your Docker image.
Building the Code Review Prompt
The quality of an AI code review lives and dies by the system prompt. A vague instruction like "review this code" produces vague output. The goal is to give Claude enough context about your team's standards and the specific concerns you care about, so the output is immediately actionable.
Here's the system prompt I use as a baseline for .NET/Angular projects:
const string systemPrompt = """
You are an expert .NET and Angular code reviewer with deep knowledge of:
- C# best practices, SOLID principles, and async/await patterns
- ASP.NET Core middleware, dependency injection, and Web API design
- Angular change detection, RxJS patterns, and component lifecycle
- SQL Server query performance and Entity Framework Core pitfalls
- Security: input validation, injection prevention, secrets handling
When reviewing code, you MUST:
1. Flag actual bugs and logic errors (highest priority)
2. Identify missing null checks, unhandled exceptions, and resource leaks
3. Call out async anti-patterns (e.g., .Result, .Wait(), fire-and-forget without error handling)
4. Note performance issues (N+1 queries, missing indexes via EF navigation properties)
5. Point out security concerns (SQL injection, XSS, exposed sensitive data)
You MUST NOT:
- Add generic style comments without specific line references
- Suggest refactors that change the logic of the code
- Comment on formatting if it follows standard .editorconfig rules
Respond only with a valid JSON object matching the schema provided.
""";
The "MUST NOT" section is important. Without it, Claude will happily produce five paragraphs about variable naming conventions when you care about the missing null check on line 47. Constrain the output to what's actually useful for your team.
For the user message, feed in the actual diff or file content along with any relevant context (the related interface, the domain model, or the test file if you have it):
string BuildUserPrompt(string fileName, string diffContent, string? contextCode = null)
{
var sb = new System.Text.StringBuilder();
sb.AppendLine($"## File: {fileName}");
sb.AppendLine();
sb.AppendLine("### Diff / Changed Code:");
sb.AppendLine("```csharp");
sb.AppendLine(diffContent);
sb.AppendLine("```");
if (!string.IsNullOrWhiteSpace(contextCode))
{
sb.AppendLine();
sb.AppendLine("### Related Context (interfaces, models):");
sb.AppendLine("```csharp");
sb.AppendLine(contextCode);
sb.AppendLine("```");
}
sb.AppendLine();
sb.AppendLine("Review the code above and return your findings as JSON.");
return sb.ToString();
}
Structured Output for Consistent Results
Getting back raw prose is fine for a one-off review, but for automation you want structured, parseable output every time. Define a C# record that matches the shape you want:
public record CodeReviewResult(
List<ReviewFinding> Findings,
string OverallAssessment,
bool HasBlockingIssues
);
public record ReviewFinding(
string Severity, // "critical" | "warning" | "info"
string Category, // "bug" | "security" | "performance" | "async" | "null-safety"
string LineReference, // e.g., "Line 34" or "Lines 40-45"
string Description,
string SuggestedFix
);
Then instruct Claude to return output matching this schema. Per Anthropic's documentation on structured outputs, you can pass a JSON schema in the request to enforce the response shape. In the .NET SDK, you can either do this via the schema parameter or by strongly instructing the model in the system prompt and parsing the response. I've found including the schema in the system prompt alongside a JSON schema definition produces reliable results:
async Task<CodeReviewResult?> ReviewCodeAsync(
AnthropicClient client,
string fileName,
string diffContent,
string? contextCode = null)
{
var messages = new List<Message>
{
new Message
{
Role = RoleType.User,
Content = BuildUserPrompt(fileName, diffContent, contextCode)
}
};
var request = new MessageParameters
{
Model = AnthropicModels.Claude3Sonnet,
MaxTokens = 2048,
System = systemPrompt,
Messages = messages
};
var response = await client.Messages.GetClaudeMessageAsync(request);
var rawJson = response.Content[0].ToString()?.Trim();
if (string.IsNullOrWhiteSpace(rawJson))
return null;
// Strip markdown code fences if present
if (rawJson.StartsWith("```json"))
rawJson = rawJson[7..].TrimEnd('`').Trim();
else if (rawJson.StartsWith("```"))
rawJson = rawJson[3..].TrimEnd('`').Trim();
return System.Text.Json.JsonSerializer.Deserialize<CodeReviewResult>(rawJson,
new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
Once you have the typed result, you can render it as a GitHub PR comment, post it to Slack, write it to a review log, or gate the CI pipeline on blocking issues. The structure makes all of those integrations straightforward.
Reading the Diff from Git
For CI integration, you'll want to pull the actual diff rather than hardcoding file content. From a .NET console app running in a pipeline, you can shell out to git diff and capture the output:
async Task<string> GetGitDiffAsync(string baseBranch = "main")
{
var psi = new System.Diagnostics.ProcessStartInfo("git")
{
Arguments = $"diff {baseBranch}...HEAD -- *.cs *.ts",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
using var process = System.Diagnostics.Process.Start(psi)
?? throw new InvalidOperationException("Failed to start git process.");
var output = await process.StandardOutput.ReadToEndAsync();
await process.WaitForExitAsync();
if (process.ExitCode != 0)
{
var error = await process.StandardError.ReadToEndAsync();
throw new InvalidOperationException($"git diff failed: {error}");
}
return output;
}
The -- *.cs *.ts filter limits the diff to C# and TypeScript files, skipping JSON configs, project files, and other noise that would waste tokens and dilute the review. Tune the file glob to match your stack.
For very large diffs, split by file and review each one separately. This also gives you per-file results you can attach directly to the relevant file in a PR review via the GitHub API.
GitHub Actions Integration
The most useful deployment is as a GitHub Actions step that runs on every pull request and posts the review as a PR comment. Here's a minimal workflow:
name: AI Code Review
on:
pull_request:
types: [opened, synchronize]
paths:
- '**.cs'
- '**.ts'
jobs:
review:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history needed for git diff
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Run AI Code Review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
run: |
dotnet run --project tools/CodeReviewTool/CodeReviewTool.csproj
Inside the console app, use the GITHUB_TOKEN to post the formatted review to the PR via the GitHub REST API. The octokit ecosystem has a .NET client (Octokit on NuGet), or you can make the REST call directly with HttpClient β it's a single POST to /repos/{owner}/{repo}/issues/{pr_number}/comments.
If you're using Azure DevOps instead of GitHub, the same pattern applies: diff the PR branch against the target, run the review, and post to the PR thread using the Azure DevOps REST API. The diff extraction and Claude call are identical; only the comment posting changes.
Prompt Caching for Repeated Reviews
If your system prompt includes a long coding standards document or a large context file, you'll benefit from prompt caching. Per Anthropic's documentation, prompt caching lets you mark a portion of the prompt as cacheable so repeated calls with the same prefix reuse the cached computation at a significant cost reduction β up to 90% on the cached portion.
For a code review pipeline, the system prompt plus your team's standards document is a natural cache candidate: it changes rarely, but gets sent on every review. This is worth setting up once you have the basic pipeline running. The Prompt Caching tutorial covers the exact API syntax if you want to layer that in.
A reasonable hardware companion for a self-hosted version of this pipeline: if you want to run a local model for code review instead of the cloud API (useful for internal code that can't leave the building), a Beelink SER5 Mini PC (~$299) running Ollama handles smaller models well. I run Ollama on exactly this setup β a Beelink on Proxmox β for private code that stays on-prem. That said, for most teams the Claude cloud API is the right call: better models, no maintenance, and the cost is minimal at the PR review scale.
For deeper reading on building AI-integrated systems like this, AI Engineering by Chip Huyen (~$45) covers the architecture patterns for integrating LLMs into production software. And if you want to understand the model layer behind what Claude is doing when it reads your code, Hands-On Large Language Models (~$50) is one of the clearest technical references available.
Tuning for Your Stack
The baseline prompt above catches common .NET and Angular issues, but the real value comes from tuning it to your specific codebase. Here are a few additions I recommend building in once you have the basics working:
Add your actual naming conventions. If your team uses a specific prefix for interfaces, private fields, or async methods, include that explicitly. Claude will flag violations against your stated convention, not generic C# style guides.
Include your forbidden patterns. If you've banned certain libraries, anti-patterns, or API usages (say, you've had recurring issues with DateTime.Now instead of DateTime.UtcNow, or Thread.Sleep in async code), list them. A one-line addition to the system prompt catches these reliably.
Feed in relevant interfaces. If the code being reviewed implements a specific interface or inherits from a base class, include that context. Claude will check whether the implementation is correct relative to the contract, not just whether the code looks reasonable in isolation.
Separate Angular and C# reviews. TypeScript and C# have different concerns, and mixing them in one prompt dilutes the focus. I run two passes β one for the C# diff, one for the TypeScript/Angular diff β with separate, targeted prompts for each. The results are noticeably more precise.
For a deep read on the software engineering fundamentals that an AI review like this should be enforcing, The Pragmatic Programmer 20th Anniversary Edition (~$45) remains the reference I'd hand to any developer on the team.
What This Doesn't Replace
An automated AI review pass is a first filter, not a replacement for human review. It consistently catches mechanical issues β null safety, async anti-patterns, obvious security misses β but it doesn't understand your product's business logic, your team's long-term architectural decisions, or the political context of a given PR.
The most effective setup I've seen treats the AI review as a required first gate: the bot posts its findings as a PR comment, the author addresses anything marked "critical" before requesting a human review, and the human reviewer uses the AI output as a checklist of things already checked. That structure saves real time without removing the human judgment from the process.
If you want to extend this further β having Claude not just flag issues but suggest fixes via tool use, or wiring it up to an n8n workflow that tracks review patterns across your team's PRs over time β the Claude API's tool use capabilities make that straightforward. The Claude API Tool Use Tutorial covers that layer in detail.
Want Claude dialed in for your workflow?
Book a 1-on-1 Claude setup call: 60 minutes, live, in English or Spanish, recorded for you. $127. Book the call β
Or start with the Claude Prompt Pack: 50 bilingual prompts, $17, instant download.