prebuttal 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. prebuttal-0.1.0/CHANGELOG.md +183 -0
  2. prebuttal-0.1.0/LICENSE +21 -0
  3. prebuttal-0.1.0/MANIFEST.in +6 -0
  4. prebuttal-0.1.0/PKG-INFO +407 -0
  5. prebuttal-0.1.0/README.md +370 -0
  6. prebuttal-0.1.0/SECURITY.md +90 -0
  7. prebuttal-0.1.0/prebuttal/__init__.py +7 -0
  8. prebuttal-0.1.0/prebuttal/__main__.py +6 -0
  9. prebuttal-0.1.0/prebuttal/cli.py +606 -0
  10. prebuttal-0.1.0/prebuttal/config.py +312 -0
  11. prebuttal-0.1.0/prebuttal/dryrun.py +79 -0
  12. prebuttal-0.1.0/prebuttal/ingestion/__init__.py +78 -0
  13. prebuttal-0.1.0/prebuttal/ingestion/arxiv.py +95 -0
  14. prebuttal-0.1.0/prebuttal/ingestion/latex.py +571 -0
  15. prebuttal-0.1.0/prebuttal/ingestion/pdf.py +456 -0
  16. prebuttal-0.1.0/prebuttal/keys.py +132 -0
  17. prebuttal-0.1.0/prebuttal/models.py +228 -0
  18. prebuttal-0.1.0/prebuttal/modelscan.py +274 -0
  19. prebuttal-0.1.0/prebuttal/orchestrator.py +490 -0
  20. prebuttal-0.1.0/prebuttal/pack.py +109 -0
  21. prebuttal-0.1.0/prebuttal/personas/__init__.py +26 -0
  22. prebuttal-0.1.0/prebuttal/personas/adversarial.md +11 -0
  23. prebuttal-0.1.0/prebuttal/personas/area_chair.md +11 -0
  24. prebuttal-0.1.0/prebuttal/personas/detail_obsessive.md +11 -0
  25. prebuttal-0.1.0/prebuttal/personas/paper_roast.md +10 -0
  26. prebuttal-0.1.0/prebuttal/personas/senior_kind.md +12 -0
  27. prebuttal-0.1.0/prebuttal/providers/__init__.py +96 -0
  28. prebuttal-0.1.0/prebuttal/providers/agent_cli.py +178 -0
  29. prebuttal-0.1.0/prebuttal/providers/api.py +244 -0
  30. prebuttal-0.1.0/prebuttal/providers/base.py +96 -0
  31. prebuttal-0.1.0/prebuttal/providers/detect.py +216 -0
  32. prebuttal-0.1.0/prebuttal/providers/ollama.py +69 -0
  33. prebuttal-0.1.0/prebuttal/providers/relay.py +108 -0
  34. prebuttal-0.1.0/prebuttal/py.typed +0 -0
  35. prebuttal-0.1.0/prebuttal/report.py +227 -0
  36. prebuttal-0.1.0/prebuttal/runs.py +305 -0
  37. prebuttal-0.1.0/prebuttal/share.py +152 -0
  38. prebuttal-0.1.0/prebuttal/venues/__init__.py +250 -0
  39. prebuttal-0.1.0/prebuttal/venues/forms/acl.md +34 -0
  40. prebuttal-0.1.0/prebuttal/venues/forms/iclr.md +26 -0
  41. prebuttal-0.1.0/prebuttal/venues/forms/icml.md +27 -0
  42. prebuttal-0.1.0/prebuttal/venues/forms/neurips.md +24 -0
  43. prebuttal-0.1.0/prebuttal.egg-info/PKG-INFO +407 -0
  44. prebuttal-0.1.0/prebuttal.egg-info/SOURCES.txt +68 -0
  45. prebuttal-0.1.0/prebuttal.egg-info/dependency_links.txt +1 -0
  46. prebuttal-0.1.0/prebuttal.egg-info/entry_points.txt +2 -0
  47. prebuttal-0.1.0/prebuttal.egg-info/requires.txt +11 -0
  48. prebuttal-0.1.0/prebuttal.egg-info/top_level.txt +1 -0
  49. prebuttal-0.1.0/pyproject.toml +95 -0
  50. prebuttal-0.1.0/scripts/calibration/calibrate.py +190 -0
  51. prebuttal-0.1.0/setup.cfg +4 -0
  52. prebuttal-0.1.0/tests/conftest.py +329 -0
  53. prebuttal-0.1.0/tests/fixtures/demo-paper.pdf +0 -0
  54. prebuttal-0.1.0/tests/test_calibration.py +23 -0
  55. prebuttal-0.1.0/tests/test_cli.py +339 -0
  56. prebuttal-0.1.0/tests/test_config.py +127 -0
  57. prebuttal-0.1.0/tests/test_confirm.py +147 -0
  58. prebuttal-0.1.0/tests/test_dryrun.py +48 -0
  59. prebuttal-0.1.0/tests/test_ingestion_latex.py +158 -0
  60. prebuttal-0.1.0/tests/test_ingestion_pdf.py +161 -0
  61. prebuttal-0.1.0/tests/test_keys.py +92 -0
  62. prebuttal-0.1.0/tests/test_modelscan.py +169 -0
  63. prebuttal-0.1.0/tests/test_orchestrator.py +111 -0
  64. prebuttal-0.1.0/tests/test_pack_parse.py +130 -0
  65. prebuttal-0.1.0/tests/test_pdf_regression.py +75 -0
  66. prebuttal-0.1.0/tests/test_providers.py +621 -0
  67. prebuttal-0.1.0/tests/test_relay.py +165 -0
  68. prebuttal-0.1.0/tests/test_report_share.py +94 -0
  69. prebuttal-0.1.0/tests/test_runs.py +173 -0
  70. prebuttal-0.1.0/tests/test_venues_personas.py +51 -0
@@ -0,0 +1,183 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ While pre-1.0: **patch** releases (0.1.x) are fixes and small additions; **minor**
9
+ releases (0.2, 0.3, …) are substantial new features.
10
+
11
+ ## [Unreleased]
12
+
13
+ ## [0.1.0] — 2026-10-25
14
+
15
+ First public release.
16
+
17
+ ### Security
18
+
19
+ - Prompt-injection hardening — the paper is untrusted input. `agent-claude`
20
+ now runs `claude -p --tools "" --strict-mcp-config` (no tools, no MCP),
21
+ `agent-codex` runs `codex exec --sandbox read-only --ignore-user-config
22
+ --ephemeral` (no user MCP servers, no session files holding the paper),
23
+ and both start in an empty temporary directory instead of your project. Every prompt fences the
24
+ paper in `<submission>…</submission>` as data and asks reviewers to report
25
+ embedded instructions as a weakness. An outdated CLI that rejects the new
26
+ flags fails fast with an "update the CLI" message. See SECURITY.md.
27
+ - Reports, JSON, share pages and run history no longer record the paper's
28
+ absolute local path (it leaked user names when shared); local sources are
29
+ shown relative to the working directory, else `~`, else by name.
30
+ - A `prebuttal.toml` merely found in the current directory can no longer run
31
+ its `[agents.*]` commands silently (it could, e.g. inside someone else's
32
+ paper repo): the commands are shown and need a yes; non-interactive runs
33
+ refuse unless the file is passed with `--config`.
34
+ - `~/.prebuttal` (run history with paper text, `keys.env`) is user-only
35
+ (0700); it used to be world-readable on shared machines.
36
+
37
+ ### Added
38
+
39
+ - Release workflow: pushing a `v*` tag builds, tests and publishes to PyPI
40
+ via Trusted Publishing (no API token stored anywhere).
41
+ - Python 3.14 and 3.15 in the CI matrix and classifiers; a CI job tests the
42
+ oldest supported dependency versions.
43
+ - Synthetic weak-paper example (`examples/weak-paper/`, fictional, deliberately
44
+ flawed) with a real 1/10 run, published on the site; real-paper sample pages
45
+ carry an "unofficial, not endorsed by the authors" banner with CC BY 4.0
46
+ attribution.
47
+ - GitHub Pages site (`site/`): landing page + curated sample reports (the
48
+ Mamba and DPO full runs, regenerated from run history by
49
+ `scripts/build_site.py`), deployed by the standard `pages` workflow —
50
+ enable once in repo Settings → Pages → Source: GitHub Actions. The web
51
+ quick-scan (drag-drop PDF + BYOK key, browser-only) is a v0.2+ roadmap
52
+ item; hosted/public review services are explicitly out of scope.
53
+ - Privacy & data-custody disclaimer (README "Honesty & policy" + SECURITY.md):
54
+ manuscript text sent to a backend is governed solely by that provider's
55
+ terms; Prebuttal is an integration layer, not a data custodian. Local-only
56
+ paths (`ollama`, `relay`) and what the tool itself stores (local disk only)
57
+ are spelled out.
58
+ - `api-openrouter` backend: one OPENROUTER_API_KEY, hundreds of models,
59
+ OpenAI-compatible wire format (attribution headers sent; JSON mode not
60
+ forced since many OpenRouter models reject it). Default is a `:free` model
61
+ (google/gemma-4-31b-it:free, non-reasoning — reasoning models on the free
62
+ tier can spend the whole token budget on hidden thinking and return no
63
+ content; that case now fails fast with an actionable error instead of
64
+ retrying) so the zero-cost story holds; `:free`
65
+ ids show as $0 in `--dry-run`. `prebuttal key set openrouter` stores the
66
+ key. `prebuttal models` scans OpenRouter's public catalog with no key at
67
+ all — free ids first with live per-1M prices, then curated notables — and
68
+ the reviewer wizard accepts typing any custom model id. Free-tier
69
+ resilience: `:free` reviewers dispatch staggered a few seconds apart and
70
+ saturation-style throttling (HTTP 429) backs off on a long curve
71
+ (15/30/60s per call) since shared free pools stay closed for minutes.
72
+ - Interactive plan confirmation for auto mode: on a terminal, `prebuttal run`
73
+ shows the full review plan (personas, backends, models, cost) before calling
74
+ anything — `[Enter]` runs, `[e]` opens a numbered-menu wizard (persona →
75
+ backend → live model list from `prebuttal models`), `[n]` aborts.
76
+ Non-interactive contexts (CI, pipes) print the plan and proceed; `-y` /
77
+ `--yes` silences; fully-explicit configs never prompt. `--dry-run` plans now
78
+ show personas too, and backends registered via `register_backend` are
79
+ eligible for auto assignment.
80
+ - `PREBUTTAL_BACKEND` environment variable: force one backend for every
81
+ reviewer and the AC (e.g. `relay` for agent-subagent reviewing);
82
+ precedence `--backend` > `PREBUTTAL_BACKEND` > `prebuttal.toml`.
83
+ - Inside a coding agent (Claude Code, Gemini CLI), `prebuttal run` and
84
+ `prebuttal backends` print a hint pointing at relay mode.
85
+ - `prebuttal models` — live model discovery per backend: scans the Gemini /
86
+ OpenAI / Anthropic model-list endpoints and Ollama's installed models
87
+ (non-chat ids filtered out), shows the claude CLI aliases, marks the current
88
+ default with `*`, and prints a copy-paste `model = "..."` toml example.
89
+ - `prebuttal key set/status/unset` — quick API-key setup: hidden-input prompt,
90
+ stored in `~/.prebuttal/keys.env` (user-only, env vars take precedence);
91
+ `prebuttal backends` and runs pick stored keys up automatically.
92
+ - Type checking: mypy (CI-enforced) and `py.typed` marker for downstream users.
93
+ - Regression fixture: a real pdflatex-compiled PDF locks ingestion behavior
94
+ (wrapped titles, separate number/title heading lines, kerned decimals).
95
+ - README reference: environment variables, exit codes, skill installation.
96
+ - OpenAI/Anthropic request-shape tests and the Windows `cmd /c` agent-CLI
97
+ fallback test; calibration parser unit tests.
98
+ - `prebuttal run` — review a paper from a PDF file, a LaTeX project directory,
99
+ or an arXiv link/id, against the real review form of NeurIPS, ICLR, ICML or
100
+ ACL Rolling Review (official scales and anchors; forms are plain-text and
101
+ community-editable).
102
+ - Three independent-context reviewers + an area chair, fanned out in parallel;
103
+ score aggregation with disagreement (σ, range) and per-review backend/model
104
+ transparency in every report.
105
+ - Ingestion pipeline: LaTeX parsing with cell-accurate `tabular` extraction
106
+ (`\multicolumn` expansion, `\label`/`\ref` resolution, appendix numbering,
107
+ `.bbl` references), PDF parsing with ruled-table detection and
108
+ caption-block fallback, arXiv download with metadata title.
109
+ - Reviewer pack with budget policy: abstract and all tables are never
110
+ truncated; optional LLM compression (`compress = true`) for elided sections.
111
+ - Provider layer with startup auto-detection: `agent-claude` (`claude -p`),
112
+ `agent-codex` (`codex exec`), `api-gemini` / `api-openai` / `api-anthropic`,
113
+ local `ollama`, the file-protocol `relay` backend (human / host-agent
114
+ subagents / external systems as responders), and custom `[agents.<name>]`
115
+ CLI backends.
116
+ - Outputs: venue-format Markdown report, machine-readable `--json`,
117
+ self-contained `--share` HTML page, `--dry-run` cost/backend matrix.
118
+ - Personas: `senior_kind`, `adversarial`, `detail_obsessive`, `area_chair`,
119
+ and the `paper_roast` easter egg.
120
+ - `prebuttal.toml` configuration (per-reviewer persona × backend × model ×
121
+ temperature × seed), `prebuttal init`, `prebuttal backends`.
122
+ - Agent skill (`skills/prebuttal/SKILL.md`) including relay mode.
123
+ - Calibration pipeline (`scripts/calibration/`): predicted vs true OpenReview
124
+ ratings, scatter plot + MAE.
125
+ - Run history: every run archived under `~/.prebuttal` (reports, JSON, resolved
126
+ config; best-effort, `--no-save` to opt out) with `prebuttal runs` / `show` /
127
+ `diff` — score deltas and weakness movement (gone / persists / new) across
128
+ revisions.
129
+
130
+ ### Changed
131
+
132
+ - **PDF parsing moved from PyMuPDF (AGPL-3.0) to pdfminer.six + pdfplumber
133
+ (MIT)**, so installing the MIT-licensed package no longer pulls in a
134
+ copyleft dependency. Booktabs-style tables (horizontal rules only) get a
135
+ dedicated detector; cell-accurate numbers, two-column layout and the real
136
+ LaTeX regression fixture are covered by tests.
137
+ - Wording: scores are no longer described as "calibrated" — the calibration
138
+ pipeline ships, published results are pending.
139
+ - README installs with plain `pip install prebuttal` (pipx / `uv tool` as
140
+ the isolated alternative); share pages and the site say the same.
141
+ - Classifier `Development Status :: 3 - Alpha` (was Beta) to match pre-release.
142
+ - Machine-specific scripts moved to the gitignored `scripts/dev/`.
143
+ - Default models brought up to the current mid-tier generation (verified
144
+ against live model listings, 2026-10): `api-gemini` → **gemini-3.5-flash-lite**
145
+ (latest flash-lite; cheapest long-context tier for the free-quota path),
146
+ `api-openai` → **gpt-5.6-terra** (the GPT-5.6 balanced tier),
147
+ `api-anthropic` → **claude-sonnet-5-5**. Old ids still work when pinned
148
+ explicitly; pricing table extended accordingly. `prebuttal models` filters
149
+ more non-chat noise (gemma / lyria / omni / robotics / nano-banana).
150
+
151
+ ### Fixed
152
+
153
+ - Windows: redirected output (`> log.txt`, pipes, CI) no longer crashes with
154
+ `UnicodeEncodeError`; stdout/stderr are switched to UTF-8.
155
+ - The sdist now carries `tests/conftest.py`, the PDF fixture and the
156
+ calibration script, so the test suite runs from the source tarball.
157
+ - `--out` / `--json` in a directory that doesn't exist yet no longer crashes
158
+ after the reviews ran; parent dirs are created, and the run is archived
159
+ before the outputs are written so a write error can't lose a paid review.
160
+ - arXiv downloads are streamed and capped at 100 MB.
161
+ - The relay spool directory writes its own `.gitignore` (it holds paper text).
162
+ - Per-reviewer `model` now actually reaches agent-CLI backends
163
+ (`claude -p --model X`, `codex exec --model X`); previously it was recorded
164
+ in reports but never passed to the CLI.
165
+ - Auto mode no longer assigns reviewers to `relay` (which waited up to 30 min
166
+ for a hand-written answer): relay is now explicit-only (`--backend relay`),
167
+ and with no automatic backend `prebuttal run` exits 3 with guidance.
168
+ - Agent CLIs are launched via the path `prebuttal backends` detected, so
169
+ npm-installed `claude.cmd` / `codex.cmd` work on Windows.
170
+ - API keys loaded from `~/.prebuttal/keys.env` are no longer passed to agent
171
+ CLIs (a stored `ANTHROPIC_API_KEY` switched `claude -p` from subscription
172
+ auth to API billing).
173
+ - LaTeX: `table*` / `figure*` were captured twice (duplicate tables, shifted
174
+ numbers, wrong `\ref`); `tabular*` leaked its column spec into the first
175
+ cell; nested `\input` now resolves from the root directory like LaTeX, and
176
+ unresolvable inputs produce an ingestion warning instead of vanishing.
177
+ - PDF ingestion on real LaTeX output: wrapped titles now join into one title,
178
+ section numbers separated from their titles merge back (side-by-side or
179
+ stacked), and table cells are rebuilt from word geometry so kerned decimals
180
+ survive (`47.9` no longer reads `479 .`; negative deltas keep their sign).
181
+
182
+ [Unreleased]: https://github.com/GuoYuKai-SaMuEl/prebuttal/compare/v0.1.0...HEAD
183
+ [0.1.0]: https://github.com/GuoYuKai-SaMuEl/prebuttal/releases/tag/v0.1.0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Prebuttal contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ # sdist extras: everything the test suite needs, so packagers (conda-forge,
2
+ # distros) can run `pytest` from the source tarball. The wheel is unaffected.
3
+ include CHANGELOG.md SECURITY.md
4
+ include tests/conftest.py
5
+ recursive-include tests/fixtures *.pdf
6
+ include scripts/calibration/calibrate.py
@@ -0,0 +1,407 @@
1
+ Metadata-Version: 2.4
2
+ Name: prebuttal
3
+ Version: 0.1.0
4
+ Summary: Pre-submission review stress test for ML papers: three independent AI reviewers + an area chair, real conference review forms, measured disagreement.
5
+ Author: Prebuttal contributors
6
+ Maintainer: GuoYuKai-SaMuEl
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/GuoYuKai-SaMuEl/prebuttal
9
+ Project-URL: Issues, https://github.com/GuoYuKai-SaMuEl/prebuttal/issues
10
+ Project-URL: Changelog, https://github.com/GuoYuKai-SaMuEl/prebuttal/blob/main/CHANGELOG.md
11
+ Keywords: peer-review,neurips,iclr,icml,acl,reviewer2,llm,arxiv,papers
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Python :: 3.15
22
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
23
+ Classifier: Topic :: Text Processing :: Markup :: LaTeX
24
+ Requires-Python: >=3.11
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: pdfplumber>=0.11.0
28
+ Requires-Dist: pdfminer.six>=20231228
29
+ Requires-Dist: httpx>=0.27
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=8; extra == "dev"
32
+ Requires-Dist: reportlab>=4; extra == "dev"
33
+ Provides-Extra: calibration
34
+ Requires-Dist: openreview>=1.42; extra == "calibration"
35
+ Requires-Dist: matplotlib>=3.8; extra == "calibration"
36
+ Dynamic: license-file
37
+
38
+ # Prebuttal
39
+
40
+ > **Answer Reviewer 2 before Reviewer 2 exists.**
41
+
42
+ [![CI](https://github.com/GuoYuKai-SaMuEl/prebuttal/actions/workflows/ci.yml/badge.svg)](https://github.com/GuoYuKai-SaMuEl/prebuttal/actions/workflows/ci.yml)
43
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/GuoYuKai-SaMuEl/prebuttal/blob/main/LICENSE)
44
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://github.com/GuoYuKai-SaMuEl/prebuttal/blob/main/pyproject.toml)
45
+ [![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-261230.svg)](https://github.com/astral-sh/ruff)
46
+
47
+ [![View a sample report](https://img.shields.io/badge/%E2%96%B6_View_sample-report-2ea44f?style=for-the-badge)](https://github.com/GuoYuKai-SaMuEl/prebuttal/blob/main/examples/sample-report.md)
48
+ [![Share page](https://img.shields.io/badge/Share_page-5087d2?style=for-the-badge)](https://guoyukai-samuel.github.io/prebuttal/reports/sample.html)
49
+ [![Website](https://img.shields.io/badge/Website-5087d2?style=for-the-badge&logo=github&logoColor=white)](https://guoyukai-samuel.github.io/prebuttal/)
50
+
51
+ **Purpose-built for ML conferences: real NeurIPS / ICLR / ICML / ARR review-form
52
+ output, three reviewers running in fully independent contexts (optionally
53
+ cross-model), and a built-in pipeline to measure its scores against real
54
+ OpenReview ratings.**
55
+
56
+ Prebuttal is a pre-submission **stress test** for your paper: it sends your
57
+ submission through three isolated AI reviewers with different temperaments
58
+ plus an area chair, and hands you a conference-format review report — scores,
59
+ disagreement, weaknesses with citations to your own tables — *before* the real
60
+ Reviewers 1–3 see it. See a synthetic sample:
61
+ [report](https://github.com/GuoYuKai-SaMuEl/prebuttal/blob/main/examples/sample-report.md) ·
62
+ [share page](https://guoyukai-samuel.github.io/prebuttal/reports/sample.html) — or what a deliberately flawed
63
+ (fictional) paper gets: [1/10 report](https://github.com/GuoYuKai-SaMuEl/prebuttal/blob/main/examples/weak-paper-report.md).
64
+
65
+ ---
66
+
67
+ ## Why not just paste the paper into ChatGPT?
68
+
69
+ That is the main competitor. It loses, four ways:
70
+
71
+ | Paste into ChatGPT | Prebuttal |
72
+ |---|---|
73
+ | 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 |
74
+ | 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* |
75
+ | 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 |
76
+ | Scores are vibes | Fixed seeds, recorded backends/models per reviewer, and a **calibration script** to measure scores against real OpenReview ratings (published results pending) |
77
+
78
+ ## Quickstart
79
+
80
+ ```bash
81
+ pip install prebuttal
82
+
83
+ prebuttal run paper.pdf --venue iclr
84
+ prebuttal run https://arxiv.org/abs/2510.12345 --venue neurips
85
+ prebuttal run ./latex-src/ --venue acl
86
+ ```
87
+
88
+ Prefer an isolated install for command-line tools? `pipx install prebuttal`
89
+ or `uv tool install prebuttal` work the same way (or `uvx prebuttal ...` to
90
+ run without installing). Requires Python 3.11+.
91
+
92
+ The first run costs **zero setup** if you already have a subscription CLI or
93
+ Ollama — Prebuttal auto-detects the cheapest path at startup and prints what it
94
+ chose (`prebuttal backends` to inspect):
95
+
96
+ | Backend | Auth | Notes |
97
+ |---|---|---|
98
+ | `agent-claude` (`claude -p`) | your Claude subscription, **zero API key** | preferred reviewer |
99
+ | `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](https://github.com/GuoYuKai-SaMuEl/prebuttal/blob/main/SECURITY.md)) |
100
+ | `api-gemini` | GEMINI_API_KEY | **free tier** — the cheapest "first key" path |
101
+ | `api-openai` / `api-anthropic` | OPENAI_API_KEY / ANTHROPIC_API_KEY | BYO key |
102
+ | `api-openrouter` | OPENROUTER_API_KEY | one key, hundreds of models — **`:free` ids cost nothing** (default is one); prices shown live in `prebuttal models` |
103
+ | `ollama` | none | local & private — *unpublished papers never leave your machine* (with the default localhost host) |
104
+ | `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) |
105
+
106
+ **Unpublished manuscript?** The text is sent to the backend's provider, and
107
+ what happens to it there is that provider's privacy policy, not ours — see
108
+ [Privacy & data custody](#privacy--data-custody). For local-only review use
109
+ `ollama` or `relay`.
110
+
111
+ > ⚠️ **Free tiers are usually paid for with your data.** Free API tiers (the
112
+ > Gemini free tier, OpenRouter `:free` models and their upstream providers)
113
+ > may let the provider log, review or train on what you send. They are fine
114
+ > for published papers and trying the tool out — for an unpublished
115
+ > manuscript, check the provider's current terms, use a paid tier, or stay
116
+ > local.
117
+
118
+ Useful flags:
119
+
120
+ ```bash
121
+ prebuttal run paper.pdf --venue neurips --dry-run # cost + plan preview, calls nothing
122
+ prebuttal run paper.pdf --venue iclr --json out.json --share # machine output + share page
123
+ prebuttal run paper.pdf --seed 42 # reproducible
124
+ prebuttal run paper.pdf -y # skip the plan confirmation
125
+ ```
126
+
127
+ In auto mode on a terminal, Prebuttal shows the review plan before calling
128
+ anything — press Enter to run, `e` to re-pick each reviewer's persona, backend
129
+ and model via numbered menus, or `n` to abort. CI and pipes get the plan
130
+ printed and proceed automatically; fully-explicit configs never prompt.
131
+
132
+ `prebuttal models` lists every backend's actually-available models (live API
133
+ scan + installed Ollama models + claude aliases) with the current default
134
+ marked — pick one and set `model = "..."` per reviewer in prebuttal.toml.
135
+ Built-in defaults are mid-tier models current at release time and change
136
+ between versions — providers retire model ids quickly, so if a default stops
137
+ working, upgrade prebuttal or pin a model yourself.
138
+
139
+ ## The reviewers
140
+
141
+ | id | Persona | Behavior |
142
+ |---|---|---|
143
+ | R1 | `senior_kind` | senior, constructive; core contribution + main concerns, grounded |
144
+ | R2 | `adversarial` | *Reviewer 2 in the flesh*: motivation, baselines, novelty, overclaiming |
145
+ | R3 | `detail_obsessive` | reads every table cell; statistics, ablations, reproducibility |
146
+ | AC | `area_chair` | meta-review, adjudicates disagreement, estimates the final rating |
147
+
148
+ Every persona enforces the same protocol: **cite the evidence** (section,
149
+ table, number) or the point doesn't count; use the full scale; JSON-only
150
+ output. There is also an easter-egg roast persona (`persona = "paper_roast"`)
151
+ for when you need the truth *fast*.
152
+
153
+ Personas live in [`prebuttal/personas/`](https://github.com/GuoYuKai-SaMuEl/prebuttal/tree/main/prebuttal/personas) and venue forms in
154
+ [`prebuttal/venues/forms/`](https://github.com/GuoYuKai-SaMuEl/prebuttal/tree/main/prebuttal/venues/forms) — plain text files, PRs
155
+ welcome (scale wording drifts every year; keep it current).
156
+
157
+ ## Configuration
158
+
159
+ `prebuttal init` writes a commented `prebuttal.toml`. Per-reviewer backends,
160
+ models and temperatures:
161
+
162
+ ```toml
163
+ [default]
164
+ venue = "iclr"
165
+ seed = 42
166
+
167
+ [[reviewer]]
168
+ id = "R1"
169
+ persona = "senior_kind"
170
+ backend = "agent-claude" # claude -p, subscription auth
171
+ temperature = 0.4
172
+
173
+ [[reviewer]]
174
+ id = "R2"
175
+ persona = "adversarial"
176
+ backend = "agent-codex" # codex exec, subscription auth
177
+ model = "gpt-5.1" # optional: forwarded as --model (agent CLIs too)
178
+ temperature = 0.7
179
+
180
+ [[reviewer]]
181
+ id = "R3"
182
+ persona = "detail_obsessive"
183
+ backend = "api-gemini" # free tier; default model gemini-3.5-flash-lite
184
+ temperature = 0.5
185
+
186
+ [ac]
187
+ persona = "area_chair"
188
+ backend = "agent-claude"
189
+ ```
190
+
191
+ ## Calibration (honesty, not prophecy)
192
+
193
+ Scores are meaningless unless measured. The calibration pipeline runs Prebuttal
194
+ on papers that **already have real OpenReview reviews** and plots predicted vs
195
+ true mean ratings:
196
+
197
+ The script lives in the repository (it is not part of the pip package), so
198
+ run it from a clone:
199
+
200
+ ```bash
201
+ git clone https://github.com/GuoYuKai-SaMuEl/prebuttal && cd prebuttal
202
+ pip install -e ".[calibration]"
203
+ python scripts/calibration/calibrate.py \
204
+ --venue-id ICLR.cc/2024/Conference --venue iclr -n 20 --out-dir calib_out
205
+ ```
206
+
207
+ Output: scatter plot + MAE + correlation. **No calibration results are
208
+ published yet** — until they are, treat every score as uncalibrated. Once
209
+ published, the claim they support is narrow
210
+ and deliberate: *this tool was measured* — unlike role-play prompts. It is
211
+ **not** a claim that it predicts your score; real reviewers disagree with each
212
+ other by more than this tool's error. Disagreement (σ) is reported with every
213
+ aggregate for exactly that reason.
214
+
215
+ ## Run history & revision diffing
216
+
217
+ Every run is archived automatically (best-effort, never blocks a review) under
218
+ `~/.prebuttal/` — reports, JSON, and the resolved config (backends, models,
219
+ seeds) for exact reproduction:
220
+
221
+ ```bash
222
+ prebuttal runs # list archived runs
223
+ prebuttal show <run-id-prefix> # re-read a report (--json for the data)
224
+ prebuttal diff <old> <new> # ratings A→B + weakness movement
225
+ ```
226
+
227
+ `diff` is the revision loop: fix what the reviewers flagged, re-run with the
228
+ same `--seed`, and see which weaknesses went away, persisted, or appeared.
229
+ Basic usage is unchanged — archiving is silent, `--no-save` opts out.
230
+
231
+ ## Skill package
232
+
233
+ [`skills/prebuttal/SKILL.md`](https://github.com/GuoYuKai-SaMuEl/prebuttal/blob/main/skills/prebuttal/SKILL.md) teaches any agent to
234
+ drive the CLI and interpret the JSON — including relay mode (the reviewers are
235
+ the agent's own subagents) and the `runs`/`diff` revision loop. The skill file
236
+ is explicit about the one rule that matters: the agent must **run the CLI**,
237
+ never role-play the reviewers itself.
238
+
239
+ When the CLI detects it is running inside a coding agent (currently Claude
240
+ Code and Gemini CLI), `prebuttal run` and `prebuttal backends` print a one-line
241
+ hint pointing at relay mode. An agent environment that should always use its
242
+ own subagents can pin it once with `PREBUTTAL_BACKEND=relay`. Relay is never
243
+ chosen automatically: the CLI has to run in the background while the agent
244
+ answers the requests, or both sides wait on each other.
245
+
246
+ Install it into your agent's skills directory — for Claude Code:
247
+
248
+ ```bash
249
+ mkdir -p ~/.claude/skills/prebuttal && curl -fsSL -o ~/.claude/skills/prebuttal/SKILL.md \
250
+ https://raw.githubusercontent.com/GuoYuKai-SaMuEl/prebuttal/main/skills/prebuttal/SKILL.md
251
+ # or, from a clone: cp -r skills/prebuttal ~/.claude/skills/
252
+ ```
253
+
254
+ Other agents (ZCode, Codex, …): copy or symlink `skills/prebuttal/` wherever
255
+ your agent discovers skills (see its docs), or reference the file from your
256
+ `AGENTS.md` / system prompt.
257
+
258
+ ## Reference
259
+
260
+ ### Environment variables
261
+
262
+ **API keys** — two ways, pick either:
263
+
264
+ ```bash
265
+ prebuttal key set gemini # quick setup: hidden prompt, stored for next time
266
+ # or the classic way: set GEMINI_API_KEY / OPENAI_API_KEY / ANTHROPIC_API_KEY yourself
267
+ ```
268
+
269
+ Stored keys live in `~/.prebuttal/keys.env` (user-only permissions, like
270
+ `~/.aws/credentials`); real environment variables always take precedence, so
271
+ CI setups are unaffected. `prebuttal key status` shows what's set (masked),
272
+ `prebuttal key unset <name>` removes one.
273
+
274
+ | Variable | Purpose |
275
+ |---|---|
276
+ | `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `GEMINI_API_KEY` (or `GOOGLE_API_KEY`) / `OPENROUTER_API_KEY` | enable the matching API backend |
277
+ | `OPENAI_BASE_URL` | point `api-openai` at an OpenAI-compatible proxy |
278
+ | `PREBUTTAL_OPENAI_MODEL` / `PREBUTTAL_ANTHROPIC_MODEL` / `PREBUTTAL_GEMINI_MODEL` / `PREBUTTAL_OPENROUTER_MODEL` | override each backend's default model |
279
+ | `PREBUTTAL_OLLAMA_HOST` (or `OLLAMA_HOST`) | Ollama base URL (default `http://localhost:11434`) |
280
+ | `PREBUTTAL_BACKEND` | force one backend for every reviewer + the AC (e.g. `relay`); `--backend` still wins, `prebuttal.toml` loses |
281
+ | `PREBUTTAL_HOME` | run-history and key storage location (default `~/.prebuttal`) |
282
+
283
+ API keys are only read from the environment or `keys.env` — never written to
284
+ reports, JSON, or share pages.
285
+
286
+ ### Exit codes
287
+
288
+ | Code | Meaning |
289
+ |---|---|
290
+ | 0 | success |
291
+ | 2 | bad usage / config error / paper not found / unknown run id |
292
+ | 3 | no review backend available |
293
+ | 4 | partial failure (some reviewers or the AC failed; report still written) |
294
+ | 5 | every reviewer failed |
295
+ | 130 | interrupted (Ctrl+C) |
296
+
297
+ ## Comparison
298
+
299
+ What Prebuttal provides, next to the common alternatives (by category —
300
+ check any specific tool's own docs for what it supports):
301
+
302
+ | Approach | Form | Venue forms | Calibration | Cross-model | Tables in-pipeline |
303
+ |---|---|---|---|---|---|
304
+ | **Prebuttal** | CLI + skill | NeurIPS / ICLR / ICML / ARR (editable plain text) | OpenReview script (scatter + MAE; results pending) | claude × codex × API × ollama | cell-by-cell |
305
+ | generic "review my paper" agent skills / prompts | agent skill | varies | rarely | single model | via the host model |
306
+ | multi-agent peer-review research frameworks | research code | study-specific | study-specific | sometimes | rarely |
307
+ | paste into a chatbot | chat | ✗ | ✗ | ✗ | ✗ |
308
+
309
+ ## How it works
310
+
311
+ ```
312
+ PDF / LaTeX dir / arXiv link
313
+ └─ ingestion: sections, cell-accurate tables, figure captions, refs
314
+ └─ reviewer pack (budget-aware; tables are never truncated)
315
+ ├─ R1 senior_kind ──┐ three independent contexts,
316
+ ├─ R2 adversarial ──┤ parallel fan-out, venue form + JSON schema
317
+ ├─ R3 detail_obsessive ─┤
318
+ └─ AC area chair ◄──┘ meta-review + estimated rating + disagreement
319
+ └─ Markdown report · --json · --share page
320
+ ```
321
+
322
+ Orchestration lives in the CLI, not the host agent — the same pipeline runs
323
+ from a terminal, from inside any coding agent, or in CI.
324
+
325
+ ## Roadmap & versioning
326
+
327
+ Versioning policy while pre-1.0: **patch** releases (0.1.1, 0.1.2, …) are
328
+ fixes and small additions; **minor** releases (0.2, 0.3, …) are substantial
329
+ new features; 1.0 only once the interface is battle-tested.
330
+
331
+ Tentative — priorities shift with usage and feedback. Short-term the focus
332
+ is **hardening the core on real papers**, not adding features:
333
+
334
+ 1. **v0.1 (current, pre-release)** — core: ingestion pipeline, real venue
335
+ forms, 3 independent reviewers + AC, every backend (agent CLIs / APIs /
336
+ Ollama / relay), reports + JSON + share page, calibration script
337
+ 2. **Now (v0.1.x)** — polish from real-usage findings: table & ingestion
338
+ edge cases (complex PDF tables), calibration scatter plot + honest
339
+ per-model calibration notes, provider-reliability UX (free-pool reality,
340
+ retry transparency), relay UX
341
+ 3. **Next (v0.2+)** — more venues, community personas, OpenReview
342
+ submission integration, and a browser-only web quick-scan (GitHub Pages:
343
+ drag-drop a PDF + your own OpenRouter/Gemini key — no server, we stay a
344
+ non-custodian); then the rebuttal workbench (reviews →
345
+ point-by-point response letter) and "CI for papers" (GitHub Action:
346
+ \ref/\label checks, citation sanity)
347
+ 4. **Eventually** — the calibration script becomes a public benchmark /
348
+ leaderboard: tools depreciate, benchmarks appreciate.
349
+
350
+ ## Develop
351
+
352
+ ```bash
353
+ git clone https://github.com/GuoYuKai-SaMuEl/prebuttal && cd prebuttal
354
+ python -m venv .venv && .venv/Scripts/pip install -e ".[dev]" # Windows
355
+ .venv/bin/pip install -e ".[dev]" # macOS/Linux
356
+ pytest -q
357
+ ```
358
+
359
+ Contributions welcome — the easiest ones are venue forms, personas, and
360
+ backends; see [CONTRIBUTING.md](https://github.com/GuoYuKai-SaMuEl/prebuttal/blob/main/CONTRIBUTING.md) for the three-step guide.
361
+ Also read [CHANGELOG.md](https://github.com/GuoYuKai-SaMuEl/prebuttal/blob/main/CHANGELOG.md), [SECURITY.md](https://github.com/GuoYuKai-SaMuEl/prebuttal/blob/main/SECURITY.md), and our
362
+ [Code of Conduct](https://github.com/GuoYuKai-SaMuEl/prebuttal/blob/main/CODE_OF_CONDUCT.md).
363
+
364
+ ## Honesty & policy
365
+
366
+ - Prebuttal **labels every review** with the backend and model that produced it.
367
+ - It reports score **disagreement**, always. High σ is information.
368
+ - It is a stress test, **not** a predictor — the report footer says so, every time.
369
+ - Mind conference policies: with [NeurIPS 2026 running an official AI-assisted
370
+ reviewing experiment](https://neurips.cc/Conferences/2026/ai-reviewing-experiment),
371
+ the etiquette is clear — AI to *prepare* your own paper is yours to decide;
372
+ AI to *review* others' papers must follow each venue's disclosure rules.
373
+
374
+ ### Privacy & data custody
375
+
376
+ - **Your paper's text goes to whatever backend you configure.** With API or
377
+ agent-CLI backends the manuscript is transmitted to that provider — and
378
+ OpenRouter further routes each request to a third-party upstream provider.
379
+ What happens to the text there (retention, training use, human review) is
380
+ governed **solely by each provider's terms and privacy policy**, not by
381
+ Prebuttal.
382
+ - **Prebuttal is an integration layer, not a data custodian.** This project
383
+ operates no models and runs no servers; we never see your paper. For
384
+ unpublished results, check the backend provider's data-use terms before
385
+ sending — provider-side handling of your data is the provider's
386
+ responsibility, not this project's.
387
+ - **Free tiers deserve extra care**: free API tiers (e.g. Gemini's free
388
+ tier, OpenRouter `:free` models) may allow logging or training on inputs;
389
+ paid tiers usually don't. Read the terms before sending unpublished work.
390
+ - **Local-only is a first-class path**: `ollama` never sends text off your
391
+ machine (as long as `PREBUTTAL_OLLAMA_HOST` / `OLLAMA_HOST` point at
392
+ localhost — a remote Ollama server receives the paper like any API), and
393
+ `relay` leaves who answers entirely to you.
394
+ - **What Prebuttal itself stores stays on your disk**: run history (pack
395
+ text, raw outputs, resolved config) under `~/.prebuttal/runs/` and keys in
396
+ `~/.prebuttal/keys.env` (user-only). No telemetry. Note reports and share
397
+ pages contain excerpts of your paper — sharing them publishes those
398
+ excerpts.
399
+
400
+ ## License & trademarks
401
+
402
+ Prebuttal is an independent project, not affiliated with or endorsed by
403
+ NeurIPS, ICLR, ICML, ACL/ARR or any model provider. Venue names are used only
404
+ to describe which review form a report follows; the forms are paraphrased
405
+ summaries of the public reviewer guidelines.
406
+
407
+ MIT