local-review

module
v0.10.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 25, 2026 License: MIT

README

local-review logo

local-review

Local, BYOK code review for any language.
Runs against a git diff, hands it to whichever LLM you point it at, prints findings.
No SaaS, no telemetry, no signup.

Release License Stars

WhyHow good is it?Get startedChecklistCustomiseWebsite


Why local-review

Reviewer tools today are mostly SaaS (your code leaves the building), CI-only (you find out about issues after pushing), vendor-locked (OpenAI-only or Anthropic-only), and runtime-heavy (Node/Python install required). local-review is the opposite: a single static binary that runs locally on a diff, sends that diff to whichever LLM(s) you've authenticated, and prints findings. Privacy posture depends on which LLM(s) you point it at — see Privacy below. Run with Ollama for fully-offline review.

What it is, what it isn't

✅ What it is ❌ What it isn't
A local CLI that reviews a git diff using LLMs you've already authenticated A replacement for Claude's /review or /simplify — those are single-prompt commands; this is multi-LLM diff orchestration
An orchestrator that runs Claude / Gemini / Codex CLIs in parallel and merges findings into one report "Code never leaves your machine" — the diff still goes to whichever LLM you authenticate (run Ollama for true offline)
BYOK — your API key, requests go direct to the vendor (no middleman server) A SaaS — no hosted dashboard, no account, no team collaboration features
A pre-commit gate — exits non-zero on major / critical findings so hooks can block the commit A linter or static analyzer — it's LLM-based, with the heuristic tradeoffs that implies
A single Go binary — no Node, no Python, no Docker, no telemetry A chat interface — reads a diff, prints findings, exits
Reads auth state from local files only (~/.claude/sessions/, env vars, etc.) to detect login readiness — never transmits credentials A keychain scraper or credential-exfil tool — auth files are read locally, never sent anywhere

How good is it?

The honest answer to "should I trust this tool?" lives in bench/RESULTS.md — a committed leaderboard, regenerated and refreshed before each release. It tracks, on a labelled 10-case dataset spanning Go / TS / Python / Rust:

  • Quality. Precision, recall, F1, and noise-rate-on-clean-diffs per LLM.
  • Uplift over a raw-LLM baseline. Same case, same model, generic prompt vs. the full local-review pipeline. Answers: "is the tool actually better than typing the diff into Claude.app cold?"
  • Overhead vs the raw-LLM baseline. Extra seconds + extra tokens per review that the tool costs you on top of the raw model. So you can decide whether the quality uplift is worth the spend.
  • Consistency. Jaccard agreement across repeated runs of the same case — how stable the verdict is.
  • Per-language splits. Tightening the Go pack shouldn't be averaged away by the TS scores; the leaderboard keeps them separated.

No marketing numbers in this README — they'd go stale. Read bench/RESULTS.md for the current state, and bench/README.md for the methodology.

Deep-codebase audit dogfood. v0.10.0 added a second trust artifact: audit/local-review audit --topic <security|tech-debt> run against this repo's own committed source tree, output committed. Same shape as bench/RESULTS.md (raw output preserved so you can read it before adopting), but answers a different question: what does diff-time review miss? See audit/README.md for methodology, audit/security.md and audit/tech-debt.md for the latest runs.


Get started

1. Install. Single binary, no Node/Python/Docker:

brew install mshykov/tap/local-review

Or

curl -fsSL https://raw.githubusercontent.com/mshykov/local-review/main/install.sh | sh

Or

go install github.com/mshykov/local-review/cmd/local-review@latest

Or grab a binary from Releases.

2. Authenticate at least one LLM. Claude is the easiest free option:

npm install -g @anthropic-ai/claude-code
claude login

Or use Gemini (free key) or Codex (ChatGPT Plus / OpenAI API). Any combination works — every authenticated LLM joins the review automatically. local-review doctor shows the state.

3. (Optional) Add a .local-review.yml to your repo for house rules:

# .local-review.yml — every field is optional
prompts:
  prepend: |
    Additional house rules:
    - Never approve commented-out code.
    - Flag any new dependency in package.json or go.mod.
review:
  min_severity: warning   # nit | info | warning | major | critical

You can ship the whole pack of overrides this way — see Customise for your team below.

4. Review your current branch vs main:

local-review review

Findings print to your terminal. The tool exits non-zero on major / critical, so it slots straight into a pre-commit hook.

5. (Optional) Check how the LLMs score on a labelled benchmark. The repo ships with bench/RESULTS.md — a leaderboard (precision / recall / F1 / noise, plus uplift-over-raw-LLM and overhead-vs-raw-LLM tables) generated from a 10-case dataset spanning Go / TS / Python / Rust. Refreshed before each release; you don't need to run anything locally. See bench/README.md for methodology.


Just want the checklist?

Every check local-review applies is published as a human-readable CHECKLIST.md — OWASP-2025-aligned, with severity tiers and concrete measurables. Paste it into your team wiki, run reviews manually against it, or use local-review review to get an LLM pass against the same rules. Either path; both work.

Customise for your team

Three knobs in .local-review.yml let you tune review tone, severity bar, or add house rules — without forking the binary:

prompts:
  pack_dir: .local-review/prompts   # per-language overrides; <language>.md replaces the embedded pack
  prepend: |                        # spliced before every pack body
    Additional house rules: ...
  append: |                         # spliced after every pack body
    Output language: English only.

All three apply to both the multi-LLM CLI path and the single-LLM fallback so customizations reach every reviewer. --prompt-pack-dir <dir> overrides for one-off runs. Full details in Customise the review prompt below.


What's new in v0.9. Make the tool sell itself. Three things driven by direct customer feedback on v0.8:

  • Overhead deltas in the leaderboard. bench/RESULTS.md now carries an "Overhead vs raw model" table next to the existing uplift block — extra seconds and extra tokens the tool costs you per review, with signed deltas vs. the raw-LLM baseline. The trade-off ("quality wins vs. cost") now reads on one page.
  • README leads with positioning, not commands. Why it exists / what it is / how good it is — then install. The action-first ordering shipped in v0.8 buried the trust signal under copy-pasteable shell blocks.
  • bench is internal now. The harness still exists; the subcommand is hidden from --help and isn't a user surface. The committed bench/RESULTS.md is the user-facing artifact, refreshed before each release.

Full notes in CHANGELOG.


Multi-LLM is the default

Every authenticated LLM CLI runs by default. No opt-in, no enabling — if you claude login, claude runs. If you export OPENAI_API_KEY=..., codex runs. If you don't authenticate one, it's silently skipped.

# Default: all active LLMs
local-review review

# Restrict to a subset (overrides config)
local-review review --only claude,gemini

# Pick a specific model for one agent
local-review review --claude-model claude-opus-4-7

# Use a specific agent to do the merge
local-review review --merge-with claude

Supported LLMs

LLM Free Option Installation
Claude ✅ Free tier via claude login (claude.ai account) npm install -g @anthropic-ai/claude-code
Gemini ✅ Free API key from Google AI Studio npm install -g @google/gemini-cli
Codex ⚠️ ChatGPT Plus ($20/mo) or OpenAI API key (pay-per-token) npm install -g @openai/codex

How it works:

  1. Detects installed LLM CLIs and which are authenticated (local-review doctor)
  2. Runs every authenticated CLI in parallel
  3. Saves each review to .local-review/reviews/<branch>/<commit>_<llm>_<version>.md
  4. Merges findings (dedup, consensus tagging) into one report
  5. Prints the merged report to stdout (also saved as <commit>_merged.md)

Authentication — what each LLM needs:

LLM Default (preferred) Alternative
Claude claude login — Anthropic OAuth, works with the free tier on a claude.ai account export ANTHROPIC_API_KEY=... (paid API access)
Gemini export GEMINI_API_KEY=... — free key from Google AI Studio gemini /auth for Google OAuth
Codex codex login — uses your ChatGPT Plus subscription ($20/mo) export OPENAI_API_KEY=... — pay-per-token; usually cheaper for occasional review use

Run local-review doctor to see which CLIs you have installed and authenticated. Each row that isn't ✓ ready tells you exactly what to fix.

Configuration is optional. If ~/.local-review.yml or ./.local-review.yml exists it overrides defaults; CLI flags override config:

# .local-review.yml — example: pin specific models, disable codex
llms:
  claude:
    model: claude-opus-4-7

  gemini:
    model: gemini-2.0-flash
    api_key_env: GEMINI_API_KEY

  codex:
    enabled: false           # opt-out (still runs if --only codex is passed)

merge:
  preferred_llm: auto        # or: claude, gemini, codex

See examples/.local-review-multi.yml for full schema.

Configure

local-review loads YAML from a cascade — built-in defaults → ~/.local-review.yml./.local-review.yml → CLI flags.

A minimal ~/.local-review.yml:

provider:
  base_url: https://api.openai.com/v1
  model: gpt-4o-mini
  api_key_env: LOCAL_REVIEW_API_KEY
review:
  min_severity: warning
  max_findings: 20

See examples/.local-review.yml for the full schema with comments.

Switching providers

local-review speaks the OpenAI chat-completions API — every major provider supports it:

Provider base_url Notes
OpenAI https://api.openai.com/v1 Default. gpt-4o-mini is cheap; gpt-4o for harder reviews.
Anthropic https://api.anthropic.com/v1 Anthropic's OpenAI-compatible endpoint. Use exact model names (e.g. claude-sonnet-4-6, claude-opus-4-7).
Mistral https://api.mistral.ai/v1 EU-hosted; Codestral is code-tuned. See examples/.local-review.mistral.yml.
DeepSeek https://api.deepseek.com/v1 Cheapest cloud option. See examples/.local-review.deepseek.yml.
Groq https://api.groq.com/openai/v1 Fast inference; Llama, Qwen, etc.
Together https://api.together.xyz/v1 Llama, Mixtral, Qwen — many open-weights options.
OpenRouter https://openrouter.ai/api/v1 One key, all models.
Ollama http://localhost:11434/v1 Fully offline. No data leaves your machine.
Ollama on a LAN host http://192.168.1.50:11434/v1 (or any RFC1918 IP) Stays on your network. Same as local Ollama for one machine, but with the model server on a separate box (typically a GPU host). Set OLLAMA_HOST=0.0.0.0:11434 on the server so it accepts connections beyond loopback. local-review treats RFC1918 / link-local / IPv6 ULA hosts as auth-free by default (see isLocalURL); set provider.api_key explicitly if your LAN gateway DOES authenticate.
vLLM http://your-host/v1 Self-hosted.

The fastest way to set any of these up is local-review init, which writes a working .local-review.yml from a preset.

Pre-commit hook

cp examples/pre-commit .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit

Or with husky / lefthook: run local-review staged in the pre-commit step.

Bypass for emergencies: LOCAL_REVIEW_SKIP=1 git commit ....

CLI

# Review (multi-LLM by default; falls back to single-LLM via configured provider if no CLI is active)
local-review review [<base>]         # canonical: current branch vs <base> (default: main)
local-review staged                  # review git diff --cached (pre-commit)
local-review commit [<rev>]          # review one commit (default: HEAD)
local-review branch [<base>]         # alias of `review` for muscle-memory

# Utilities
local-review init                    # interactive setup (writes .local-review.yml)
local-review doctor                  # check LLM installations + auth state
local-review config                  # print resolved config (API keys masked)
local-review version                 # print version

Common flags:

Flag Purpose
--only <list> Comma-separated agents to run (e.g. claude,gemini); overrides config
--claude-model <id> Override claude's model (same for --gemini-model, --codex-model)
--merge-with <agent> Pick which agent merges findings (default: auto)
--model <id> Override provider.model (single-LLM fallback only)
--base-url <url> Override provider.base_url (single-LLM fallback only)
--min-severity <tier> nit / info / warning / major / critical (single-LLM fallback only)
--max-findings <n> Cap output (single-LLM fallback only)
--json Emit JSON (single-LLM fallback only — see below)

In multi-LLM mode the merger returns markdown, not structured findings, so --json, --min-severity, and --max-findings are ignored: they only take effect in the single-LLM fallback path (when no LLM CLI is authenticated and we hit the configured provider: directly). Multi-LLM emits a stderr warning when those flags are passed so you know they had no effect. A structured-JSON multi-LLM output mode (where the merger emits both markdown and a JSON envelope) is on the post-v0.8 roadmap — no fixed date; we'll unpark it when the third user asks for it.

Config wins by default; flags override config at runtime (e.g., --only codex runs codex even if your config sets codex.enabled: false).

Exit codes:

  • 0 — no blocking findings
  • 2major or critical findings present (pre-commit gate)
  • non-zero — local-review itself failed (the hook ignores this and lets the commit through)

Prompt packs

local-review ships with packs for default, typescript, go, python, rust, swift, kotlin, and liquid, with more coming. The CLI auto-picks based on the dominant language in your diff. Force a specific pack with review.prompt_pack: <id> in your YAML config.

Each pack is a markdown file (in internal/prompts/packs/) that defines:

  • What to look for (priority-ordered)
  • Severity tiering rules
  • Hard rules ("never invent code that isn't in the diff")
  • Output JSON schema

See docs/prompt-packs.md for how to write or override one.

Customise the review prompt (v0.8+)

Different teams have different opinions about what's a "warning" vs a "nit." Forking the binary to change the bundled packs is a heavy hammer. Three lighter knobs in .local-review.yml:

prompts:
  # 1. Per-language override directory. A `<language>.md` file here
  #    replaces the embedded pack of the same name. Missing files
  #    fall through to the embedded pack — partial overrides are
  #    fine.
  pack_dir: .local-review/prompts

  # 2. Inline rules spliced BEFORE every pack body. Use for house
  #    rules that should colour the entire review.
  prepend: |
    Additional house rules:
    - Never approve commented-out code.
    - Flag any new dependency in package.json or go.mod.

  # 3. Inline rules spliced AFTER every pack body. Use for output-
  #    shape rules the LLM should see last.
  append: |
    Output language: English only.

All three apply to the multi-LLM path AND the single-LLM fallback, so a team's customizations reach every reviewer (claude, gemini, codex).

For one-off runs, --prompt-pack-dir <dir> overrides prompts.pack_dir for a single review without touching the YAML.

local-review config shows where each language's prompt actually came from:

# Resolved prompt sources:
#   default      embedded
#   go           /Users/me/repo/.local-review/prompts/go.md
#   python       embedded+prepend
#   rust         embedded
#   typescript   embedded

local-review doctor actively probes the prompt configuration and warns on every misconfiguration the resolver tolerates silently: missing pack_dir, pack_dir pointing at a file (not a directory), pack_dir with no <language>.md files matching a shipped pack, or known-language override files that exist but aren't readable. The resolver itself stays fall-through-on-error so a transient FS glitch can't kill every review; doctor surfaces the same conditions once at setup-check time.

What it does NOT do (yet)

  • No multi-file refactor reasoning. local-review reviews diffs, not architectures.
  • No auto-fix / auto-PR. Findings are advisory.
  • No GitHub integration in the binary. The --json output is structured for piping into your CI's PR-comment tool of choice. A native local-review github mode is parked — open an issue if you need it.
  • No telemetry. None. Ever.

On the roadmap

These are queued and will land in priority order; ping the issue tracker if you want to influence the sequence.

  1. Org-config fetching (near-term) — an org: block in your .local-review.yml (with a config_url: field) will fetch + cache an org-wide policy YAML, so a team can ship a single repo-local config that pulls org defaults from a central URL. Example shape:
    org:
      config_url: https://your-internal-host/local-review.yml
    
  2. Structured JSON multi-LLM output — the merger will emit markdown plus a JSON envelope so CI integrations don't have to text-scrape. Demand-pull: open an issue if you need it.
  3. Cosign release signinginstall.sh already verifies SHA-256 checksums (defense against accidental corruption + basic tampering). Cosign signatures will add stronger supply-chain provenance: every release tarball signed via keyless OIDC at build time, verified by the installer against the GitHub Actions identity. Useful for enterprise installs that need to prove an artifact came from this repo's release pipeline and wasn't swapped at the channel/CDN layer.

For organizations

Distributing to a few hundred engineers? Two patterns work:

  1. Org config repo. Drop a .local-review.yml in each project that sets:
    org:
      config_url: https://your-internal-host/local-review.yml
    
    (Org-config fetching is the next planned feature — see "On the roadmap" above; today, just commit the YAML to each repo.)
  2. One install command in onboarding. curl -fsSL <install.sh> | sh plus an env var = done.

Privacy

local-review is telemetry-free: no analytics, no auto-update calls, no signup, no SaaS. The only network traffic is to the LLM endpoint(s) you configure — either an HTTP call from local-review's built-in client (single-LLM mode) or the authenticated CLI subprocesses (multi-LLM mode). What "private" means therefore depends on which LLM(s) you point it at:

Mode Where your diff goes
Single-LLM, provider.base_url: http://localhost:11434/v1 (Ollama) Stays on your machine. Fully offline.
Single-LLM, any cloud provider (OpenAI, Anthropic, Mistral, etc.) The provider you configured, over TLS. Their privacy policy applies.
Multi-LLM (default) — Claude / Gemini / Codex CLIs Each authenticated CLI calls its own backend (Anthropic, Google AI, OpenAI). One review fans out to multiple cloud vendors. Your provider.base_url is irrelevant in this mode.
Multi-LLM with --only restricted to a fully-local agent Roadmap. Will be possible once a fully-local-agent preset lands; today every multi-LLM agent (claude / gemini / codex) calls its own cloud backend.

If you need air-gapped review today, use single-LLM mode against a local Ollama and stay off local-review review (which fans out to authenticated cloud CLIs by default).

Develop

go test ./...
go build -o local-review ./cmd/local-review
./local-review staged

See CONTRIBUTING.md.

License

MIT. See LICENSE.

Directories

Path Synopsis
cmd
local-review command
local-review: a local, BYOK code reviewer that runs against a git diff.
local-review: a local, BYOK code reviewer that runs against a git diff.
internal
audit
Package audit implements the `local-review audit` subcommand — the deep-analysis mode introduced in v0.10.0-c.
Package audit implements the `local-review audit` subcommand — the deep-analysis mode introduced in v0.10.0-c.
bench
SWE-bench-lite adapter for the local-review bench harness.
SWE-bench-lite adapter for the local-review bench harness.
cli
Package cli handles detection, invocation, and version extraction for LLM CLI tools.
Package cli handles detection, invocation, and version extraction for LLM CLI tools.
config
Package config loads the cascading YAML config that drives local-review.
Package config loads the cascading YAML config that drives local-review.
git
Package git wraps the user's local `git` CLI for diff extraction.
Package git wraps the user's local `git` CLI for diff extraction.
lang
Package lang maps file paths to a language identifier used to pick the right prompt pack.
Package lang maps file paths to a language identifier used to pick the right prompt pack.
llm
Package llm is a minimal HTTP client for the OpenAI chat-completions API.
Package llm is a minimal HTTP client for the OpenAI chat-completions API.
multi
Package multi handles multi-LLM orchestration, storage, and merging.
Package multi handles multi-LLM orchestration, storage, and merging.
output
Package output renders a Report into terminal-friendly text or JSON.
Package output renders a Report into terminal-friendly text or JSON.
prompts
Package prompts ships the review prompt packs as embedded markdown.
Package prompts ships the review prompt packs as embedded markdown.
review
Package review owns the orchestration: takes a diff, runs it through the LLM with the right prompt pack, and returns structured findings.
Package review owns the orchestration: takes a diff, runs it through the LLM with the right prompt pack, and returns structured findings.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL