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
error_handling Review Removed ?, try/except, try/catch, except clauses
size_threshold Review Hunks > 150 changed lines (configurable)

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, size).

Install

From source:

cargo install --path .

The binary is 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
      - run: cargo 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
size_threshold = 150

[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.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.2.0.tar.gz (21.1 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.2.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.2.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.2.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.2.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl (3.2 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ i686

garbelour-0.2.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.2.0-cp39-abi3-macosx_11_0_arm64.whl (2.9 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

garbelour-0.2.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.2.0.tar.gz.

File metadata

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

File hashes

Hashes for garbelour-0.2.0.tar.gz
Algorithm Hash digest
SHA256 273ea16e2614231912742789964fd0333e991e552561b256f0f8cd78cff3c6b3
MD5 557f8b5043dfa53e5d0cbb8e62f0a837
BLAKE2b-256 e02c601da7a6b585cc0f10795cc5c78e20671bcdf64bde165f68b33cbee3eb38

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for garbelour-0.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ce7cfbd883824c6ff17ad16d02496feecca2aa36eb66f1c5019a1832f2206f02
MD5 5cb2cdc1fe9d181bf74204e56e6ca8ac
BLAKE2b-256 5b050c21b5de8b9f5c6bd923e763a95c6b87fa456b5cad18389414caf3e8c400

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for garbelour-0.2.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm Hash digest
SHA256 adca60aacf85a7823c95cbc243ac683a8f1486f31960a96bb7d85b58e69a503e
MD5 d7a1708349b4e20953fdc9d3e1998eba
BLAKE2b-256 f6b1ab5e4c4df6e9224f5c765569cc7276b2da9c2690f0518d4ef9daff880462

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for garbelour-0.2.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
Algorithm Hash digest
SHA256 174567bea5690b8aafa5e0839bddb6c62b5df2c2c4f853b672dd9152ac59b9bf
MD5 ddc942072035f779c03d06a07fb41397
BLAKE2b-256 f3fddeec6396c2f119cdbb3744b5892f177a38b8f77d5f00dd20c6c43bef1ed9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for garbelour-0.2.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 b3e45ac32779096e27b486ca159f1b0d5714d84eb6ecc51271e419ad0a7224e6
MD5 14a89e485a52139abb61b06b0af1e1cf
BLAKE2b-256 76deb638ec0aac7b4926cd6045476ad82c065000b9131aac5124f1bcb6e4415c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for garbelour-0.2.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 98556a2f6c6853fc9a5097963b3b12c1c2f40634e89ac12d5a30a5b0557b1c51
MD5 4287f036212dba9a6ba4ed03a30878dd
BLAKE2b-256 ebf495a2a1e32253c8e86868c40b2f7a24d33b6ccc2d9f9236a3d4210189dfd4

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for garbelour-0.2.0-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 d3e5275e7159f02391e6f05285261f8877a2d024e54cca9e8e072a1e45b5d0bc
MD5 57c3cfd6afa854696cc3492a0f2d13bb
BLAKE2b-256 cf31fb9e1f77c5149fd6539b3ada975cf4bb476423d1d4835f3df034525f6f85

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for garbelour-0.2.0-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 6e2b96a05f2d4db395755d21a47668da67439d7c9f2389b554834adb1b451fca
MD5 7a88d6cfa1079342ea4eccc5447f0f63
BLAKE2b-256 7a282d4a2bd5daac6faec671b1bb13ba928a1a814f4a3550cdd5b03ceae04266

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