Your PR is 4,000 lines long. Nobody wants to review it.
diffly reads it for you — files, symbols, checks, tests, blast radius —
and hands you one page and one verdict: PASS, QUARANTINE, or BLOCK.
Pick whichever fits your setup:
curl (recommended)
curl -fsSL https://raw.githubusercontent.com/VIVAAN-DHAWAN/diffly-cli/main/install.sh | shpip
pip install diffly-cliuv
uv tool install diffly-cliHomebrew
brew install VIVAAN-DHAWAN/diffly-cli/diffly-cliThat's it. If diffly isn't found, add ~/.local/bin to your PATH (curl/pip/uv) and open a new shell.
If you already have diffly installed but are on a version before 0.4.0 (which introduced the built-in update system), run the one-time upgrade script:
curl -fsSL https://raw.githubusercontent.com/VIVAAN-DHAWAN/diffly-cli/main/upgrade.sh | shThis pulls in 0.4.0+, which has diffly update built in. From that point on, diffly will automatically check for new releases every time you run it and prompt you to update — no more manual upgrades needed.
From 0.4.0 onwards, just run:
diffly updateOr simply start diffly normally — it will check for updates on launch and ask if you'd like to install the latest version. You can also choose to enable automatic updates so future versions install silently.
diffly pr https://github.com/astral-sh/ruff/pull/27808Paste any pull-request URL — or run bare diffly for a guided flow. You'll get a keyboard-driven, one-page review: verdict, risk flags, checks, and a per-file blast-radius map. Arrow keys move, space toggles sections, Enter renders, q quits.
Large AI-generated pull requests are hard to review because file-by-file diffs hide what matters: which symbols changed, which tests cover them, whether dependencies moved, whether a security-sensitive file was touched. diffly makes the deterministic part of that review visible before any LLM gets involved.
It fetches the PR metadata, changed files, unified diff, commits, status checks, and repository tree; parses source changes with Tree-sitter; maps the blast radius; applies fixed risk rules; and emits a one-page Markdown report with a verdict.
| One-page verdicts | PASS, QUARANTINE, or BLOCK from fixed, documented rules. Same PR data in, same verdict out — every time. |
| Blast-radius map | Per file: status, additions/deletions, touched symbols, direct callers visible in changed hunks, and related test files discovered from the repository tree. |
| Risk flags | Auth/secrets touches, database changes, new dependencies, missing test coverage, failed or pending checks — each with severity and evidence. |
| Works offline | diffly local triages git changes in any folder on disk — private, archived, or removed repositories included. |
| CI-native | Bundled GitHub Action posts one self-updating verdict comment on every PR. Stable JSON output for scripts. |
| Optional AI explainer | Bring your own OpenAI-compatible key for a generated narrative — sandboxed, redacted, strictly validated, and never allowed to change the verdict. |
Analyze git changes on your own disk. No token, no network:
diffly local # uncommitted working-tree changes in the current folder
diffly local ~/code/private-repo # any checkout — even repos deleted from GitHub
diffly local --base main # compare your branch against main insteadUntracked files are included, so brand-new work is never silently ignored. CI checks don't exist locally, so check-derived flags are skipped; everything else behaves exactly as it does for pull requests.
Add this to analyze every pull request automatically:
name: Diffly
on: pull_request
permissions:
contents: read
pull-requests: write
jobs:
diffly:
runs-on: ubuntu-latest
steps:
- uses: VIVAAN-DHAWAN/diffly-cli@mainTo enable the optional explainer in CI, add DIFFLY_LLM_API_KEY: ${{ secrets.DIFFLY_LLM_API_KEY }} under the step's env. Without a key, the Action runs deterministic-only.
diffly # guided wizard
diffly pr astral-sh/ruff 27808 # owner/repo + number
diffly pr https://github.com/astral-sh/ruff/pull/27808 # just paste the URL
diffly pr astral-sh/ruff 27808 --interactive # keyboard-driven review
diffly pr astral-sh/ruff 27808 --output triage.md
diffly pr astral-sh/ruff 27808 --json # stable JSON for scripts
diffly setup # guided tutorial
diffly doctor # environment diagnostics
diffly update # check for and install the latest releaseFor automation prefer --json: successful triage exits 0 regardless of verdict — enforce policy by reading the verdict field. Operational errors exit 2.
Every opted-in explanation is shown in the review. With an AI key, Diffly produces a bounded, redacted AI narrative; without one—or if the provider is unavailable—it creates a clearly labelled local explanation from deterministic review facts instead. Neither path can alter the verdict.
export DIFFLY_LLM_API_KEY="your-key"
export DIFFLY_LLM_BASE_URL="https://api.openai.com/v1" # omit for the default endpoint
diffly pr OWNER/REPO NUMBER --explainDefault model is gpt-5-mini; override with DIFFLY_LLM_MODEL or --llm-model. The explainer sends bounded, redacted context, requires strict JSON output, rejects citations to files outside the changed-file set, and fails safely back to deterministic triage when anything is off.
| Verdict | Rule |
|---|---|
| BLOCK | A required check failed, or production code appears to add a credential-like value. |
| QUARANTINE | Security-sensitive code, database schema/migrations, or newly added dependencies need focused review. Credential-like values limited to tests, fixtures, or docs also quarantine rather than block. |
| PASS | Healthy changes, ready to merge. Pending or unavailable checks, version-bump-only manifest edits, and missing obvious tests stay visible as review notes, not gates. SHIP remains accepted as a legacy alias. |
PASS is the normal healthy outcome. A verdict is a review signal, not a claim that a PR is correct or safe in every context.
Captured from live terminal sessions against public pull requests:
| Pull request | Files | Lines | Verdict | Why |
|---|---|---|---|---|
microsoft/vscode#330848 |
25 | +2,557 / -251 | QUARANTINE | production files without obvious test coverage |
kubernetes/kubernetes#141413 |
41 | +708 / -740 | QUARANTINE | missing coverage + pending tide check |
astral-sh/ruff#27808 |
53 | +1,845 / -274 | BLOCK | CodSpeed Performance Analysis check failed |
Standalone screenshots: vscode · kubernetes · ruff
Live AI-explainer reports (deterministic verdict preserved): ruff phase 2 · kubernetes phase 2
Tree-sitter parsing covers symbols and direct calls visible in changed hunks, not a full repository-wide call graph. Test-coverage detection is heuristic (filenames + repository tree), so it is presented as a review note rather than a verdict gate. AI model context is bounded and may truncate on very large PRs. A local explanation is used when AI generation is not available.
- repository-wide symbol resolution and import-aware blast radius;
- configurable policy files for org-specific risk rules and thresholds;
- GitHub annotations and check-run output alongside the PR comment;
- baseline mode reporting only risks introduced vs the target branch;
- coverage-artifact-based test mapping;
- SARIF output for code-scanning integrations.
Details: docs/phase-2-contract.md · docs/benchmarks.md
git clone https://github.com/VIVAAN-DHAWAN/diffly-cli.git
cd diffly-cli
python -m venv .venv
. .venv/bin/activate
python -m pip install -e '.[dev]'
pytest -qKeep changes focused, include regression tests, and record user-facing changes in CHANGELOG.md. See CONTRIBUTING.md.
Diffly talks to the GitHub API only for the repo and PR you point it at. Deterministic mode sends no code to any LLM. With --explain, bounded redacted context goes to your configured endpoint — read docs/phase-2-contract.md before enabling it on sensitive repositories. Prefer environment variables over command-line tokens.
Report vulnerabilities privately via GitHub security advisories.
Released under the MIT License.
