Observed since 20 Oct, 22:13 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Production-grade agentic code reviewer: multi-step LLM workflow with context retrieval, verification, and reproducible benchmarking.
A production-grade, agentic code reviewer. It analyzes real software changes the way a senior engineer would - planning, targeted repository context, staged analysis across 23 evidence-backed categories, layered deterministic verification (regex, AST, symbol, taint), and a final aggregated review - then measures whether that agentic approach actually beats single-pass review with a leakage-controlled benchmark. Ships as the
acrCLI with a full-screen Textual terminal dashboard, works with six LLM providers, and needs no.envfile: everything is configured from the CLI or the TUI.
Code review is a verification problem disguised as a language problem. A single LLM call against a diff produces fluent prose with no guarantee any of it is true - findings get invented, lines get cited that were never changed, and there is no mechanism that catches a hallucinated defect before it reaches the developer. Manual review avoids this failure mode but doesn't scale: reading, cross-referencing, and judging every changed line by hand is exactly the high-volume, well-defined cognitive labor automation should be doing.
The core requirement is not "generate findings." It is "generate findings that have been checked."
Agentic Code Reviewer answers this by never letting a single model both write and grade its own work - every claim is re-verified against the actual repository, the real diff, and the changed lines before it ships.
confirmed, strongly_supported, insufficient_evidence, or rejectedprimary_category and related_categories; cross-change interactions are detected as materially new defects--fail-on <severity> exits non-zero when the gate trips; per-repo policy files drive gates for every contributor$KNOWLEDGE$; deterministic token-overlap retrieval with zero extra token cost432 tests passing, ruff clean, mypy clean across 100 source files, and a fully offline test suite - provider calls are transport-mocked and workflow/UI tests run against deterministic mock clients.
| Signal | Value |
|---|---|
| Review categories | 23 (22 LLM agents + deterministic dead-code) |
| Evidence statuses | confirmed / strongly_supported / insufficient_evidence / rejected |
| LLM providers | 6 (OpenAI, Anthropic, Gemini, OpenAI-compatible, Ollama, mock) |
| Output formats | Markdown, JSON, SARIF 2.1.0 |
| Benchmark systems | single-pass, context, rag, agentic |
| Test suite | 432 passing, fully offline |
| Runtime execution of reviewed code | never |
An honest benchmark: metrics are empty until experiments actually run - nothing is fabricated. Run acr benchmark (keyless with the mock provider) to reproduce the full harness yourself.
The reviewer judges a change across 23 evidence-backed categories. All share the same hard rules: concrete evidence tied to a changed line, severity critical → info, confidence in [0, 1], and style preferences are never reported.
| Category | What it checks |
|---|---|
| Correctness | wrong conditions / off-by-one, missing null handling, state transitions, API misuse, resource leaks |
| Security | injection, XSS, auth bypass, secret exposure, unsafe subprocess/deserialization, weak crypto, SSRF, path traversal, prompt-injection risks |
| Error handling | uncaught/swallowed exceptions, retry/timeout gaps, resource leaks on error paths, partial failures |
| Testing | coverage of changed behaviour (happy path, empty, invalid, boundary, failure), negative/boundary cases, tests that mirror buggy logic, skipped/empty tests |
| Regression | changed/removed APIs & defaults, changed error semantics, silently-broken callers |
| Performance | algorithmic regressions, N+1 queries, blocking calls in async paths, unbounded caches |
| Maintainability | material risks only: dead/duplicated logic, god functions, leaked abstractions |
| Observability | swallowed errors with no log/metric, invisible production failure paths |
| Data integrity | migrations breaking existing rows, missing validation, serialization compat, partial writes |
| Accessibility | frontend changes: missing labels/alt, keyboard operability, focus traps, colour-only meaning |
| Concurrency | races, check-then-act, mutation during iteration, async pitfalls, lock ordering |
| Dependencies | new/upgraded deps, unpinned or latest/* ranges, lockfile/manifest drift, unjustified new attack surface |
| Privacy | PII in logs/errors/analytics, missing audit trails, sensitive data exposed without justification |
| i18n | hardcoded user-facing strings, locale/timezone formatting assumptions, translation-breaking concatenation |
| API contract | breaking signature/export/data-shape changes with real consumers (external or in-repo callers) |
| Requirement alignment | does the diff satisfy the stated intent? scope creep, named acceptance criteria unmet - only runs when a requirement is provided |
| Authorization | IDOR/BOLA, missing ownership checks, privilege escalation, tenant isolation, missing auth on new routes |
| Reliability / Resilience | retry storms, retries of non-idempotent operations, duplicate processing, missing idempotency, cascading failures, queue ack problems, timeout mismatches |
| Architecture / Design | bypassing established abstractions, violated module boundaries, circular dependencies, logic leaking into the wrong layer, duplicated capabilities |
| Compatibility | incompatible serialized data, changed event/message schemas, renamed env vars, changed CLI args, rolling-deployment coexistence |
| Configuration / Deployment | new required env vars without config, type mismatches, broken health/readiness checks, startup-order and migration sequencing |
| Resource lifecycle | file/socket/connection leaks, goroutines/tasks that never terminate, listeners/subscriptions never removed, locks never released, timers never cleaned up |
| Dead code (deterministic) | newly-added imports and locals never referenced anywhere in the repository snapshot - no LLM involved |
Findings do not flow from the LLM straight to the report. Each one is resolved against the repository first:
LLM finding
↓
Evidence resolver
↓
Regex verification
↓
AST verification
↓
Symbol/reference verification
↓
Semantic verification (taint)
↓
Evidence status
| Status | Meaning |
|---|---|
confirmed | a deterministic rule, AST rule, symbol analysis, or equivalent independently confirms the claim |
strongly_supported | the finding is backed by multiple concrete repository facts, but no deterministic rule fully proves it |
insufficient_evidence | the LLM made a plausible claim but could not establish sufficient evidence |
rejected | the claim contradicts the actual repository state or fails evidence requirements |
Only confirmed and strongly_supported findings normally reach the user (configurable via VERIFICATION_STRICTNESS). Deterministic confirmation is never fabricated - if the evidence cannot be established, the finding does not ship.
Code Change (GitHub PR / commit / local git)
↓
Diff ingestion → Planner → Change Understanding → Context Retrieval (RAG)
↓
22 analysis agents in parallel Dead Code (deterministic, no LLM)
correctness, security, testing, ↓
regression, performance, ... Evidence verification (regex → AST → symbol → taint)
authorization, reliability, ↓
architecture, compatibility, Cross-category correlation + interaction analysis
configuration, resource lifecycle ↓
Aggregation → Final Review (Markdown / JSON / SARIF)
Every stage is a typed component (pydantic in/out) with its own timeout, retry policy, structured error recording, and observability. LLM failures degrade gracefully - a single failed reviewer never destroys the review; the workflow continues and records the stage error. The workflow streams typed events (orchestration/events.py) so the TUI renders live progress without blocking the review thread.
agentic-code-reviewer/
|
+-- src/agentic_code_reviewer/
| +-- agents/ planner, change_analyzer, 22 analysis agents + a
| | deterministic dead-code checker, verifier, aggregator
| +-- orchestration/ workflow state machine, review state, typed event stream
| +-- analysis/ diff parsing, repository snapshot, AST rules, taint
| | engine, severity model, category rules, aggregation
| +-- retrieval/ symbol-aware chunking, embeddings, vector index
| +-- knowledge/ persistent knowledgebase: models, JSONL store,
| | token-overlap retrieval, auto-capture, prompt renderer
| +-- github/ GitHubClient, models, adapters
| +-- llm/ provider clients (OpenAI, Anthropic, Gemini, Ollama,
| | OpenAI-compatible, mock), retries, structured output
| +-- evaluation/ benchmark, baselines, metrics, experiments, runner
| +-- cli/ typer CLI: review commands, init, completion, exporters,
| | interactive triage, knowledge management
| +-- ui/ Textual TUI: apps, screens, widgets, theme
| +-- config/ models/ observability/ local/ prompts/
|
+-- tests/ unit + integration + failure-path tests (fully offline)
+-- benchmarks/ datasets (fixture + importer output), metadata, results
+-- configs/ example experiment YAML
+-- docs/ architecture, research, security, screenshots
+-- pyproject.toml
+-- LICENSE
# From PyPI
pip install agentic-code-reviewer
# From source (development / full extras)
git clone https://github.com/royxforge/agentic-code-reviewer.git
cd agentic-code-reviewer
pip install -e ".[all]"
Requirements: Python 3.11+ · pydantic 2.12+ · typer 0.15+ · rich 13.9+ · textual 8.0+ (provider SDKs are optional extras)
Optional extras: .[openai] for the OpenAI SDK, .[anthropic] for the Anthropic SDK, .[dev] for testing/linting tooling, .[all] for everything. Gemini and Ollama speak plain HTTP - no SDK required.
# 1. One-time provider setup (stored in your user config, no .env file)
acr get-started
# 2. Review local uncommitted changes
acr review-local . --output review.md
# 3. Watch it run live in the terminal dashboard
acr tui review-local .
One word, like claude: install the global launcher once (adds acr to your PATH), then from any git project just type:
powershell -ExecutionPolicy Bypass -File scripts/install-cli.ps1
acr # launcher menu on the current directory
acr path/to/project # launcher menu on any other git project
acr --help # all commands
On the very first run (no provider configured yet) a welcome screen auto-opens and walks you through provider setup - or lets you explore instantly with the keyless mock provider. If the working tree has no uncommitted changes, a review automatically falls back to the last commit. The old reviewer command is kept as a backwards-compatible alias.
No key handy? The mock provider runs a deterministic test double (never a real model) - the keyless smoke path for the whole pipeline:
LLM_PROVIDER=mock acr benchmark --dataset benchmarks/datasets/fixture_small.json \
--systems single-pass,agentic --limit 2
| Command | Description |
|---|---|
acr | Launcher menu on the current directory (review / providers / history / help) |
acr review --repo o/r --pr 123 | Review a GitHub pull request (public repos work without a token) |
acr review-commit --repo o/r --commit <sha> | Review a single commit |
acr review-local <path> | Review local uncommitted changes in a git repo |
acr benchmark --dataset <file> | Run baseline + agentic systems over a dataset |
acr evaluate --config <yaml> | Run a reproducible experiment from a config |
acr init | Scaffold a .reviewer.yaml repository policy file |
acr knowledge add/list/remove/search | Manage curated rules, auto-captured findings, and indexed docs |
acr knowledge index-docs <path> | Index markdown docs into the knowledgebase |
acr completion bash|zsh|fish|powershell | Print shell completion |
acr tui … | The same commands inside the interactive dashboard |
acr --version | Show the version |
Common options:
--output review.md - write the review as Markdown--format markdown|json|sarif - output format (default markdown)--fail-on <severity> - quality gate: exit 1 when a finding at or above this severity exists--interactive / -i - triage findings after the review: apply (via git apply), dismiss, copy, skip, or quit--apply - non-interactively apply every suggested fix to the working tree--publish - post the review on GitHub (requires a write-scoped GITHUB_TOKEN)--base <ref> - diff against a different base ref for review-local (default HEAD)--requirement "..." - stated intent to review against; feeds the planner and the requirement-alignment check--provider <name> - override LLM_PROVIDER for a single run (benchmark commands)acr review --repo owner/repository --pr 123
acr review-commit --repo owner/repository --commit abc123
acr review-local . --output review.md
acr review --repo owner/repository --pr 123 --publish
acr review-local . --requirement "Search must be case-insensitive"
Typing acr opens a full-screen Textual launcher; the live pipeline, findings browser, and everything else live inside the same session. Logs are redirected to a temp file while it runs, so the screen is never corrupted.
Real screenshots (regenerate anytime with python scripts/screenshot_tui.py):
| Boot splash | Launcher | Providers & API keys |
|---|---|---|
| Review history | Help | Live pipeline |
|---|---|---|
| Findings browser | Findings by category | Benchmark runner |
|---|---|---|
acr launches: block-letter logo, product name, version, and an animated loading line; auto-dismisses after ~1.8s or skips on any key↑/↓ or j/k + enter, or the number keys)c from results) - every finding grouped by check type across all 23 categories, with live severity chips and zero-count categories kept visiblectrl+s saves to your user configctrl+p) - review, providers, history, help, exports (Markdown / JSON / SARIF), clear history, open config folderSet LLM_PROVIDER (in the environment or via acr get-started) and the matching credentials. Both openai-compatible and openai_compatible spellings are accepted.
| Provider | LLM_PROVIDER | Requirements | Extra install |
|---|---|---|---|
| OpenAI | openai | OPENAI_API_KEY; optionally OPENAI_BASE_URL / OPENAI_MODEL | .[openai] |
| Anthropic | anthropic | ANTHROPIC_API_KEY; optionally ANTHROPIC_MODEL | .[anthropic] |
| Google Gemini | gemini | GEMINI_API_KEY; optionally GEMINI_MODEL (default gemini-2.5-flash) | none (plain HTTP) |
| OpenAI-compatible | openai-compatible | OPENAI_COMPATIBLE_BASE_URL and OPENAI_COMPATIBLE_MODEL; API key optional | .[openai] |
| Ollama | ollama | a running Ollama server at OLLAMA_BASE_URL; no key | none |
| Mock (tests) | mock | none - deterministic test double, not a real model | none |
The Gemini client talks to the v1beta REST API over plain HTTP with responseMimeType: application/json for structured output. Any endpoint speaking the OpenAI chat-completions protocol works as openai-compatible. EMBEDDING_PROVIDER=auto picks the embedding model that matches your LLM provider and falls back to a deterministic local TF-IDF embedder - RAG works fully offline.
Every review command accepts --fail-on <severity>: when the review contains a finding at or above that severity, the command exits with code 1 - the standard hook for CI/CD. Human status always goes to stderr; stdout stays clean for the machine format.
# Fail the pipeline on any critical or high finding
acr review-local . --fail-on high
# Machine-readable report + gate, in one shot (CI-friendly)
acr review-local . --format json --fail-on high > review.json
# .github/workflows/code-review.yml (GitHub Actions)
- name: Agentic code review
run: acr review-local . --fail-on high --format sarif \
--output ${{ github.workspace }}/review.sarif
--fail-on beats the repo policy; without the flag, the policy in .reviewer.yaml applies.
Run acr init to scaffold a policy file, or write one by hand. It is discovered upward from the reviewed path, so the file checked into your repo controls every contributor's run. Unknown keys are rejected loudly (a typo'd policy must never silently do nothing).
# .reviewer.yaml
quality_gate:
critical: 0 # fail when any critical finding exists
high: 5 # fail when more than 5 high findings exist
medium: 20
low: null # never fail on low / info
info: null
ignore_patterns: # findings on these paths are dropped
- "**/test_*.py"
- "**/tests/**"
- "docs/**"
- "*.lock"
severity_weights:
critical: 1.0
high: 0.8
medium: 0.5
low: 0.2
info: 0.0
# Optional model overrides (any Settings field, kebab or underscore)
# max_tokens: 8192
# temperature: 0.2
# providers:
# llm_provider: openai
# openai_model: gpt-4o-mini
acr can remember across reviews. The knowledgebase is a persistent store (JSONL under your user config dir, config_dir()/knowledge/) of three kinds of entries, all injected into analysis prompts via the $KNOWLEDGE$ block:
| Kind | How it gets in | Example |
|---|---|---|
rule | acr knowledge add --title ... --content ... | "This repo uses SQLAlchemy 2.0 style" |
finding | auto-captured when KNOWLEDGE_AUTO_CAPTURE=true (repo memory) | "[high] SQL injection in db.py (2026-08-15): use parameterized queries" |
dismissed | recorded automatically when a finding is dismissed in triage | "SQL injection via interpolated query (dismissed: suppress in future reviews)" |
doc | acr knowledge index-docs docs/ | a section from docs/architecture.md |
acr knowledge add --repo owner/repo --category security \
--title "Parameterized SQL required" \
--content "Never interpolate user input into SQL strings; use ? placeholders."
acr knowledge list --repo owner/repo
acr knowledge search "sql injection" --repo owner/repo
acr knowledge index-docs docs/ --repo owner/repo
Retrieval is deterministic token-overlap scoring - no LLM call and no embedding endpoint - so the knowledgebase adds zero token cost and works fully offline. The next review of the same repository sees the entries most relevant to the current diff and can reference past decisions instead of re-deriving them.
Learning loop: the knowledgebase is not just one-way memory. Dismiss a finding in interactive triage (-i) and a dismissed entry is recorded for that repository - future reviews suppress findings that match it (same category + strong token overlap, or same file + category). The reviewer learns "we already decided this class of issue is acceptable here" from your decisions.
Every run is token-aware by design, and several levers cut cost on the 22 parallel analysis calls:
diff_text_for_category), falling back to the full diff when nothing matches. The full diff is still what the evidence verifier checks against.cache_control (opt-out: USE_PROMPT_CACHING=false), so parallel agents pay one full read + cache reads.ANALYSIS_MAX_TOKENS=4096 (vs the global MAX_TOKENS=8192).KNOWLEDGE_MAX_CHARS caps the injected $KNOWLEDGE$ block.AGGREGATOR_MAX_FINDINGS (default 60) limits the findings serialized into the aggregator prompt.LLM_CACHE_ENABLED=true, structured responses are stored on disk keyed by prompt content + model + params, so repeat reviews of identical diffs (CI) skip the provider entirely.Watch the live usage ticker (tokens, cost, LLM calls) in the TUI pipeline screen, or read token_usage / estimated_cost_usd from --format json output.
--format json - canonical machine view of the review (findings, metrics, model, cost, token usage) for dashboards and downstream tooling--format sarif - SARIF 2.1.0, so findings plug into GitHub Advanced Security, GitLab code scanning, VS Code, and CI dashboards--format markdown (default) - the human-readable reportWith --format json|sarif the human summary is printed to stderr, keeping stdout strictly parseable. Interactive triage (--interactive / --apply) walks findings after the review and can apply suggested fixes to the working tree via git apply (never stages or commits).
Four systems are compared under identical conditions:
# Run all four systems over the fixture dataset (keyless: --provider mock)
acr benchmark --dataset benchmarks/datasets/fixture_small.json \
--systems single-pass,context,rag,agentic
# Reproducible experiment from a YAML config
cp configs/experiment.yaml.example configs/experiment.yaml
acr evaluate --config configs/experiment.yaml
Experiment config keys: name, dataset, systems (list or comma string), limit (or null), settings (any Settings field, e.g. ablation switches like workflow_use_retrieval: false), notes. Results - metrics, prompts, per-entry artifacts - land in an immutable, timestamped directory under experiments/.
Fetch real historical-bug data (SWE-bench; requires pip install datasets):
python scripts/fetch_swebench.py --output benchmarks/datasets/swebench_review.jsonl --limit 20
pip install -e ".[dev]" # or ".[all]" for providers + dev tools
pytest # 432 tests: unit + integration + failure-path
ruff check src/ tests/ # lint
mypy src/agentic_code_reviewer # type checking
The test suite is fully offline: provider calls are transport-mocked, and the workflow/UI tests run against the deterministic mock and AdaptiveMock clients. The TUI screenshots are regenerated with python scripts/screenshot_tui.py.
All settings are read from environment variables and map to Settings fields in src/agentic_code_reviewer/config/settings.py. Providers and API keys are normally set through acr get-started or the TUI Providers screen, which persist them to your user config.
| Variable | Default | Purpose |
|---|---|---|
LLM_PROVIDER | openai | openai | anthropic | ollama | gemini | openai-compatible | mock |
TEMPERATURE / MAX_TOKENS | 0.2 / 8192 | model behaviour |
LLM_TIMEOUT_SECONDS / LLM_MAX_RETRIES / LLM_RETRY_BACKOFF_SECONDS | 120 / 3 / 2 | retry policy (exponential backoff) |
STAGE_TIMEOUT_SECONDS | 300 | per-stage deadline |
MIN_FINDING_CONFIDENCE | 0.6 | false-positive control |
VERIFICATION_STRICTNESS | balanced | strict (confirmed only) | balanced (confirmed + strongly_supported) | lenient |
HISTORY_ANALYSIS / TAINT_ANALYSIS / AST_ANALYSIS | false / true / true | analysis-layer switches |
DIFF_TOKEN_BUDGET / CONTEXT_CHAR_BUDGET | 14000 / 24000 | context budgeting |
RETRIEVAL_ENABLED / RETRIEVAL_TOP_K | true / 6 | RAG behaviour |
EMBEDDING_PROVIDER | auto | auto | openai | ollama | gemini | openai-compatible | local |
KNOWLEDGE_ENABLED / KNOWLEDGE_TOP_K | true / 4 | knowledgebase behaviour |
KNOWLEDGE_DIR | user config knowledge/ | JSONL knowledge store location |
KNOWLEDGE_MAX_CHARS | 1200 | hard cap on the $KNOWLEDGE$ block injected into a prompt |
KNOWLEDGE_AUTO_CAPTURE | false | persist verified findings as repo memory after each review |
ANALYSIS_MAX_TOKENS | 4096 | per-analysis-agent output cap (vs the global MAX_TOKENS) |
USE_PROMPT_CACHING | true | Anthropic cache_control on the shared system block (cost cut for parallel agents) |
AGGREGATOR_MAX_FINDINGS | 60 | cap on findings serialized into the aggregator prompt |
LLM_CACHE_ENABLED / LLM_CACHE_DIR | false / config cache/llm | content-addressed disk cache of structured LLM responses (repeat-review cost cut) |
GITHUB_TOKEN / GITHUB_REVIEW_PUBLISH | - / false | GitHub integration |
WORKFLOW_USE_RETRIEVAL / WORKFLOW_USE_VERIFIER / WORKFLOW_USE_*_AGENT / WORKFLOW_USE_DEAD_CODE_CHECKER | all true | ablation switches - disable individual categories |
BENCHMARK_DATASET / MAX_WORKERS | benchmarks/datasets/fixture_small.json / 4 | evaluation |
LOG_LEVEL / LOG_FORMAT | INFO / json | DEBUG | INFO | WARNING | ERROR; json | text |
| Symptom | Fix |
|---|---|
OPENAI_API_KEY is not set / ANTHROPIC_API_KEY / GEMINI_API_KEY | run acr get-started (or set the key in the environment), or switch LLM_PROVIDER to ollama / mock |
OPENAI_COMPATIBLE_BASE_URL is not set | this provider needs an explicit base URL - e.g. http://localhost:8000/v1 |
Unknown LLM_PROVIDER | use one of openai, anthropic, ollama, gemini, openai-compatible, mock (hyphen and underscore both work) |
| Ollama connection errors | is the Ollama server running? Check OLLAMA_BASE_URL (default http://localhost:11434) |
Gemini 403 on every call | the API key is invalid or lacks quota - Gemini reports bad keys as 403, not 401 |
review-local with mock finds nothing | expected - the mock is a test double that returns an empty finding set; use it to smoke-test the pipeline keyless, then switch to a real provider |
| TUI renders garbage | you're piping/redirecting output; the TUI needs a real terminal (logs go to a temp file automatically) |
@software{roy2026agenticcodereviewer,
author = {Roy, Sourav},
title = {Agentic Code Reviewer: Multi-Agent LLM Code Review with Layered Deterministic Verification},
year = {2026},
url = {https://github.com/royxforge/agentic-code-reviewer}
}
See CITATION.cff for the machine-readable citation metadata.
MIT - see LICENSE
Built by Sourav Roy · Artificial Intelligence Engineer · Accure Inc.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.3.0 | 21 Aug 2026 | 14 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 22:13 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:70de0778ea145b2106845e9bf5262e77bb27fb06b519d791ad2524d90db442df