pryti-semantic-reviewer

See what a pull request actually changes — no LLM required

Git tells you what lines changed. Pryti tells you what they mean — and points you at the exact line to read.

A deterministic semantic PR reviewer for Python web apps. No AI black box, no API key, no per-PR token bill — same PR in, same review out, every time.

No LLM No API key $0 per PR Deterministic Runs offline
pip install pryti-semantic-reviewer
★ Star on GitHub · · by Ankush Singh Gandhi · warriorwhocodes.com
The problem

A single PR can be 60 files and 18,000 lines

A normal line-diff buries the one change that matters — "user email now leaves the server" — under thousands of mechanical edits. You don't need to read all of it. You need to know what changed in behavior, how it flows, where to look, and whether it broke a promise.

$ pryti review . --pr 481   →   🔴 3   🟠 4   🟡 4   🟢 20
# 17,841 lines changed → 3 things to actually look at

🔴 NEW ENDPOINT  /api/companions/payment
   why: new endpoint exposes a PII path with open/unspecified auth
   flow: /api/companions/payment → CompanionPayment → {Order:write} → ext: PayTM
   investigate: payment_views.py:90  email → requests.post @ services.py:9

🟠 CHANGED       /api/orders/invoice
   why: new external call: razorpay.post  ·  money path

🟢 REFACTOR      /api/users/profile
   handler renamed, semantics unchanged — nothing to see
See it

What changed → how it flows → where to look

A ranked list, an interactive flow graph for every change, and the exact file:line locations — in the terminal, a web UI, a PR comment, or your Security tab.

A finished Pryti review in the web UI
Why Pryti

Why not just read the diff?

Because on an 18,000-line PR you can't — and the usual alternatives either guess, or miss what actually matters.

🎯

Facts, not vibes

It reads your code with Python's own parser and reports what's there — it never runs it, and never guesses. Every finding traces to a file:line, so there's nothing to fact-check.

🤫

Honest about the unknown

A tool that wrongly says "all clear" ships the bug. Pryti fails toward look here — ✓ / ⚠ / ? — and never renders "didn't see it" as "it's safe."

🔁

Refactor-proof

Facts are matched on the URL route, not class names. Rename every class in the repo and a pure refactor produces zero noise — so the real change stands out.

🔒

Your rules, enforced

It learns the promises your codebase already keeps and flags the PR that breaks one. That confirmed corpus is yours — the piece a competitor can't clone.

Read the diffAI reviewersStatic scannersPryti
Survives an 18k-line PR~~
No hallucinations
Honest about what it can't tell~
Refactor-stable (renames = no noise)
Learns your team's own rules
Zero config, zero dependencies~

It doesn't replace your tests or type-checker — it sees a different layer: behavior at the endpoint, and whether a change broke a promise.

The lens

Six things it reads for every endpoint

It reads your code with Python's own parser — it never runs it — and reports facts, not guesses.

route → handlerwhich URL maps to which view?
authdoes it require a login / permission?
db tableswhich tables does it read and write?
external callsdoes it call another service (payment, email, …)?
asyncdoes it kick off a background job / thread / signal?
PIIdoes personal data travel toward something that leaves the app?
✓ verified — saw it clearly ⚠ potential — one hop away / behind config ? unknown — couldn't tell

It will never say "no PII leaves here" when it just didn't see it. Absence is shown as unknown, never as safe.

Run it your way

Terminal, a web UI, or on every PR

Same facts, three surfaces — pick whatever fits your workflow.

⌨️

CLI

pryti review — a ranked review right in your terminal or CI logs.

🖥️

Web UI

pryti serve — an interactive flow graph and where-to-look, in your browser.

🤖

GitHub Action

A sticky comment, inline notes, and an optional merge gate on every pull request.

The Pryti web UI
The moat

It learns the rules your code already follows

A property your codebase kept for 800 commits was almost certainly on purpose. Pryti mines your git history, surfaces those rules, you confirm the real ones — and then every PR that breaks one gets flagged, with the exact commit that broke it.

Pryti invariants: discover, confirm, and blame rules
More

Built to be trusted

🩸

Traced PII leaks

The exact field → the exact line where it leaves. Traced, not guessed.

📦

Dependency powers

Flags a bumped package that newly gains network / subprocess / native code.

🎭

Intent vs. behavior

PR says "just a refactor" but added an endpoint? Caught — from facts, not an LLM.

💬

Inline PR comments

Each finding pinned to the exact changed line, plus a sticky summary and a triage label.

🛡️

SARIF + gating

Findings in the Security tab, and an optional merge gate on a broken rule.

📊

Org roll-up

pryti digest counts the open risky PRs across every repo — one number for leadership.

Questions

The honest answers

Won't it be noisy?

No — it's a diff. It only speaks up about what a PR actually changed, and it labels anything uncertain "look here," never "safe." Roll it out in observe mode and you'll see the signal before it can ever block a merge.

Does it need setup or config?

Nothing. It's a pure-Python-standard-library package with zero third-party dependencies. Point it at a repo (local path or GitHub URL) and go — no config file, no server, no account.

Will it hallucinate like an AI reviewer?

No. There's no LLM in the analysis — so there's nothing to hallucinate, no API key to wire up, and no per-PR token bill. It reads your code with Python's parser and reports facts; every finding traces to an exact file:line, and the same PR always produces the same review. That's the whole point: LLM reviewers are smart but drift and cost tokens; Pryti is deterministic and free.

Does it run my code?

Never. It reads code statically and analyzes clean git snapshots (via git archive) in a temp folder — it doesn't execute anything or touch your working tree. Safe to point at any repo.

What about repos that aren't Django / DRF?

Its lens is endpoint-centric (Django & Django REST Framework today). On a repo it can't read, it simply finds nothing to report — it won't invent false alarms. More frameworks (FastAPI, …) are on the roadmap.

Do I need GitHub Advanced Security?

No. The review, PR comments, labels, gating, and the org roll-up all work without it. GHAS only powers the optional SARIF Security-tab dashboard.

Is it free?

Yes — under the Elastic License 2.0: free to use, self-host, and modify. You just can't resell it as a hosted service.

Get started in 30 seconds

Three commands, zero setup

Needs Python 3.8+, plus git and tar. That's the whole install.

1

Install it

pip install pryti-semantic-reviewer
2

Review a pull request

pryti review https://github.com/owner/repo --pr 481
3

Or explore it in your browser

cd your-repo && pryti serve