Evidence-backed LLM code review for merge requests. Watches GitLab MRs, runs a structured agent review, and posts only actionable findings as inline review threads — no chatbot noise, no praise, no summaries.
The bot posts inline review threads in a fixed shape — Issue / Impact /
Evidence / Fix / Confidence:
Issue: HS256 JWT fallback is skipped when Cognito URL construction fails.
Impact: Valid local/shared-secret JWT requests return 500 instead of authenticating.
Evidence: The changed interceptor rethrows InvalidAwsUrlException before fallback runs.
Fix: Treat Cognito validation construction failures as failed Cognito auth when fallback is allowed.
Confidence: 0.94
When a review finds nothing actionable, the bot posts a single change-level acknowledgement so a clean MR/PR is distinguishable from one the reviewer never touched:
Automated review ran — no issues found.
This is idempotent on exact body match scoped to the bot's author — re-reviews
on rebases or repeated polls reuse the existing comment. Default-on; configure
or disable under [agents] (see the configuration reference).
Real (sanitized) inline findings on GitLab MRs:
More sanitized examples are in docs/examples/README.md. Demo GIF: docs/media/llm-reviewer-demo.gif.
Install prereqs (uv, Python 3.14+, Git, plus the CLI for your SCM and a Codex/Claude agent — see prerequisites for the copy-paste blocks), then:
uv tool install git+https://github.com/mountainowl/ai-code-review@v0.6.0
llm-reviewer init # idempotent; --dry-run to preview
# Edit ~/.local/share/llm-reviewer/config/env.toml:
# [gitlab].token, [agents].llm_api_key, [agents].llm_model,
# and at least one [[projects]] entry.
llm-reviewer doctor # verify before first poll
mr-review-poller # one poll cycle; exits at the endThe first cycle runs with [review].dry_run = true (the default) — findings
are planned but no comments are posted. Flip to false once a real review
looks right. For the full install + bot-account walkthrough, see
install and configure. For poller flags
and the bundled MCP server, see run.
flowchart TB
A["Open merge requests"]
B["Poller<br/>+ SQLite state"]
C["Forked review worker"]
D["Agent review skill<br/>(Codex / Claude)"]
E["Inline review<br/>discussions"]
F["OpenTelemetry<br/>+ outcome sync"]
A --> B --> C --> D --> E --> F
- The poller lists open MRs for each configured project, skipping any it has already reviewed at the current head SHA.
- For each eligible MR it forks a worker. The worker checks out the MR diff, runs the agent review skill, and parses structured findings.
- Each finding is mapped to a changed line in the MR diff and posted as an
inline GitLab review thread (or stored as a "planned" finding if
dry_runis on). - If a review finishes with zero findings, the worker posts a single
change-level acknowledgement comment (the no-findings comment) so
reviewer-ran-and-passed is distinguishable from reviewer-never-ran.
Default-on, dedup'd by bot author + exact body; honors
dry_run; a failure to post the acknowledgement is a soft error that does NOT flip the underlying clean review toFAILED. - SQLite records reviewed SHAs and posted-finding fingerprints so the bot does not spam the same MR or duplicate a comment.
--sync-outcomeslater checks which posted findings were resolved, replied to, marked false-positive, deleted, or merged-unresolved.
The poller does not try to be a code-review brain. It orchestrates SCM access, state, prompt rendering, posting, and metrics. The actual review logic lives in the configured CLI skill.
| Doc | What's in it |
|---|---|
| Prerequisites | macOS / Linux runtime, per-provider tools, credentials, install verification. |
| Install and configure | uv tool install, llm-reviewer init, the minimum config/env.toml, GitLab and GitHub bot setup. |
| Run | One-off review, the GitLab poller, the bundled mcp-llm-reviewer MCP server (three deployment patterns) and upstream wrappers. |
| Configuration reference | Every [scm] / [gitlab] / [github] / [review] / [poller] / [agents] / [telemetry] / [[projects]] setting and its default. |
| Operate | Remote deploy, scheduling under cron or systemd, --sync-outcomes grading, one-shot backfill. |
| Telemetry | Emitted llm_review.* metrics, ready-made dashboard queries, cardinality discipline. |
- GitLab posting via polling — production path. Stable.
- GitHub posting via polling — supported, at outcome-metric parity with
GitLab. Set
[scm].provider = "github"(or rungh-review-poller, which forces it). See how the GitHub provider talks to GitHub for the MCP/REST + GraphQL details. - Webhook-driven triggering — not implemented; polling is the only path.
- pip-only install — not supported. The install needs the bundled prompt, skill, config template, wrapper scripts, and deployment templates that ship with the checkout.
Review execution is intentionally outside CI/CD. Run it as a poller beside your existing pipelines.
config/env.tomlis gitignored and holds tokens. Do not print or commit real values from it.- Review-agent stdout is redacted (
GITLAB_TOKEN=,OPENAI_API_KEY=,glpat-…,sk-…, and credentialed Git URLs) before being written to reports, logs, or the database error column. - The reviewer subprocess is launched with a strict env allowlist (see
REVIEWER_ENV_ALLOWLISTinsrc/llm_reviewer/poller.py) — host secrets are not passed wholesale into the LLM agent. - Report vulnerabilities per
SECURITY.md.
Upload assets/llm-reviewer.png as the GitLab (or
future GitHub) bot avatar.


