What the compiler
does not tell you
judge reads the current source tree, the workspace structure, the public APIs and the dependency graph. It never repeats what the compiler or Clippy already report.
$ cargo judge [WARN] Judge summary Analysis context: boundary rules: 0 not checked (no judge.toml) Evidence: 102 Advisory: 58 Top issue rules: 84x duplicate-code 35x complexity-inflation 14x maintainability-index 9x swallowed-result 5x silent-default
Measured on the lightweight-pdf workspace with 8 crates and 765 analysed functions. Plus 58 heuristics, reported separately.
cargo judge dupes in mild mode: 84 members across 41 families, each with file, line range and function names. Test code counts only with --include-tests.
A configurable trend index, not an objective quality verdict. The delta against a baseline is the message, not the absolute number.
Structural findings that only become visible across a whole workspace.
judge is built as a Cargo subcommand and runs both as cargo judge and as cargo-judge. It analyses the checked-out state – no commit history, no authorship, no telemetry. Results apply equally to human-written, generated and agent-refactored code.
- 01Deterministic — same source tree, same findings; no network access unless you ask for it
- 02Evidence, not guesswork — every finding carries an evidence class, a location and a reason
- 03Heuristics kept apart — advisory findings affect neither verdict nor score
- 04Not a replacement — no linter, no formatter, no security scanner
Five directions judge looks in.
Each category is its own subcommand and part of the combined run – except the ones that are explicitly opt-in.
- 01
Duplication
dupesgroups repeated token spans into clone families, in four modes fromstricttosemantic. Intentional duplicates can be justified with// judge-dupe-ignore: <reason>before the function – without a reason the directive does not apply. - 02
Complexity and maintainability
complexityandhealthreport cyclomatic complexity per function and a maintainability index per file. Production and test code stay separate. - 03
Dead code
dead-codebelongs to the Deep Tier and reportsunused-pub-workspace:pubitems with no reference from another workspace crate and no reachability from a recognised entry point. That means “no use found in the examined view”, not “proven dead”. - 04
Dependency hygiene
depschecks dependency kinds, feature flags and local name collisions. crates.io lookups and cross-referencing an already generatedcargo audit --jsonreport are opt-in – judge never runs cargo-audit itself. - 05
API surface and boundaries
apishowsundocumented-public-itemandsemver-hazard.boundarieschecks crate boundaries declared in ajudge.tomland finds cycles; without a config it does nothing.
Three outputs from a real run.
$ cargo judge dupes
mode: mild
min tokens: 20
clone families: 41
refactoring summary: 41 clone families, 84 members (repeated tokens, not an automatic merge recommendation)
#1 3 members × 22 tokens = 66 repeated tokens across 2 files collect_anchors_in_node, collect_headings_in_node, collect_anchor_pages_in_node
#2 3 members × 20 tokens = 60 repeated tokens across 1 files layout_rich_text, layout_rich_text, layout_text_fixed_overflow
#3 2 members × 66 tokens = 132 repeated tokens across 1 files layout_row_cells, render_cells_starting_at
#4 2 members × 63 tokens = 126 repeated tokens across 1 files hard_break_word, hard_break_styled_word
#5 2 members × 59 tokens = 118 repeated tokens across 1 files natural_row_heights, apply_rowspan_deficits$ cargo judge deps
dependency findings: 5
[unused-feature-flag] lightweight-pdf serde
[heavy-dependency] lightweight-pdf-cli lightweight-pdf
[workspace-dep-drift] ? png
[workspace-dep-drift] ? schemars
[workspace-dep-drift] ? serde
feature-only candidates (no code usage found; see unused-feature-flag findings above for detail): serde$ cargo judge health --score
functions analyzed: 765
slop signals: 14 (52 advisory)
swallowed-result: 9
suppression-debt: 2
complexity-inflation: 35
maintainability-index: 14
abstraction-inflation: 1
integer-cast-risk: 2
panic-in-lib: 3
health score: 97.8 (A) — 16026 authored LOC, 0 fail, 12 warn, 57 advisory (not scored)Install, run, freeze.
- 1Install
From crates.io
Requires Rust 1.95 or newer (edition 2024). Alternatively build from the repository or use
cargo install --path ..cargo install cargo-judge - 2Run
Combined report
The default view groups by rule and shows one representative location per group.
--detailslists every finding,--format jsonwrites the full artifact.cargo judge - 3Freeze
Set a baseline
The baseline is a file, not a Git revision. From then on, only what is new against that state counts.
cargo judge --save-baseline
Why two runs produce the same thing.
Without the opt-in flags of deps, judge makes no network calls. The result therefore does not depend on when you ran it.
compare compares the current state with a saved artifact file and works without Git.
Every JSON file starts with a header holding the working directory, output path, timestamp, a command description and an assessment.
A trend is shown only when the baseline was produced with the same score formula version and the same crate profiles. Anything else is reported as not comparable instead of a false delta.
One job, two artifacts.
# .github/workflows/judge.yml
name: judge
on: [pull_request]
jobs:
judge:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo install cargo-judge
# fails as soon as anything new appears against the baseline
- run: cargo judge --baseline .judge/baseline.json
# SARIF 2.1.0 goes to stdout, e.g. for code scanning
- run: cargo judge --format sarif > judge.sarifWhat judge deliberately leaves alone.
| Criterion | judge | Clippy | cargo-audit |
|---|---|---|---|
| Field of view | workspace, across files | file and expression | dependency graph |
| Duplication across crates | yes | no | no |
| Known vulnerabilities | only against an existing report | no | yes, its own source |
| Baseline with a verdict | yes | no | no |
| Needs a build | only in the Deep Tier | yes | no |
judge replaces neither tool. The rule in the repository: anything the compiler or Clippy already tells you, judge does not repeat.
Fast Tier and Deep Tier.
- Default
Fast Tier
Analysis via
syn,cargo metadataand the manifests. No build of the project needed, so it is fast enough for every pull request. - Opt-in
Deep Tier
Loads the workspace into rust-analyzer to work with real reference data instead of syntax-level guesses. Building the
ra_ap_*crates takes noticeably longer. - Handoff
Artifacts
Versioned JSON on every report command, SARIF 2.1.0 for code scanning, Markdown for pull-request descriptions. A separate MCP adapter passes the JSON output on to assistants.
The verdict CI listens to.
$ cargo judge --save-baseline
$ cargo judge compare .judge/baseline.json
verdict: pass
unchanged: 160
resolved: 0
introduced: 0
introduced advisory (heuristic — no verdict effect): 0
severity changed: 0What the analysis does not do.
The findings are evidence, not verdicts. Four limits judge names itself.
Dead code is not proven dead
unused-pub-workspace means “no use found in the examined view”. The workspace is loaded without a proc-macro server and without running build.rs, so generated code is invisible.
The score is a trend index
Not an objective quality ranking. With no basis to compute it, judge reports the score as unavailable and exits with code 2 – rather than inventing a perfect number.
Early in the project
The Fast Tier is implemented, the Deep Tier only as a first slice. Module-level boundaries and several planned maintainability and dependency-hygiene rules are still missing.
Duplication needs judgement
A clone family is an observation of repeated tokens, not an automatic recommendation to merge. That is why refactor never invents a patch.
cargo-judge, or a modified version, to third parties as a hosted service or a competing product. Each version converts to Apache 2.0 four years after its release.Licence text in the repository →- Rust workspaces with several crates
- Reviews after large refactorings
- Pull-request gates
- Handovers between teams
- Coding agents as readers
Frequently asked questions.
Does judge replace Clippy?
No. The rule in the repository: anything the compiler or Clippy already tells you, judge does not repeat. It covers structural and cross-file concerns that only become visible across a whole workspace.
Which exit codes are there?
0 for a clean run, 1 when findings are reported, 2 for an error or an incomplete analysis. In the run against lightweight-pdf on 2026-09-16 the exit code was 0 even though 102 evidence findings were reported: none of them had severity fail.
How do I keep CI from failing on old debt?
With a baseline. cargo judge --save-baseline writes the current state to .judge/baseline.json, after which cargo judge --baseline only judges what is new against that state. The baseline is a file and needs no Git.
Does judge read my commit history?
No. The analysis looks at the checked-out source tree, the workspace structure, the public APIs and the dependency graph. Authorship, commit history, telemetry and code provenance are explicitly out of scope, and compare compares against an artifact file rather than a revision.
What is the difference between evidence and advisory?
Evidence findings are tied to verifiable proof and affect verdict and score. Advisory findings are reproducible interpretations, that is heuristics: they are reported separately and affect neither verdict nor score.
Can a coding agent use the output?
Yes, that is part of the design. Every report command can write versioned JSON, and the judge-mcp directory holds a thin stdio adapter that shells out to an already-built cargo-judge binary and returns its JSON as MCP tool calls. It computes nothing itself and is not a requirement for judge.
Run it once, then set a baseline.
The first run needs no build of the project and no configuration.