<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Landry Monga</title>
    <description>The latest articles on Forem by Landry Monga (@lvndry).</description>
    <link>https://forem.com/lvndry</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F16752%2Fcba21620-ec8e-4d7e-a55b-ef697ac700bd.png</url>
      <title>Forem: Landry Monga</title>
      <link>https://forem.com/lvndry</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/lvndry"/>
    <language>en</language>
    <item>
      <title>Build your own AI code review agent in CI</title>
      <dc:creator>Landry Monga</dc:creator>
      <pubDate>Sat, 21 Feb 2026 14:13:20 +0000</pubDate>
      <link>https://forem.com/lvndry/build-your-own-ai-code-review-agent-in-ci-4mai</link>
      <guid>https://forem.com/lvndry/build-your-own-ai-code-review-agent-in-ci-4mai</guid>
      <description>&lt;p&gt;If you do PR reviews all day, you already know the pain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reviewers miss stuff when they’re tired&lt;/li&gt;
&lt;li&gt;the same comments repeat forever (naming, tests, edge cases)&lt;/li&gt;
&lt;li&gt;“quick PR” turns into a 45-minute context rebuild&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now imagine this instead:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every pull request gets an &lt;strong&gt;instant, structured code review&lt;/strong&gt; (correctness, security, performance, tests) posted automatically by CI using &lt;strong&gt;your choice of model&lt;/strong&gt; (OpenAI / Anthropic / OpenRouter / local Ollama) — without paying yet another “AI code review” subscription.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s the workflow.&lt;/p&gt;

&lt;p&gt;This post shows a &lt;strong&gt;simple&lt;/strong&gt; way to build a “coding agent” that reviews PR diffs and produces an actionable review. I’ll use &lt;a href="https://github.com/lvndry/jazz" rel="noopener noreferrer"&gt;Jazz&lt;/a&gt; as the runner because it’s designed for &lt;strong&gt;workflows + automation&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 80/20 in one minute
&lt;/h2&gt;

&lt;p&gt;You want a pipeline that does:&lt;/p&gt;

&lt;p&gt;1) CI checks out your repo&lt;br&gt;
2) an agent reads the PR diff&lt;br&gt;
3) it outputs a review in Markdown&lt;br&gt;
4) CI posts that review as a PR comment (or logs it / saves it as an artifact)&lt;/p&gt;

&lt;p&gt;The most important part is not the model.&lt;/p&gt;

&lt;p&gt;It’s the &lt;strong&gt;review rubric&lt;/strong&gt; (the prompt/workflow) that forces useful structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;separate &lt;em&gt;high-risk&lt;/em&gt; issues from nitpicks&lt;/li&gt;
&lt;li&gt;demand concrete fixes and test suggestions&lt;/li&gt;
&lt;li&gt;require “what I looked at” and “what I’m unsure about”&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Why DIY can be cheaper than subscriptions
&lt;/h2&gt;

&lt;p&gt;Chat subscriptions are awesome for interactive use, but CI code review is a different pricing pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it only runs &lt;strong&gt;when PRs happen&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;you can use &lt;strong&gt;pay-as-you-go APIs&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;you can route cheaper/faster models for small diffs&lt;/li&gt;
&lt;li&gt;or run &lt;strong&gt;local models&lt;/strong&gt; (Ollama) where the marginal cost is near zero&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With a DIY pipeline you control the knobs model choice, max tokens, when it runs, and what counts as “worth reviewing”.&lt;/p&gt;
&lt;h2&gt;
  
  
  What you’ll build
&lt;/h2&gt;

&lt;p&gt;By the end, you’ll have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a GitHub Action that runs on every PR&lt;/li&gt;
&lt;li&gt;a code review workflow that outputs a structured Markdown review&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Step 1: run the agent in GitHub Actions
&lt;/h2&gt;

&lt;p&gt;Create this file in your repo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Filename:&lt;/strong&gt; &lt;code&gt;.github/workflows/ai-code-review.yml&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AI Code Review&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;review&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
      &lt;span class="na"&gt;pull-requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Jazz&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install -g jazz-ai&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run code review workflow&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jazz --output raw workflow run code-review --auto-approve&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.OPENAI_API_KEY }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--output raw&lt;/code&gt; is nice in CI (easy to capture/redirect).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--auto-approve&lt;/code&gt; makes it fully unattended.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;permissions&lt;/code&gt; are intentionally minimal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don’t want OpenAI, swap the environment variables for your provider (Anthropic / OpenRouter / etc.).&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: define what “good code review” means (the rubric)
&lt;/h2&gt;

&lt;p&gt;This is where most “AI code review” attempts fail: they generate vibes, not review.&lt;/p&gt;

&lt;p&gt;A good rubric forces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;severity&lt;/strong&gt; (what would actually break prod)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;confidence&lt;/strong&gt; (what’s a guess)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;next actions&lt;/strong&gt; (exact fixes / tests)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create a workflow file (this is the prompt your agent will run):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Filename:&lt;/strong&gt; &lt;code&gt;workflows/code-review/WORKFLOW.md&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a template you can start with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;code-review&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Review PR diff and produce a structured report&lt;/span&gt;
&lt;span class="na"&gt;autoApprove&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read-only&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

Review the current PR diff.

Output GitHub-flavored Markdown with:

1) Summary (2–4 bullets)
2) High-risk issues (correctness + security)
3) Performance / complexity concerns
4) API / UX footguns
5) Test gaps + concrete test suggestions
6) Nitpicks (style/readability)

Rules:
&lt;span class="p"&gt;-&lt;/span&gt; Be specific: reference files/functions.
&lt;span class="p"&gt;-&lt;/span&gt; Prefer minimal diffs / smallest safe fix.
&lt;span class="p"&gt;-&lt;/span&gt; If you’re unsure, say so and propose how to verify.
&lt;span class="p"&gt;-&lt;/span&gt; No generic advice ("add tests") — propose exact test cases.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: post the review as a PR comment
&lt;/h2&gt;

&lt;p&gt;The simplest reliable approach:&lt;/p&gt;

&lt;p&gt;1) generate a markdown file&lt;br&gt;
2) post it using &lt;code&gt;gh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In CI, you can write the review output to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Filename:&lt;/strong&gt; &lt;code&gt;review.md&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate review markdown&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jazz --output raw workflow run code-review --auto-approve &amp;gt; review.md&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.OPENAI_API_KEY }}&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Comment on PR&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gh pr comment "$PR_NUMBER" --body-file review.md&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;GH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
    &lt;span class="na"&gt;PR_NUMBER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.event.pull_request.number }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inline annotations are possible later, but they’re not required to get value immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safety: keep it read-only in CI
&lt;/h2&gt;

&lt;p&gt;If you only take one thing from this post:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don’t let your CI agent mutate the repo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Keep auto-approve at &lt;strong&gt;read-only&lt;/strong&gt; for review jobs.&lt;/p&gt;

&lt;p&gt;Even if your tool can run shell commands or commit changes, you’ll get most of the value without giving it that power.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical tips to keep reviews useful (not noisy)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Force it to rank issues&lt;/strong&gt; (High/Medium/Low). If everything is “important”, nothing is.&lt;/li&gt;
&lt;li&gt;Add a “&lt;strong&gt;false positive budget&lt;/strong&gt;”: if it’s noisy for a week, devs will ignore it forever.&lt;/li&gt;
&lt;li&gt;Route by diff size: cheap model for small PRs, stronger model for large refactors.&lt;/li&gt;
&lt;li&gt;Require it to list: &lt;strong&gt;files reviewed&lt;/strong&gt;, &lt;strong&gt;assumptions&lt;/strong&gt;, and &lt;strong&gt;what it didn’t check&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advanced example
&lt;/h2&gt;

&lt;p&gt;Jazz repo is using Jazz for its own code reviews and release notes: &lt;a href="https://github.com/lvndry/jazz/tree/main/.github" rel="noopener noreferrer"&gt;https://github.com/lvndry/jazz/tree/main/.github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>githubactions</category>
      <category>cicd</category>
    </item>
  </channel>
</rss>
