Prebuttal
Answer Reviewer 2 before Reviewer 2 exists.
Purpose-built for ML conferences: real NeurIPS / ICLR / ICML / ARR review-form output, three reviewers running in fully independent contexts (optionally cross-model), and a built-in pipeline to measure its scores against real OpenReview ratings.
Prebuttal is a pre-submission stress test for your paper: it sends your submission through three isolated AI reviewers with different temperaments plus an area chair, and hands you a conference-format review report — scores, disagreement, weaknesses with citations to your own tables — before the real Reviewers 1–3 see it. See a synthetic sample: report · share page — or what a deliberately flawed (fictional) paper gets: 1/10 report.
Why not just paste the paper into ChatGPT?
That is the main competitor. It loses, four ways:
| Paste into ChatGPT | Prebuttal |
|---|---|
| One conversation role-playing three reviewers → persona collapse into a single bland compromise opinion | Three reviewers in fully independent contexts (separate calls/processes), genuinely different verdicts + measured disagreement |
| Long papers get skimmed; tables are flattened into prose | Ingestion pipeline: cell-by-cell table extraction (LaTeX tabular parsing, PDF table detection, caption fallback) — reviewers can point at Table 3, column 4 |
| Output is free-form chat text | Real conference review forms: NeurIPS 1–6, ICLR 1–10, ICML 1–10, ARR Soundness/Excitement/Overall — with official scale anchors |
| Scores are vibes | Seeds and temperatures applied where the backend supports them (API, Ollama) and marked n/a where it doesn't (agent CLIs), recorded backends/models per reviewer, and a calibration script to measure scores against real OpenReview ratings (published results pending) |
Quickstart
pip install prebuttal
prebuttal run paper.pdf --venue iclr
prebuttal run https://arxiv.org/abs/2510.12345 --venue neurips
prebuttal run ./latex-src/ --venue acl
Prefer an isolated install for command-line tools? pipx install prebuttal
or uv tool install prebuttal work the same way (or uvx prebuttal ... to
run without installing). Requires Python 3.11+.
The first run costs zero setup if you already have a subscription CLI or
Ollama — Prebuttal auto-detects the cheapest path at startup and prints what it
chose (prebuttal backends to inspect):
| Backend | Auth | Notes |
|---|---|---|
agent-claude (claude -p) |
your Claude subscription, zero API key | preferred reviewer |
agent-codex (codex exec) |
your Codex subscription, zero API key | gives cross-model reviews together with claude; runs locked down, ignoring ~/.codex/config.toml (see SECURITY.md) |
api-gemini |
GEMINI_API_KEY | free tier — the cheapest "first key" path |
api-openai / api-anthropic |
OPENAI_API_KEY / ANTHROPIC_API_KEY | BYO key |
api-openrouter |
OPENROUTER_API_KEY | one key, hundreds of models — :free ids cost nothing (default is one); prices shown live in prebuttal models |
ollama |
none | local & private — unpublished papers never leave your machine (with the default localhost host) |
relay |
none | file protocol: prompts spool to disk and you, your agent's subagents, or any system write the answers — zero key, explicit only (--backend relay; never picked by auto) |
Unpublished manuscript? The text is sent to the backend's provider, and
what happens to it there is that provider's privacy policy, not ours — see
Privacy & data custody. For local-only review use
ollama or relay.
⚠️ Free tiers are usually paid for with your data. Free API tiers (the Gemini free tier, OpenRouter
:freemodels and their upstream providers) may let the provider log, review or train on what you send. They are fine for published papers and trying the tool out — for an unpublished manuscript, check the provider's current terms, use a paid tier, or stay local.
Useful flags:
prebuttal run paper.pdf --venue neurips --dry-run # cost + plan preview, calls nothing
prebuttal run paper.pdf --venue iclr --json out.json # also write machine-readable JSON
prebuttal run paper.pdf --note "added ablation" # label this revision
prebuttal run paper.pdf --seed 42 # reproducible (API / Ollama backends)
prebuttal run paper.pdf -y # skip the plan confirmation
In auto mode on a terminal, Prebuttal shows the review plan before calling
anything — press Enter to run, e to re-pick each reviewer's persona, backend
and model via numbered menus, or n to abort. CI and pipes get the plan
printed and proceed automatically; fully-explicit configs never prompt.
prebuttal models lists every backend's actually-available models (live API
scan + installed Ollama models + claude aliases) with the current default
marked — pick one and set model = "..." per reviewer in prebuttal.toml.
Built-in defaults are mid-tier models current at release time and change
between versions — providers retire model ids quickly, so if a default stops
working, upgrade prebuttal or pin a model yourself.
The reviewers
| id | Persona | Behavior |
|---|---|---|
| R1 | senior_kind |
senior, constructive; core contribution + main concerns, grounded |
| R2 | adversarial |
Reviewer 2 in the flesh: motivation, baselines, novelty, overclaiming |
| R3 | detail_obsessive |
reads every table cell; statistics, ablations, reproducibility |
| AC | area_chair |
meta-review, adjudicates disagreement, estimates the final rating |
Every persona enforces the same protocol: cite the evidence (section,
table, number) or the point doesn't count; use the full scale; JSON-only
output. There is also an easter-egg roast persona (persona = "paper_roast")
for when you need the truth fast.
Personas live in prebuttal/personas/ and venue forms in
prebuttal/venues/forms/ — plain text files, PRs
welcome (scale wording drifts every year; keep it current).
Your own venue (custom review forms)
Built in: neurips, iclr, icml, acl. Anything else — CVPR, AAAI, a
journal, this year's revised ICML form, your lab's internal mock review — is
one TOML file plus the form text:
prebuttal venues new cvpr # template in ~/.prebuttal/venues/
prebuttal venues new icml-2027 --from icml --here # copy a built-in, project-local
prebuttal venues # list built-in + custom (invalid ones flagged)
prebuttal venues show cvpr # the scores and form reviewers will see
prebuttal run paper.pdf --venue cvpr # or --venue path/to/venue.toml
# cvpr.toml
name = "CVPR 2027"
form = "cvpr.md" # the reviewer guidelines, shown to reviewers verbatim
rating = "rating" # which score is the overall recommendation
[[fields]]
key = "weaknesses"
label = "Weaknesses"
kind = "list" # text | list | score
[[fields]]
key = "rating"
label = "Overall recommendation"
kind = "score"
max = 6 # scores run 1..max; half_steps = true allows 3.5
anchors = { "1" = "Reject", "3" = "Borderline", "6" = "Strong accept" }
Venues are looked up in ./.prebuttal/venues/ (commit it to share with
co-authors) and then ~/.prebuttal/venues/; built-in names can't be
shadowed, so a copy needs its own name. Files are checked before any model is
called, and every error names the file and the setting. Reports keep the
venue's definition, so archived runs still render after the file changes.
Custom venues are not calibrated: the calibration script needs OpenReview
scores for a real venue. A venue's form text is instructions to your reviewers, so only
use venue files you trust (the form must sit next to its .toml).
Configuration
prebuttal init writes a commented prebuttal.toml. Per-reviewer backends,
models and temperatures:
[default]
venue = "iclr"
seed = 42
# effort = "high" # optional, see "Reasoning effort" below
[[reviewer]]
id = "R1"
persona = "senior_kind"
backend = "agent-claude" # claude -p, subscription auth
temperature = 0.4
[[reviewer]]
id = "R2"
persona = "adversarial"
backend = "agent-codex" # codex exec, subscription auth
model = "gpt-5.1" # optional: forwarded as --model (agent CLIs too)
temperature = 0.7
[[reviewer]]
id = "R3"
persona = "detail_obsessive"
backend = "api-gemini" # free tier; default model gemini-3.5-flash-lite
temperature = 0.5
[ac]
persona = "area_chair"
backend = "agent-claude"
Reasoning effort
Leave it unset and every model thinks as much as its provider's default — the
right choice for most papers. To trade cost and time for depth, set
--effort low|medium|high for one run, effort = "..." under [default],
or per [[reviewer]] / [ac]. It maps onto each backend's own control:
| Backend | Sent as |
|---|---|
agent-claude |
claude --effort |
agent-codex |
-c model_reasoning_effort=... |
api-anthropic |
output_config.effort |
api-openai |
reasoning_effort (gpt-5 and later / o-series reasoning models) |
api-gemini |
thinkingLevel (Gemini 3+) / thinkingBudget (2.x) |
api-openrouter |
reasoning.effort |
ollama |
think (gpt-oss models) |
Where a model has no such control (classic chat models, relay, custom agent
CLIs) the setting is skipped; --dry-run says so up front, and every report
lists the effort each review actually ran with.
Figures as images
Reviewers see figure captions by default. With --figures (or
figures = true under [default]), reviewers on the vision-capable API
backends — api-anthropic, api-openai, api-gemini, api-openrouter —
also get the figures as images: for a PDF or arXiv paper, each page that
holds a figure caption; for a LaTeX project, the first \includegraphics of
each figure (files inside the project folder only). At most max_figures
(default 6) images, ~1.5k tokens each. A text-only model behind one of those
APIs is retried without images; agent CLIs, Ollama and relay keep captions
only. Each review says how many images it saw.
Calibration (honesty, not prophecy)
Scores are meaningless unless measured. The calibration pipeline runs Prebuttal on papers that already have real OpenReview reviews and plots predicted vs true mean ratings:
The script lives in the repository (it is not part of the pip package), so run it from a clone:
git clone https://github.com/GuoYuKai-SaMuEl/prebuttal && cd prebuttal
pip install -e ".[calibration]"
python scripts/calibration/calibrate.py \
--venue-id ICLR.cc/2024/Conference --venue iclr -n 20 --out-dir calib_out
Output: scatter plot + MAE + correlation. No calibration results are published yet — until they are, treat every score as uncalibrated. Once published, the claim they support is narrow and deliberate: this tool was measured — unlike role-play prompts. It is not a claim that it predicts your score; real reviewers disagree with each other by more than this tool's error. Disagreement (σ) is reported with every aggregate for exactly that reason.
The revision plan
Reviews tell you what is wrong; the revision plan tells you what to do about it. The area chair merges what the reviewers raised into a short, prioritised list — no extra model call, it comes with the meta-review:
- [ ] **must** — Baseline set is thin: Table 1 misses a Perceiver comparison
→ Add Perceiver-AR to Table 1 or scope the claim to the baselines run (R2, R3 · effort: medium)
- [ ] **should** — No variance across seeds for the Table 2 ablation
→ Report mean and std over 3 seeds (R3 · effort: small)
It opens every report, the run prints the top items (Fix first:), and
prebuttal plan [run] prints it as a checklist to paste into your notes or an
issue (--json for scripts). After you revise and re-run, prebuttal diff
checks the old plan against the new reviews: which items are no longer
detected, which still are, and what is new. The matching is by wording, so a
reworded issue shows up as "not re-detected" and "new" — compare runs made
with the same backends and seed, and read both lists before ticking anything
off.
Projects, reports & revision history
Each paper gets a project, found from where it came from: the same PDF
path, LaTeX folder or arXiv id always lands in the same project, even when the
title changes between revisions (--project NAME to pick one yourself). Every
run gets a number within it — mamba-linear-time-sequence#3 — and its own
report folder, so nothing is ever overwritten:
prebuttal-reports/ (has a .gitignore: reviews stay out of git)
└── mamba-linear-time-sequence/
├── latest.md / latest.html ← always the newest run
├── 2026-10-25_1530_iclr/report.md, report.html
└── 2026-10-26_0910_iclr/report.md, report.html
The complete record (Markdown, HTML, JSON and the resolved config — backends,
models, seeds) is also archived under ~/.prebuttal/ (--no-save opts out),
so everything below works from any directory:
prebuttal projects # one line per paper: runs, latest score, trend
prebuttal runs [project] # its runs, newest first, with notes
prebuttal open # newest report in the browser (HTML)
prebuttal plan # the newest run's revision plan as a checklist
prebuttal diff # newest run vs the one before: ratings, weaknesses, plan
prebuttal diff --llm # ... matching plan items by meaning (one model call)
prebuttal retry # re-run only the reviewers that failed (+ the AC)
prebuttal dashboard # local HTML overview: every project, score trends, links
prebuttal show / export / note / rm # print, copy out, annotate, delete runs
prebuttal projects rename|rm # tidy up
Runs are referenced as latest (the default), mamba (newest run of a
project), mamba#3 (run 3), mamba~1 (one before the newest) or by id
prefix.
The revision loop: fix what the reviewers flagged, re-run with the same
--seed and a --note "what changed", then prebuttal diff shows which
weaknesses went away, persisted, or appeared, and which revision-plan items
are no longer detected. Report location and formats
are configurable: --out-dir, --format md,html,json, or an [output]
section in prebuttal.toml (dir = "" keeps reports in the archive only).
Need a file at a fixed path, e.g. for a script? --json PATH, or
prebuttal export -f md -o PATH after the run.
Skill package
skills/prebuttal/SKILL.md teaches any agent to
drive the CLI and interpret the JSON — including relay mode (the reviewers are
the agent's own subagents) and the runs/diff revision loop. The skill file
is explicit about the one rule that matters: the agent must run the CLI,
never role-play the reviewers itself.
When the CLI detects it is running inside a coding agent (currently Claude
Code and Gemini CLI), prebuttal run and prebuttal backends print a one-line
hint pointing at relay mode. An agent environment that should always use its
own subagents can pin it once with PREBUTTAL_BACKEND=relay. Relay is never
chosen automatically: the CLI has to run in the background while the agent
answers the requests, or both sides wait on each other.
Install it into your agent's skills directory — for Claude Code:
mkdir -p ~/.claude/skills/prebuttal && curl -fsSL -o ~/.claude/skills/prebuttal/SKILL.md \
https://raw.githubusercontent.com/GuoYuKai-SaMuEl/prebuttal/main/skills/prebuttal/SKILL.md
# or, from a clone: cp -r skills/prebuttal ~/.claude/skills/
Other agents (ZCode, Codex, …): copy or symlink skills/prebuttal/ wherever
your agent discovers skills (see its docs), or reference the file from your
AGENTS.md / system prompt.
Reference
Environment variables
API keys — two ways, pick either:
prebuttal key set gemini # quick setup: hidden prompt, stored for next time
# or the classic way: set GEMINI_API_KEY / OPENAI_API_KEY / ANTHROPIC_API_KEY yourself
Stored keys live in ~/.prebuttal/keys.env (user-only permissions, like
~/.aws/credentials); real environment variables always take precedence, so
CI setups are unaffected. prebuttal key status shows what's set (masked),
prebuttal key unset <name> removes one.
| Variable | Purpose |
|---|---|
OPENAI_API_KEY / ANTHROPIC_API_KEY / GEMINI_API_KEY (or GOOGLE_API_KEY) / OPENROUTER_API_KEY |
enable the matching API backend |
OPENAI_BASE_URL |
point api-openai at an OpenAI-compatible proxy |
PREBUTTAL_OPENAI_MODEL / PREBUTTAL_ANTHROPIC_MODEL / PREBUTTAL_GEMINI_MODEL / PREBUTTAL_OPENROUTER_MODEL |
override each backend's default model |
PREBUTTAL_OLLAMA_HOST (or OLLAMA_HOST) |
Ollama base URL (default http://localhost:11434) |
PREBUTTAL_BACKEND |
force one backend for every reviewer + the AC (e.g. relay); --backend still wins, prebuttal.toml loses |
PREBUTTAL_HOME |
run-history and key storage location (default ~/.prebuttal) |
API keys are only read from the environment or keys.env — never written to
reports, JSON, or share pages.
Exit codes
| Code | Meaning |
|---|---|
| 0 | success |
| 2 | bad usage / config error / paper not found / unknown run id |
| 3 | no review backend available |
| 4 | partial failure (some reviewers or the AC failed; report still written) |
| 5 | every reviewer failed |
| 130 | interrupted (Ctrl+C); reviews that had finished are archived — prebuttal retry completes the run |
Comparison
What Prebuttal provides, next to the common alternatives (by category — check any specific tool's own docs for what it supports):
| Approach | Form | Venue forms | Calibration | Cross-model | Tables in-pipeline |
|---|---|---|---|---|---|
| Prebuttal | CLI + skill | NeurIPS / ICLR / ICML / ARR (editable plain text) | OpenReview script (scatter + MAE; results pending) | claude × codex × API × ollama | cell-by-cell |
| generic "review my paper" agent skills / prompts | agent skill | varies | rarely | single model | via the host model |
| multi-agent peer-review research frameworks | research code | study-specific | study-specific | sometimes | rarely |
| paste into a chatbot | chat | ✗ | ✗ | ✗ | ✗ |
How it works
PDF / LaTeX dir / arXiv link
└─ ingestion: sections, cell-accurate tables, figure captions, refs
└─ reviewer pack (budget-aware; tables are never truncated)
├─ R1 senior_kind ──┐ three independent contexts,
├─ R2 adversarial ──┤ parallel fan-out, venue form + JSON schema
├─ R3 detail_obsessive ─┤
└─ AC area chair ◄──┘ meta-review + estimated rating + disagreement
└─ Markdown + HTML report per run · JSON · project history
Orchestration lives in the CLI, not the host agent — the same pipeline runs from a terminal, from inside any coding agent, or in CI.
Roadmap & versioning
Versioning policy while pre-1.0: patch releases (0.1.1, 0.1.2, …) are fixes and small additions; minor releases (0.2, 0.3, …) are substantial new features; 1.0 only once the interface is battle-tested.
Tentative — priorities shift with usage and feedback. Short-term the focus is hardening the core on real papers, not adding features:
- v0.2 (released) — core: ingestion pipeline, real venue forms, 3 independent reviewers + AC, every backend (agent CLIs / APIs / Ollama / relay), reports + JSON + share page, calibration script; plus projects & revision history (per-paper report folders, run management, local dashboard) and per-role reasoning effort; v0.2.1 hardened PDF table extraction on real two-column papers
- v0.3 (current) — custom venues (any review form and scale as a TOML
file) and the revision plan (the AC's prioritised fix list, checked
against the next run by
prebuttal diff) - Now (v0.3.x) — polish from real-usage findings: calibration scatter plot + honest per-model calibration notes, provider-reliability UX (free-pool reality, retry transparency), relay UX
- Next (v0.4+) — community personas, OpenReview submission integration, and a browser-only web quick-scan (GitHub Pages: drag-drop a PDF + your own OpenRouter/Gemini key — no server, we stay a non-custodian); then the rebuttal workbench (reviews → point-by-point response letter) and "CI for papers" (GitHub Action: \ref/\label checks, citation sanity)
- Eventually — the calibration script becomes a public benchmark / leaderboard: tools depreciate, benchmarks appreciate.
Develop
git clone https://github.com/GuoYuKai-SaMuEl/prebuttal && cd prebuttal
python -m venv .venv && .venv/Scripts/pip install -e ".[dev]" # Windows
.venv/bin/pip install -e ".[dev]" # macOS/Linux
pytest -q
Contributions welcome — the easiest ones are venue forms, personas, and backends; see CONTRIBUTING.md for the three-step guide. Also read CHANGELOG.md, SECURITY.md, and our Code of Conduct.
Honesty & policy
- Prebuttal labels every review with the backend and model that produced it.
- It reports score disagreement, always. High σ is information.
- It is a stress test, not a predictor — the report footer says so, every time.
- Mind conference policies: with NeurIPS 2026 running an official AI-assisted reviewing experiment, the etiquette is clear — AI to prepare your own paper is yours to decide; AI to review others' papers must follow each venue's disclosure rules.
Privacy & data custody
- Your paper's text goes to whatever backend you configure. With API or agent-CLI backends the manuscript is transmitted to that provider — and OpenRouter further routes each request to a third-party upstream provider. What happens to the text there (retention, training use, human review) is governed solely by each provider's terms and privacy policy, not by Prebuttal.
- Prebuttal is an integration layer, not a data custodian. This project operates no models and runs no servers; we never see your paper. For unpublished results, check the backend provider's data-use terms before sending — provider-side handling of your data is the provider's responsibility, not this project's.
- Free tiers deserve extra care: free API tiers (e.g. Gemini's free
tier, OpenRouter
:freemodels) may allow logging or training on inputs; paid tiers usually don't. Read the terms before sending unpublished work. - Local-only is a first-class path:
ollamanever sends text off your machine (as long asPREBUTTAL_OLLAMA_HOST/OLLAMA_HOSTpoint at localhost — a remote Ollama server receives the paper like any API), andrelayleaves who answers entirely to you. - What Prebuttal itself stores stays on your disk: run history (pack
text, raw outputs, resolved config) under
~/.prebuttal/runs/and keys in~/.prebuttal/keys.env(user-only). No telemetry. Note reports and share pages contain excerpts of your paper — sharing them publishes those excerpts.
License & trademarks
Prebuttal is an independent project, not affiliated with or endorsed by NeurIPS, ICLR, ICML, ACL/ARR or any model provider. Venue names are used only to describe which review form a report follows; the forms are paraphrased summaries of the public reviewer guidelines.
MIT
Metadata
Release files for prebuttal 0.4.0
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 |
|---|---|---|---|---|
| prebuttal-0.4.0.tar.gz | 370.7 kB | With provenance | Details for prebuttal-0.4.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| prebuttal-0.4.0-py3-none-any.whl | Python 3 | none | any | Details for prebuttal-0.4.0-py3-none-any.whl |
Total release size: 508.1 kB
Release files / prebuttal-0.4.0.tar.gz
| Download URL | prebuttal-0.4.0.tar.gz |
|---|---|
| Size | 370.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ce00ac136b714f9128daf6c8f579935f6b0b97c1224b05881423018972079b2e
|
|
BLAKE2b-256 checksum How to use checksums |
cc9b59c47c0c320b1be711ec58bd59e97200a210121cd3848b87521dd95321f0
|
| 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 Oct 27, 2026.
Transparency logRelease files / prebuttal-0.4.0-py3-none-any.whl
| Download URL | prebuttal-0.4.0-py3-none-any.whl |
|---|---|
| Size | 137.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ebd2efb20b92d6330152624a12e2f6bf8853ea3d29187e674bc946dfa544512d
|
|
BLAKE2b-256 checksum How to use checksums |
8bd4a59961786aa76fac640d82ae94a53a096ce8694022713fdd9d8227ab71b1
|
| 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 Oct 27, 2026.
Transparency logSecurity for prebuttal 0.4.0
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
All 2 files in this release have been uploaded with provenance metadata.
Attestation for prebuttal-0.4.0.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 Oct 27, 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.