Skip to main content

Provider-agnostic PR reviewer — seven hosted providers, ollama, and any OpenAI-compatible endpoint, one flag, no keys in secrets for cloud.

Project description

lgtmaybe logo — a shrugging face with curly-brace arms

lgtmaybe

Provider-agnostic PR reviewer. Seven hosted providers, local ollama, and any OpenAI-compatible endpoint — one flag, no static keys for cloud providers. Posts inline review comments and a summary.

📖 Full documentation: https://mattjcoles.github.io/lgtmaybe/

What it reviews

lgtmaybe fetches the PR diff from the GitHub API and reviews the lines a pull request changes. It never checks out or runs your code. To judge each change in context it also reads a few surrounding lines from the file. It only ever comments on what the PR actually changed, not the whole repository.

Reviews surface the kind of thing a careful reviewer would flag, each graded from info up to critical:

  • Logic and correctness bugs — edge cases, null dereferences, off-by-one and boundary errors, mismatched ranges, unhandled error paths, races and TOCTOU, missed awaits, numeric and timezone bugs.
  • Security vulnerabilities — the model is prompted with an OWASP-aligned checklist: injection, XSS, CSRF and open redirects, hardcoded secrets, broken authn/authz (including JWT pitfalls), path traversal, unrestricted uploads, SSRF, insecure deserialization and XXE, mass assignment, weak crypto, resource/DoS safety (including ReDoS), secrets or PII (passwords, tokens, SSNs, card data) leaking into logs, and CI/IaC misconfiguration (workflow script injection, unpinned actions, broad IAM, public buckets). Security findings are first-class, not an afterthought.
  • Missing or weak tests for changed code paths, with a suggested test to drop in.
  • Undocumented public APIs or stale docs the change just made wrong.
  • Factually outdated code — deprecated APIs, end-of-life or vulnerable dependencies, typosquat-looking additions — when the diff shows them.
  • Performance regressions — N+1 queries, accidentally quadratic work, redundant computation, allocations or blocking I/O on hot paths, unbounded queries, caches that never evict.
  • Needless complexity — deep nesting / high cyclomatic complexity, over-long functions, duplicated logic.
  • Intent — does the PR do what it says? lgtmaybe reads the PR title, description, and commit names (or your git log commit names on the CLI) and flags out-of-scope hunks, code that contradicts the stated intent, and promised behaviour the diff never implements.
  • Ponytail — the "lazy senior dev" lens: the best code is the code you never wrote. Flags code that needn't exist at all — YAGNI, reach for the standard library, do it in fewer lines.

Generated and non-reviewable files (lockfiles, minified bundles, vendored directories, binaries) are skipped automatically, and secrets are redacted from the diff before it is sent to the model.

Hardened against malicious PRs. lgtmaybe never checks out or runs PR code, treats the diff as untrusted input, defends against prompt injection (including forged delimiter break-out attempts), and redacts a broad set of secret formats (cloud keys, GitHub/Slack/Google/Stripe tokens, private keys, passwords, and credentials in connection strings) before anything leaves your environment. See Data and Privacy.

Fast by default. Reviews run the fast preset by default: security, correctness (including stated intent), and code health (performance/complexity/ponytail/deprecation) run in three model calls. Tests and documentation are reserved for --preset full (or preset: full in .lgtmaybe.yml), which restores the one-call-per-lens deep audit for release branches. This keeps the everyday path focused on code defects while avoiding a low-yield call that can dominate wall time. On top of that, all calls across all batches share one concurrency pool (max_concurrency, default 8 on cloud providers) and share a cached preamble-plus-diff prefix on anthropic/bedrock, so the diff is processed once per batch, not once per lens. Add --profile to any run to see exactly where the time and tokens went.

How the scope is bounded. Every run is capped so a large PR can't blow up latency:

  • preset (default fast) — three focused/grouped calls; full restores tests and documentation and runs one call per lens.
  • max_files (default 50) — reviews the top-N changed files and notes how many were skipped.
  • max_input_tokens (default 100k) — batches the diff to fit the model's budget.
  • max_concurrency (default 8 cloud / 1 ollama and openai-compatible) — concurrent model calls across the whole fan-out.
  • recursive (default on) — when a single file's diff exceeds that budget, walks it hunk-by-hunk instead of sending it whole; --no-recursive sends files whole.
  • categories (default all nine) — which review lenses to run; an explicit list overrides the preset grouping and runs exactly those lenses, one call each.
  • min_severity (default low) plus include_paths / exclude_paths — focus the review on what you care about.

See Configure .lgtmaybe.yml for every knob.

Big files, small models. When one file's diff is too big for a single model call, lgtmaybe reviews it hunk-by-hunk rather than whole, so the model never loses the tail of a large file. On by default; --no-recursive turns it off. Smaller local models gain the most — across 8 runs on two fixtures, a local qwen3.5:4b averaged 88% recall reviewing hunk-by-hunk versus 61% reviewing files whole, with its worst run matching the whole-file method's best (a real effect, not noise), at ~2.4× the tokens. See the benchmark.

What you get back. Each finding is structured data — file, line, severity, a title, an explanation, and an optional suggested fix — so it renders the same everywhere:

  • On a GitHub PR — an inline comment on the exact changed line for each finding, plus one summary comment naming the model used. Re-running updates the same comments instead of duplicating them, auto-resolves a conversation once its finding is fixed, and a clean PR gets a 👍 LGTM!.
  • On the CLIlgtmaybe review reads your local git diff and prints the findings (a readable listing, a JSON array with --json, or --format agent for an AI coding agent to read and apply); nothing is posted to GitHub.

Beyond the review, slash commands on the PR route to the same engine: /review and /improve post (or refresh) the review, /ask <question> answers a question about the change in-thread, /describe (auto_describe) posts a structured description, and /diagram (auto_diagram) posts a C4-style change diagram — a Mermaid diagram of the components the PR touches, rendered natively in the comment, with an ASCII fallback that also prints from lgtmaybe diagram locally. See Generate a change diagram.

On re-runs and big PRs the review stays cheap: a synchronize push triggers an incremental review of just the new commits, an optional cheap triage model (triage_model) skips plainly-non-substantive files before the strong model runs, and optional static-analysis fusion (static_analysis) feeds ruff/bandit/semgrep hints into the review as untrusted context.

An inline lgtmaybe review comment on a GitHub pull request flagging a [CRITICAL] SQL injection vulnerability, with an explanation and a suggested parameterized-query fix

On a GitHub PR — an inline comment on the changed line. The same findings on the CLI:

The lgtmaybe review command running in a terminal, printing a finding with its file, line, severity, and a summary line naming the model

A fuller walkthrough with example output is in What gets reviewed.

Quick start (60 seconds, local, zero cost)

From inside a git repo, on a branch with changes, review your diff against the remote primary branch and print the findings:

pip install lgtmaybe        # or Homebrew — see docs/how-to/install-the-cli.md

lgtmaybe review \
  --provider ollama \
  --model qwen3.6:27b \
  --api-base http://localhost:11434

No GitHub token and no pull request needed — lgtmaybe review reads your local git diff and prints the findings. lgtmaybe help lists every command with usage examples; lgtmaybe help review shows the full option reference. To post reviews on real pull requests, wire up the GitHub Action. See Getting Started for the full walkthrough.

Picking a model: use a coding model, and bigger/newer is more accurate. Our benchmark numbers are for a small qwen3.5:4b; a larger, current coding model catches more. See Which model?.

Providers

Provider Auth Guide
openai OPENAI_API_KEY OpenAI
anthropic ANTHROPIC_API_KEY Claude
openrouter OPENROUTER_API_KEY OpenRouter
zai ZAI_API_KEY — GLM / Zhipu AI (glm-4.6, glm-4.7, glm-4.5-air, …; newer glm-5.x too). Optional --api-base for the China / coding-plan endpoint z.ai (GLM)
bedrock Ambient AWS creds — GitHub OIDC, no static key Bedrock
vertex Ambient GCP creds — Workload Identity Federation, no key Vertex
azure Ambient Azure AD creds — GitHub OIDC, no static key (or AZURE_API_KEY) + endpoint Azure
ollama None — local only, zero cost ollama
openai-compatible Any OpenAI /v1 endpoint via --api-base (DeepSeek, llama.cpp, LM Studio, vLLM). Key optional — --api-key / OPENAI_COMPATIBLE_API_KEY, or none for local servers Local & OpenAI-compatible

Documentation

Browse the rendered docs at https://mattjcoles.github.io/lgtmaybe/, or read the Markdown sources below. For LLM agents, a curated llms.txt index (and a whole-corpus llms-full.txt) are published at the docs root.

Tutorial — learn by doing

How-to guides — task recipes

Reference — look things up

Explanation — understand the design

  • What gets reviewed — scope, caps, and what the output looks like
  • Architecture — ports and adapters, the review pipeline
  • Auth Model — why keyless cloud, how credential resolution works
  • Data and Privacy — what is sent where, secret redaction, ollama local mode
  • Trust and Cost — choosing who reviews run for (everyone, trusted contributors, or admins) and the small cost angle

Use as a GitHub Action

GitHub Marketplace copies the Action syntax into a workflow; it does not choose an LLM service or model for you. In .github/workflows/lgtmaybe.yml, set provider, model, and the matching authentication input in the step's with: block. This complete example uses OpenAI:

name: lgtmaybe

on:
  pull_request_target:
  issue_comment:
    types: [created]

permissions:
  contents: read
  pull-requests: write

jobs:
  review:
    if: ${{ github.event_name == 'pull_request_target' || github.event.issue.pull_request }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: MattJColes/lgtmaybe@v1
        with:
          provider: openai
          model: gpt-5.5
          api_key: ${{ secrets.OPENAI_API_KEY }}

Using another platform? Copy-paste workflows for every cloud and API-key provider live in examples/workflows/. Cloud providers (Bedrock, Vertex, Azure) are keyless — pass aws_role_arn / gcp_wif_provider / azure_client_id and the action does the OIDC/WIF exchange for you (needs id-token: write). See Use as a GitHub Action. ollama is local only — run it through the CLI instead.

🔧 Choose who can trigger reviews. You decide who reviews run for — everyone, trusted contributors, or just admins. The example workflows default to trusted contributors (OWNER, MEMBER, COLLABORATOR), and it's a one-line change to open it up or tighten it. With ollama this is free; on a hosted provider it also keeps token spend predictable. See Who can trigger a review and Trust and Cost.

Distribution

  • CLI (PyPI)pip install lgtmaybe
  • CLI (Homebrew)brew tap MattJColes/lgtmaybe && brew trust MattJColes/lgtmaybe && brew install lgtmaybe (details — the brew trust step is required for third-party taps)
  • GitHub Actionuses: MattJColes/lgtmaybe@v1

Contributing

Test-first, green CI, scope is the gate. See CONTRIBUTING.md.

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lgtmaybe-1.1.0.tar.gz (2.6 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lgtmaybe-1.1.0-py3-none-any.whl (171.7 kB view details)

Uploaded Python 3

File details

Details for the file lgtmaybe-1.1.0.tar.gz.

File metadata

  • Download URL: lgtmaybe-1.1.0.tar.gz
  • Upload date:
  • Size: 2.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for lgtmaybe-1.1.0.tar.gz
Algorithm Hash digest
SHA256 447e6c19583ac6d646c66496ed962ffc1d4a6caae3a105561e49bb87554b0265
MD5 201cfacfbc1957538745191d912f0fdb
BLAKE2b-256 3815ec65d56e7c8cde5230696169426bfc7a98610ff0e76daa2d3a706ece9f80

See more details on using hashes here.

Provenance

The following attestation bundles were made for lgtmaybe-1.1.0.tar.gz:

Publisher: release-please.yml on MattJColes/lgtmaybe

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lgtmaybe-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: lgtmaybe-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 171.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for lgtmaybe-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7b8248af430776c0e6e222dc9bc2d396f8730843fbaac7c1f254d6ef078df4c0
MD5 682c1fe62f9b0572fc58442ffa7565ef
BLAKE2b-256 cb01c1c130b885ba00e0c7f10d45e48a07f827de633d259d75ff4d3b4e312cf2

See more details on using hashes here.

Provenance

The following attestation bundles were made for lgtmaybe-1.1.0-py3-none-any.whl:

Publisher: release-please.yml on MattJColes/lgtmaybe

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page