judgepanel
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:
- 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.
- 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.
- 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 agreefirst, 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 simulatewith 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)
| 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)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| 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 logRelease 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 logSecurity 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.
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 logA 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.