Skip to content

Repository files navigation

🛡️ Sentinel — AI Code Reviewer

Paste or upload code and get a senior-engineer-style review: 🐛 bugs with concrete fixes, 💡 design suggestions, ⏱️ algorithmic complexity analysis, and a 0–100 health score — every finding grounded in real line numbers from your file.

status stack


✨ Features

  • 📤 Upload or paste code — drag a file onto the editor or paste directly, with a synced line-number gutter
  • 🤖 AI-powered review — bugs, warnings, suggestions, and praise, each pinned to the exact line
  • 🔧 Concrete fixes — every bug/warning finding includes a suggested code fix, not vague advice
  • ⏱️ Complexity analysis — Big-O time & space, explained in plain language
  • 📊 Health score — a 0–100 score with a rubric behind it, not vibes
  • 🎯 Optional review focus — steer the reviewer toward security, performance, readability, etc.
  • 🔌 Bring your own model — OpenAI, OpenRouter, OmniRoute, Ollama, or anything OpenAI-compatible

📸 Proof it works

Same file, two runs. The reviewer catches a real syntax bug (an unmatched closing brace), scores it accordingly — then after the fix, correctly recognizes the code as clean and bumps the score to 95.

🐛 Before — bug caught ✅ After — fix verified
Sentinel catching a syntax error, scoring 35/100 Sentinel confirming the fix, scoring 95/100
Flags the extra } on line 12 as a BUG, explains why it breaks compilation, and gives the exact fix (Remove line 12 entirely) — while still praising what's correct elsewhere in the function (overflow-safe midpoint, readonly param). Re-running after the fix: score jumps from 35 → 95, the bug list is empty, and it now offers a SUGGESTION-level improvement (add JSDoc) instead of a blocking issue.
Layer Tech
Framework Next.js 14 (App Router)
Language TypeScript
Styling Tailwind CSS
AI OpenAI API (or any OpenAI-compatible endpoint — local or gateway-routed)

🚀 Getting started

npm install
cp .env.example .env.local
# edit .env.local — add your API key (see provider options below)
npm run dev

Open http://localhost:3000, paste some code (or drop a file onto the editor panel), optionally give it a focus like security or performance, and hit Run review. 🎉


🔑 Choosing a model provider

The app reads three env vars — set the two/three that match your provider and nothing else needs to change in the code.

Option A — OpenAI directly

OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4o-mini

Option B — 🧭 OmniRoute (self-hosted local gateway)

OmniRoute is a free, self-hosted AI gateway that puts one OpenAI-compatible endpoint in front of 280+ providers (Claude, GPT, Gemini, DeepSeek, Kimi, and more) — handy if you want to point this app at a Claude model without an Anthropic key, or want automatic fallback across providers.

1. Install it:

npm install -g omniroute
omniroute
# API:       http://localhost:20128/v1
# Dashboard: http://localhost:20128

2. Get an API key: Open the dashboard at http://localhost:20128Endpoints, and copy the key shown there (this is OmniRoute's own gateway key, not a provider key — you connect individual providers separately from the Dashboard's Providers tab).

3. Point Sentinel at it — in .env.local:

OPENAI_API_KEY=your-omniroute-key
OPENAI_BASE_URL=http://localhost:20128/v1
OPENAI_MODEL=kr/claude-sonnet-4.5   # or any model id from `omniroute models --search <term>`

⚠️ Note the /v1 on the base URL — the dashboard root (/home) is not the API endpoint.

4. Restart:

npm run dev

Env vars are only read at process start, so a restart is required after any .env.local change.

Option C — 🌐 OpenRouter (hosted, no self-hosting)

OPENAI_API_KEY=sk-or-v1-...
OPENAI_BASE_URL=https://openrouter.ai/api/v1
OPENAI_MODEL=openai/gpt-oss-20b:free

Sign up at openrouter.ai/keys — no card required for :free-suffixed models.

Option D — 🖥️ Fully local (Ollama, LM Studio, vLLM)

OPENAI_API_KEY=not-needed        # any non-empty string
OPENAI_BASE_URL=http://localhost:11434/v1
OPENAI_MODEL=llama3.1

🩺 Debugging a failed review

The server logs a masked fingerprint of the key it's using on every request:

[openai] using key sk-abc…7055 (len 35) via http://localhost:20128/v1
  • 401 / missing auth → the key isn't loading. Check .env.local is at the project root (next to package.json), has no quotes/extra spaces around the value, and that you restarted npm run dev after editing it.
  • 502 / parse error → the model responded, but not in valid JSON. The server console (dev mode) prints the raw response above the error — the reviewer already retries once without response_format and strips stray markdown fences, but a very small/undertrained model may still misbehave.

🗂️ Project structure

app/
  api/review/route.ts   → validates input, calls the model, returns JSON
  page.tsx               → split-pane UI (editor left, review right)
  layout.tsx, globals.css
components/
  CodeInput.tsx           → editor pane: line numbers, upload, severity gutter rail
  ReviewPanel.tsx          → results pane: summary, score, complexity, findings
  FindingCard.tsx           → single finding (severity, detail, suggested fix)
  ScoreGauge.tsx              → circular 0–100 score indicator
lib/
  prompts.ts              → 🧠 system prompt + user-prompt builder (the prompt engineering core)
  openai.ts                 → OpenAI client wrapper, retries, JSON parsing/validation
  types.ts                    → shared TypeScript types for the review contract
  ui.ts                         → severity color/label metadata, filename→language guess

🧠 How the prompt engineering works

This is the part worth reading if you're studying the repo rather than just running it.

  1. Line-numbered source — every line of submitted code is numbered ( 12 | const x = 1) before it reaches the model, so findings can cite real lines instead of guessing them.
  2. A closed JSON contract — the system prompt defines an exact output schema and the API call requests response_format: json_object. If a model/gateway rejects that param, the client automatically retries once without it, and strips markdown fences before parsing — this is what makes it resilient across OpenAI, OpenRouter, OmniRoute-routed Claude, and local models.
  3. Calibration rules, not just a task description — the prompt explicitly tells the model to prefer a few high-confidence findings over noise, to never invent a line number, and to always include a concrete fix for anything rated bug/warning. This is the single biggest lever for review quality — a vague prompt produces a vague review.
  4. A scoring rubric — the 0–100 health score is anchored to explicit bands (90–100 production-ready, 70–89 minor issues only, etc.) so scores are comparable across different pieces of code instead of being mood-based.
  5. Low temperature (0.2) — code review should be consistent and grounded, not creative.

See lib/prompts.ts for the full system prompt.


🎨 Design

Dark, IDE-inspired theme (IBM Plex Mono/Sans, a deep blue-black base, and a 4-color semantic severity palette — red/amber/violet/green for bug/warning/suggestion/praise). The signature UI element is the severity gutter rail: after a review runs, small colored ticks appear next to the exact lines with findings, mirroring an editor's error gutter — so you can spot where the issues cluster before reading a single card.


📝 Notes / next steps

  • MAX_CODE_LENGTH in app/api/review/route.ts caps requests at 20,000 characters — raise it for larger files, at the cost of latency and token spend.
  • Stateless by design — no review history or persistence. Add a database if you want to keep past reviews.
  • For very large files, consider chunking by function/class and merging findings rather than one giant single-shot review.

Built with 🧠 + ☕. PRs and issues welcome.

About

AI-powered code reviewer that catches bugs, suggests fixes, and explains complexity — grounded in real line numbers. Next.js + TypeScript + Tailwind.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages