Six months ago I got fed up with my AI code review tool.
Two problems.
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 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:
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.
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:
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."
}
]
}
Six reports come back simultaneously.
That is where the interesting part begins.
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.
Security and bug reviewers frequently report the same issue.
Example:
Instead of showing duplicates, the synthesizer groups findings by:
and keeps the strongest explanation.
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
When conflicts occur, the final report still includes both viewpoints so the developer can override the decision.
Ordering matters more than people realize.
Nobody wants this:
Instead, findings are sorted by:
Severity
→ Category Weight
→ File
→ Line
Critical issues always appear first.
Finally the synthesizer emits one overall review.
Possible outputs:
based entirely on blocker 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.
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.
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 }}
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"
Detected immediately.
No reasoning required.
Another:
uses: some-org/action@main
Unpinned GitHub Actions.
Again, deterministic.
Not AI.
The scanner currently includes detectors for:
pull_request_target
...and several more.
Sometimes boring software beats AI.
Another decision I made early:
LGTM never owns your API usage.
You connect your own:
Every review runs against your account.
Not mine.
That means:
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.
| 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.
CLI:
npm install -g @tarin/lgtm-cli
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.
🌐 Website
🚀 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.