Copy for Originals · Original research
AI research tools now write a sourced report in minutes. Checking whether the sources say what the report says still takes a person most of a day. We built a checker that does the first pass on an ordinary laptop, with nothing sent to an AI company, and published it as open source. We tested it on 340 claims, 235 of them damaged on purpose, and then pointed it at research notes of our own that were already on this site. It caught most of the planted errors. In our own notes it led us to 36 claims that were wrong or not in their sources, and we have corrected them.
It reads a report from ChatGPT, Claude, Gemini, Perplexity or an open-source research agent, fetches every page the report cites, and keeps a copy of each. Then it runs three checks.
Everything runs on the user’s own machine or servers, with any model behind an OpenAI-compatible endpoint (llama.cpp, Ollama, vLLM, LM Studio). The code is at github.com/jbastide/receipts under the Apache 2.0 licence.
We started from 105 claims in our earlier study of AI research runs that two graders had accepted and whose quotes were on the cited page. Each was checked as written, where it should pass, and in up to four damaged versions, where it should be flagged: one number changed, the first verb negated, the claim checked against a page from another website, or an invented fact added (“according to a 2019 survey of 4,000 law firms”). 17 negations of claims that were already negative made nonsense and are left out.
| Method | Correct passed | A number changed | A verb negated | Checked against another site’s page | An invented fact added | All errors caught | Seconds per claim |
|---|---|---|---|---|---|---|---|
| MiniCheck (770M checker model) | 84 of 105 | 28 of 40 | 29 of 35 | 76 of 80 | 79 of 80 | 212 of 235 (90%) | 0.7 |
| HHEM-2.1-Open (checker model) | 86 of 105 | 29 of 40 | 12 of 35 | 77 of 80 | 73 of 80 | 191 of 235 (81%) | 0.2 |
| Gemma 4 12B as judge | 94 of 105 | 35 of 40 | 29 of 35 | 79 of 80 | 79 of 80 | 222 of 235 (94%) | 9.9 |
| Gemma 4 12B judge, dense claims split | 92 of 105 | 34 of 40 | 30 of 35 | 79 of 80 | 78 of 80 | 221 of 235 (94%) | 12.7 |
| MiniCheck or the judge flags it | 78 of 105 | 37 of 40 | 33 of 35 | 79 of 80 | 80 of 80 | 229 of 235 (97%) | 10.6 |
Splitting long claims into single facts made no difference here, because each planted error sits in one fact. It matters on real reports, where one sentence can carry five figures and the reader needs to know which one fails.
| Passed | Check by hand | Flagged | |
|---|---|---|---|
| 105 correct claims | 78 | 18 | 9 |
| 235 damaged claims | 6 | 17 | 212 |
We ran it on the research notes behind our page How AI agents choose products: 112 claims citing 87 sources, most of them academic papers. The checker flagged 4 quotes that were not on their pages and 137 facts with figures it could not confirm. Each flagged item was then checked against its source, reading the paper or page itself.
| Result | Items |
|---|---|
| Correct: the source says it | 91 |
| Wrong: the source says something different | 21 |
| Not in any source the claim cites | 15 |
| Right, but on another page the claim cites | 7 |
| The report’s own reasoning, not a sourced fact | 6 |
| Source could not be read | 1 |
So roughly one flag in four pointed at a real problem. That is the honest description of what a local checker does with dense research prose today: it cannot tell a missed sentence from a missing fact, but it turns a reading of 87 sources into a list of 141 places to look. Some of what it found:
The published page had been checked before it went live and already used the sources’ wording. The research notes behind it had not. We corrected them: 30 edits from the flagged items and 7 more found while reviewing them. Afterwards every quote in the notes was on its cited page.
On a Mac or Linux machine with uv installed and a local model server running:
git clone https://github.com/jbastide/receipts
cd receipts
uv sync --extra support
uv run receipts check report.md --judge-url http://127.0.0.1:8080/v1
It writes a readable report, a JSON file and a CSV. The quote and link checks work without any model: uv run receipts check report.md.
Mostly, if it is used as a judge rather than as the last word. In a Copy for Originals test, Gemma 4 12B running on a MacBook Air with 16 GB of memory caught 222 of 235 claims we had deliberately damaged (94%) and passed 94 of 105 correct ones (90%), at about ten seconds a claim. Paired with a smaller checker model, 6 of the 235 damaged claims got through without a flag.
Fetch every cited page and look for each quoted passage in it, ignoring spacing, punctuation and case. That needs no AI model. Copy for Originals’ checker reproduced all 593 quote grades from an earlier study this way, and when one word in each quote was replaced, none of 588 damaged quotes was accepted. A quote that is on the page can still fail to support the claim made with it, so the claim needs a second check.
In our own published research notes on how AI shopping agents choose products, the checker flagged 141 items. A source-by-source review found 36 of them wrong or not in any cited source: paraphrases inside quotation marks, a range reported as +19.75 to +23.38 points that the paper gives as +13.0 to +37.9, a finding reported as no effect that the paper reports as statistically significant. 91 were correct. The checker narrowed where to look; it did not decide.
bench/planted.py in the code repository.