DEV Community

LooksGoodToMeow
LooksGoodToMeow

Posted on

I built an AI code reviewer with 6 parallel agents. Here’s the architecture, warts and all.

Six months ago I got fed up with my AI code review tool.

Two problems.

  • It charged roughly 3.5× the raw OpenAI API cost while pretending that wasn't happening.
  • It kept flagging phantom SQL injection in a codebase that literally had no SQL, while completely missing a real authorization bypass in the same pull request.

That combination broke my trust.

So I cancelled my subscription and started building my own.

Today I'm launching LGTM (Looks Good To Meow).

This isn't a launch post about features.

It's about the architecture, because that's the interesting part.


The one-prompt failure mode

The obvious implementation looks like this:

Give one LLM a giant system prompt telling it to review security, bugs, performance, readability, best practices and documentation all at once.

I built exactly that first.

It didn't work.

The model spread its attention across every category equally.

That meant:

  • Critical security issues got buried beneath variable naming suggestions.
  • Performance regressions were mixed together with documentation comments.
  • The review became 30+ unordered findings.

Beta users simply stopped reading after the first few comments.

I tried making the prompt more aggressive.

Prioritize security above everything else.

That solved one problem and created another.

Security became better.

Everything else became dramatically worse.

The fundamental issue remained.

One prompt was trying to solve six different problems.


Six agents in parallel

Instead of making one model do everything, I split the review into six independent reviewers.

Agent Responsibility
🔒 Security Auth, injection, secrets, XSS, unsafe deserialization
🐞 Bugs Correctness, null handling, race conditions
⚡ Performance N+1 queries, quadratic loops, allocations
📖 Readability Naming, function size, cognitive complexity
✅ Best Practices Language idioms and architectural patterns
📝 Documentation JSDoc, docstrings, README updates

Each receives:

  • the same PR diff
  • its own specialized system prompt
  • zero knowledge of the other reviewers

Every agent returns structured JSON.

{
  "agent": "security",
  "findings": [
    {
      "severity": "high",
      "file": "src/api/user.ts",
      "line": 47,
      "title": "Missing authorization check",
      "description": "DELETE endpoint allows any authenticated user to delete accounts.",
      "suggested_fix": "Verify ownership or admin role before deletion."
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Six reports come back simultaneously.

That is where the interesting part begins.


The synthesizer

Simply concatenating six reports produces garbage.

Real pull requests can easily end up with 40–60 findings.

Nobody reads that.

The synthesizer converts six raw reports into one review.

It performs four jobs.

1. Deduplication

Security and bug reviewers frequently report the same issue.

Example:

  • Missing null check
  • Unsafe input validation
  • Missing authorization

Instead of showing duplicates, the synthesizer groups findings by:

  • file
  • line
  • category

and keeps the strongest explanation.


2. Conflict resolution

Sometimes two reviewers disagree.

For example:

Security says:

Add rate limiting.

Performance says:

Remove rate limiting to improve latency.

They're both technically correct.

So I built a simple precedence system.

Security
    >
Correctness
    >
Performance
    >
Style
Enter fullscreen mode Exit fullscreen mode

When conflicts occur, the final report still includes both viewpoints so the developer can override the decision.


3. Ranking

Ordering matters more than people realize.

Nobody wants this:

  1. Rename variable
  2. Missing JSDoc
  3. Catastrophic auth bypass

Instead, findings are sorted by:

Severity
→ Category Weight
→ File
→ Line
Enter fullscreen mode Exit fullscreen mode

Critical issues always appear first.


4. Final verdict

Finally the synthesizer emits one overall review.

Possible outputs:

  • ✅ Approve
  • 🟡 Request Changes
  • ❌ Block

based entirely on blocker findings.


Why only show 10 findings?

One surprising lesson from beta testing:

People don't read long reviews.

The dashboard originally showed everything.

Average review length:

27 findings

Almost nobody reached the bottom.

Today LGTM only surfaces the top 10 findings plus a summary.

Everything else stays available inside the dashboard.

Ten wasn't chosen mathematically.

It was chosen because users actually read ten.


Building the synthesizer took longer than everything else

Early versions had weird behavior.

The longest report usually won.

Not because it found better issues.

Because the model subconsciously treated verbose output as more important.

I fixed that by normalizing token counts before synthesis.

Then another issue appeared.

The synthesizer became too aggressive.

Different findings got merged together.

That caused genuine bugs to disappear.

The fix was introducing a confidence score for every finding so uncertain matches remained separate.

Most of the work wasn't building reviewers.

It was teaching them how to disagree.


Some detectors are not LLMs

The CI/CD scanner doesn't use AI.

It shouldn't.

It consists of 16 deterministic detectors.

Example:

on:
  pull_request_target:

jobs:
  test:
    steps:
      - uses: actions/checkout@v3
        with:
          ref: ${{ github.event.pull_request.head.sha }}
Enter fullscreen mode Exit fullscreen mode

That's a classic pull_request_target vulnerability.

Static analysis detects it instantly.

I benchmarked several popular LLMs.

Two missed it completely.

One detected it but couldn't explain why it was dangerous.

Pattern matching wins here.

Another example:

env:
  API_KEY: "sk_live_xxxxxxxxx"
Enter fullscreen mode Exit fullscreen mode

Detected immediately.

No reasoning required.

Another:

uses: some-org/action@main
Enter fullscreen mode Exit fullscreen mode

Unpinned GitHub Actions.

Again, deterministic.

Not AI.

The scanner currently includes detectors for:

  • pull_request_target
  • hardcoded secrets
  • unpinned actions
  • privileged Docker containers
  • curl piped to shell
  • world-writable permissions
  • missing least privilege tokens
  • sudo without passwords

...and several more.

Sometimes boring software beats AI.


Bring Your Own Key (BYOK)

Another decision I made early:

LGTM never owns your API usage.

You connect your own:

  • OpenAI
  • Anthropic
  • Gemini

Every review runs against your account.

Not mine.

That means:

  • Your token usage appears directly on your provider bill.
  • I don't proxy or resell tokens.
  • I don't silently mark up usage.

Most AI products bundle token costs into subscriptions.

Eventually someone pays for that.

Usually the customer.

I preferred making pricing explicit.

The downside is obvious.

Users now have two bills.

For solo developers that's usually cheaper.

For larger organizations wanting one invoice, it's friction.

I'm considering managed API keys in the future.

Not today.


Pricing

Plan Price
Free ₹0/month
Hobby ₹399/month
Pro ₹999/month
Enterprise Custom

Top-ups are available separately for additional reviews and CI scans.

Payments are handled through Dodo Payments.


Tech Stack

  • Node.js
  • TypeScript
  • MongoDB
  • React
  • GitHub App
  • Fly.io

CLI:

npm install -g @tarin/lgtm-cli
Enter fullscreen mode Exit fullscreen mode

What's next?

I'm the only person building this.

The part I'm watching most closely isn't whether the AI finds bugs.

It's whether the synthesizer makes the same prioritization decisions that experienced engineers would.

If it disagrees with your judgment, I want to know why.

That's the failure mode I'm most interested in fixing.


Links

🌐 Website

https://looksgoodtomeow.in

🚀 Dashboard

https://app.looksgoodtomeow.in

📚 Documentation

https://docs.looksgoodtomeow.in

🏆 Product Hunt

https://www.producthunt.com/products/lgtm-looks-good-to-meow?utm_source=other&utm_medium=social

🐛 Feedback & Issues

https://github.com/tarinagarwal/lgtm-feedback


Thanks for reading.

If you're building AI developer tools, I'd genuinely love to hear how you're approaching review quality, ranking, or synthesis. I think that's where the next generation of AI coding tools will differentiate themselves.

Top comments (0)