Skip to main content

Classify PR diffs by reviewer attention: review, skim, or skip

Project description

garbelour

Classify every hunk in a git diff (or a GitHub pull request) by how much reviewer attention it deserves: review, skim, or skip.

What it does

Garbelour walks the diff between two git refs, runs each hunk through a pipeline of deterministic classifiers, and (optionally) sends whatever the heuristics didn't classify to an LLM for enrichment. The output is a single report in one of three formats:

  • human (terminal): grouped by level, color-coded, with file:line pointers to the lines that matter.
  • markdown (GitHub sticky comment): collapsible Skim/Skip sections and deep links to the exact lines of each Review item.
  • json (machine-readable): one record per classified hunk plus a summary; suitable for piping into other tools.

The format defaults to auto: markdown when posting to GitHub, human in a TTY, json otherwise.

Built-in classifiers

Classifier Level What it catches
generated Skip Files matching globs (*.lock, dist/**, *.min.js, …) or .gitattributes linguist-generated
lockfile Skip Cargo.lock, package-lock.json, yarn.lock, pnpm-lock.yaml, go.sum, …
comment_only Skip Hunks where every changed line is inside a comment / docstring node
import_reorder Skip Same set of imports, different order
public_api Review pub items in Rust, export in TS/JS, module-level def/class in Python
control_flow Review Added / removed / modified if, match/switch, for, while, loop, return
numerical_calc Review Non-trivial arithmetic (≥ 2 operators) or calls into Math.* / np.* / f64::* / …
error_handling Review Removed ?, try/except, try/catch, except clauses

AST-based classifiers use tree-sitter for Rust, Python, TypeScript, and JavaScript. Files in unsupported languages still go through the path-based classifiers (generated, lockfile).

Large hunks aren't auto-elevated. Size alone is a weak signal; instead, big hunks that no other heuristic claims flow through --llm for a content-aware verdict, or fall back to review when the LLM is off.

Install

To install the CLI via Python pip:

pip install garbelour

To instsall the CLI via Rust cargo:

cargo install garbelour

Usage

Locally, against any two refs

garbelour review --base main

Pretty terminal output by default. Pipe to jq to get JSON instead:

garbelour review --base main | jq '.summary'

Force a specific format:

garbelour review --base main --format markdown
garbelour review --base main --format json

Force color on through a pager:

garbelour review --base main --color always | less -R

In a GitHub Action

Garbelour reads the PR event payload from GITHUB_EVENT_PATH and posts a single sticky comment, updating it on each push.

# .github/workflows/garbelour.yml
on:
  pull_request:
    types: [opened, synchronize, reopened]
permissions:
  contents: read
  pull-requests: write
jobs:
  review-map:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-python@v5
        with:
          python-version: '3.14'
      - run: pip install garbelour
      - run: garbelour review --post-comment --llm
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

fetch-depth: 0 matters — git diff needs both base and head refs in the local repo.

LLM triage (optional)

--llm sends hunks no heuristic claimed to an LLM, which assigns each a level (review/skim/skip), a focus line range, and a one-line rationale.

The provider is auto-detected from whichever API-key env var is present:

Env var Provider Default model
ANTHROPIC_API_KEY Anthropic claude-haiku-4-5
OPENAI_API_KEY OpenAI gpt-4o-mini
OLLAMA_API_KEY Ollama llama3.2

Override with --llm-provider, --llm-model, or --llm-base-url.

Without --llm, hunks no heuristic claimed default to review — the safe option, since the tool hasn't actually evaluated them.

Configuration

garbelour.toml at the repository root is loaded automatically. All fields are optional.

[classify]
generated_globs = ["generated/**", "*.auto.ts"]   # merged with defaults
lockfile_names = ["shrinkwrap.json"]              # merged with defaults

[llm]
provider = "anthropic"
model = "claude-haiku-4-5"

[github]
base_url = "https://github.example.com/api/v3"     # GitHub Enterprise

CLI flags override config; config overrides built-in defaults.

.gitattributes is also consulted: any path marked linguist-generated (or linguist-generated=true) is treated as generated. Glob patterns in .gitattributes are not interpreted — fall back to [classify].generated_globs for those.

Output examples

Human:

garbelour: 3 of 47 hunks need review, 5 worth skimming, 39 mechanical
  Review (3)
    src/engine.rs:145–148    public fn signature changed
    src/engine.rs:201–208    new branch in retry loop
    src/store.rs:88–95 (old) removed try/except block
  Skim (5)
    …
  Skip (39)
    generated (15)        proto/*.pb.go, dist/bundle.js, ...
    lockfile (1)          Cargo.lock
    comment-only (3)      src/engine.rs, src/store.rs, README.md
    import-reorder (8)    src/engine.rs, src/store.rs, ...
    test-fixture (12)     tests/fixtures/*.snap

JSON:

{
  "base_sha": "...",
  "head_sha": "...",
  "hunks": [
    {
      "hunk_id": "src/engine.rs:142",
      "file": "src/engine.rs",
      "line": 142,
      "level": "review",
      "category": "public_api_change",
      "rationale": "public fn signature changed at lines 145–148",
      "focus_lines": { "start": 145, "end": 148, "side": "new" },
      "source": { "heuristic": { "name": "public_api" } }
    }
  ],
  "summary": { "total": 47, "review": 3, "skim": 5, "skip": 39 }
}

Library use

Garbelour is dual-target: a garbelour binary and a garbelour library crate. The pipeline, classifiers, and renderers are public API.

use garbelour::{diff, classify::{Pipeline, PipelineConfig}};

let mut d = diff::extract(std::path::Path::new("."), "main", "HEAD")?;
let pipeline = Pipeline::standard(&PipelineConfig::default())?;
let (classified, unclassified) = pipeline.run(&mut d);

Design notes

  • One subprocess to git diff --raw -z -M -C for file statuses (rename detection), one to git diff -U3 -M -C for hunks (parsed via the patch crate). File content for AST classifiers is loaded lazily via git show.
  • Heuristics emit only Skip or Review. Skim requires positive evidence — currently only the LLM emits it.
  • focus_lines pinpoints the specific line range that triggered each classification, so the markdown deep link lands on the right line, not just the start of the hunk.

What is New in Garbelour

0.3.0

Improved classifier prompt.

Added new classifier for numerical calculations.

0.2.0

Extensions to the public interface.

0.1.0

Initial release.

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

garbelour-0.3.0.tar.gz (21.5 kB view details)

Uploaded Source

Built Distributions

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

garbelour-0.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.2 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

garbelour-0.3.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl (3.2 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ s390x

garbelour-0.3.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (3.6 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ppc64le

garbelour-0.3.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl (3.3 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ i686

garbelour-0.3.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (3.0 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARMv7l

garbelour-0.3.0-cp39-abi3-macosx_11_0_arm64.whl (2.9 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

garbelour-0.3.0-cp39-abi3-macosx_10_12_x86_64.whl (3.0 MB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

Details for the file garbelour-0.3.0.tar.gz.

File metadata

  • Download URL: garbelour-0.3.0.tar.gz
  • Upload date:
  • Size: 21.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.13.3

File hashes

Hashes for garbelour-0.3.0.tar.gz
Algorithm Hash digest
SHA256 fd2bb480126a99b38ee95c170017677ae48b76d4c984d7493eeb4650fec0fbcd
MD5 a8209a51cf3b20e7598a4f57b68ab6af
BLAKE2b-256 dae35154dfa2e69c2d5e71794a5bc1cf07c1c7241900013502e5bd937b8aae3d

See more details on using hashes here.

File details

Details for the file garbelour-0.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for garbelour-0.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 08069607adbabc25cbd8c8333669337e44e8df01bd4a97dbdeac1e8c08f6d79e
MD5 e4d670d70e9f166536cb76dc91bb5f6e
BLAKE2b-256 4bb118cebca2939614579536fb2efaf7cb0e17f3f8e4b5890a28f754c769de9a

See more details on using hashes here.

File details

Details for the file garbelour-0.3.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl.

File metadata

File hashes

Hashes for garbelour-0.3.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm Hash digest
SHA256 8e666d78979f497529b528e32b300c2cf32c863a3584ebfdcf54d0561ffcdf30
MD5 5845e606bd35847d7fd77458f429d70e
BLAKE2b-256 b2275baf15722ce9f08f3d32156d6974847a90cee4d87570606ed5105479b51f

See more details on using hashes here.

File details

Details for the file garbelour-0.3.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl.

File metadata

File hashes

Hashes for garbelour-0.3.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
Algorithm Hash digest
SHA256 c14bf59181b26fa43e5a9f83a431e827bbaef1f7b9fd4a9f0aefffc9ab5f3fc3
MD5 6395b4141a78eb1af90b3642044b967c
BLAKE2b-256 a2069c812cd072c14285b9bb6b5c3a701d99adf08776d453a97d6657462e32b8

See more details on using hashes here.

File details

Details for the file garbelour-0.3.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for garbelour-0.3.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 fb57eda9193484f74f08d27ef1eae3e7e8dcfae78b36b15470f7f9f5559d3e77
MD5 f9b99ba519438d9f13d41c796ef0b695
BLAKE2b-256 a0e6adbc5b8656639c4e8b6e317f2a5682d965a7266753431db5a31817019a30

See more details on using hashes here.

File details

Details for the file garbelour-0.3.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl.

File metadata

File hashes

Hashes for garbelour-0.3.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 b1cc68ed78390c7e0063772be8739470c61fb3e63cb46c0c6c1ec99bd0a1cceb
MD5 cf9a80a034df4f264e6fe48d4533d396
BLAKE2b-256 60a08362a37892286558a2128fabff130ad8e655a9d060b0b4fd3444815b122f

See more details on using hashes here.

File details

Details for the file garbelour-0.3.0-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for garbelour-0.3.0-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 80fb09bdc23adcac57709beb3655a8a0b406d77a351aded420a34b71c8535598
MD5 ba12384fec1dd51d523b02b0a8d6a803
BLAKE2b-256 0457c7a7510f4e4b70017e2d3e2f44d09b432762275211d0c97750914b1e66fd

See more details on using hashes here.

File details

Details for the file garbelour-0.3.0-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for garbelour-0.3.0-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 4344c78e9ce751257fdfcf6b9785409db71b1e2a5db44d39e81f04720476abc5
MD5 ad28bb0883a14fd74410c4cec9ad81dc
BLAKE2b-256 5a3c023b2d2c453f58e3c97fc7db79b044544e7e7e6bd135c1a83b2f18af939f

See more details on using hashes here.

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