Skip to main content

judgepanel

CI PyPI DOI Python License: MIT

Estimate how accurate your LLM judges are without gold labels. On a real panel of 400 agent trajectories, posterior aggregation ties majority vote on accuracy (0.895 vs 0.897, one item apart).

When several imperfect judges label the same items, the disagreement pattern itself reveals who is reliable. judgepanel fits the classic Dawid–Skene model (1979) to a judge panel and recovers, jointly:

  • each judge's confusion matrix (sensitivity/specificity in the binary case),
  • the class prevalence,
  • a posterior over every item's true label, weighted by estimated judge quality instead of one-judge-one-vote.

Around the core: majority-vote baselines with explicit tie handling, chance-corrected agreement (Cohen's and Fleiss' kappa), bootstrap confidence intervals, and simulators for planning panels and studying failure modes. Pure NumPy; no model calls; every fit deterministic.

Install

pip install judgepanel

Sixty seconds

Your data is one JSON object per (item, judge) verdict:

{"item": "case-0017", "judge": "gpt-strict", "label": "faulty"}
judgepanel fit examples/data/demo_panel.jsonl --positive faulty --bootstrap 200
panel: 300 items, 5 judges, 2 classes (clean, faulty)
converged after 55 iterations
estimated prevalence: clean=0.577, faulty=0.423

judge            sens    spec  youden
gpt-strict      0.906   0.931   0.836
gpt-lenient     0.715   0.999   0.714
small-model     0.692   0.710   0.402
rules           0.562   0.996   0.559
flag-happy      0.953   0.394   0.347

The demo panel is synthetic with known truth (examples/data/demo_gold.jsonl): the true parameters are (0.92, 0.94), (0.70, 0.97), (0.66, 0.72), (0.55, 0.99) and (0.97, 0.35) — every estimate above lands within 0.04 without ever seeing a gold label, and the flag-everything judge is exposed immediately.

Same thing in Python:

from judgepanel import fit_dawid_skene, read_panel_jsonl

panel = read_panel_jsonl("panel.jsonl")
result = fit_dawid_skene(panel)
result.sensitivity("faulty")   # {"gpt-strict": 0.906, ...}
result.labels()                # posterior-aggregated label per item

Keys are configurable, so existing verdict files work directly (--item-key trajectory_id --judge-key judge_id --label-key faulty; boolean labels become "true"/"false").

Validation on a real judge panel

The trajectory-judge study had five LLM judges label the same 400 agent trajectories as faulty or clean, with gold labels known by construction. Fitting judgepanel on the verdicts alone (gold hidden), then unblinding (python examples/case_study.py --raw .../results/raw):

judge est sens true sens est spec true spec
programmatic rules 0.771 0.667 0.993 1.000
outcome-only (14B) 0.639 0.613 0.633 0.670
step-rubric (14B) 0.995 0.857 1.000 1.000
step-rubric (8B) 0.988 0.990 0.000 0.000
self-consistency k=3 (14B) 0.980 0.843 0.994 0.990

Three honest findings:

  1. The spammer is exposed exactly. The 8B judge flags nearly everything; its estimated specificity is 0.000 — matching the truth — with no gold label in sight. The judge quality ranking is right across the board, and the production-default outcome judge is estimated within 0.04.
  2. Correlated judges inflate their own estimates. Self-consistency is the step judge sampled three times, and the two agree at kappa 0.96. Dawid–Skene assumes conditionally independent judges, so this pair drags the latent truth toward its shared verdicts: both get overestimated by up to +0.14, and estimated prevalence drops to 0.645 against a true 0.750. The library prints the kappa matrix precisely so you check this before believing the fit.
  3. No aggregation recovers what every judge misses. Faults that leave the final answer correct are invisible to the whole panel, so posterior aggregation (0.895 accuracy) cannot beat majority (0.897) here. Weighted aggregation wins when judge quality is uneven, not when errors are shared.

When not to trust it

  • Fewer than 3 judges: weakly identified; the fit warns.
  • Highly correlated judges (same base model, ensembles of one judge, shared blind spots): estimates bias toward the correlated cluster — check judgepanel agree first, and prefer diverse judge families.
  • A panel that is wrong on average: if most judges are worse than chance, the labels-and-mirror solution is indistinguishable without gold.
  • Tiny or extremely imbalanced panels: run judgepanel simulate with your expected operating points to see the estimation error you should expect before you rely on the numbers.

API

call what it does
read_panel_jsonl(path, ...) long-format JSONL → Panel
fit_dawid_skene(panel) EM fit → confusions, prevalence, posteriors
bootstrap_judges(panel, n_boot=200) percentile CIs for judge parameters
majority_vote(panel) baseline aggregation, ties made explicit
cohen_kappa, fleiss_kappa, pairwise_cohen_kappa agreement diagnostics
simulate_panel, simulate_confusion_panel synthetic panels with known truth

CLI: judgepanel fit, judgepanel agree, judgepanel simulate, judgepanel version (each supports --json).

Development

python -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/pytest          # 52 tests: hand-computed values, seeded recovery, CLI
.venv/bin/ruff check src tests && .venv/bin/mypy src

The suite checks statistical behaviour, not just plumbing: kappa against hand-computed tables, EM recovery on seeded synthetic panels, log-likelihood monotonicity, bootstrap coverage, and determinism.

Part of evalstack

evalstack is the map of these eleven evaluation tools: what each one measures, what it found on real data, and the two chains that run end to end.

Citing

The accompanying paper, Judging Without Gold: Gold-Free Estimation of LLM-Judge Accuracy and Its Failure Modes, is a working paper (2026).

Releases are archived on Zenodo. Cite the concept DOI 10.5281/zenodo.21809473, which always resolves to the latest version; structured metadata is in CITATION.cff.

License

MIT — see LICENSE.

Metadata

Release files for judgepanel 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for judgepanel 0.1.1
File Size Uploaded Provenance Actions
judgepanel-0.1.1.tar.gz 22.5 kB With provenance Details for judgepanel-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for judgepanel 0.1.1
File Interpreter ABI Platform Actions
judgepanel-0.1.1-py3-none-any.whl Python 3 none any Details for judgepanel-0.1.1-py3-none-any.whl

Total release size: 43.2 kB

Release files / judgepanel-0.1.1.tar.gz

Download URL judgepanel-0.1.1.tar.gz
Size 22.5 kB
Tags Source
SHA-256 checksum
How to use checksums
c782ee09c69a8b98fc827693c4f68ba9ce7d752b77014cff636b14bb092a6a2f
BLAKE2b-256 checksum
How to use checksums
d8cd7ecf141ba7f220b38c771a9cac36a89305acffefa5b5992e48e72221168c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

Release files / judgepanel-0.1.1-py3-none-any.whl

Download URL judgepanel-0.1.1-py3-none-any.whl
Size 20.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ec5970b905b3a7d47cc65335d7c00c746783a136847fac69b95fa46828d8aa1f
BLAKE2b-256 checksum
How to use checksums
2312fedc64aeb30ddbbbccaa171bf4fdff245731569080004b7cb1fe2b5ec171
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

Security for judgepanel 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for judgepanel-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page