Metadata-Version: 2.5
Name: refproof
Version: 0.1.0
Summary: Catch fake, wrong and retracted references in your paper's bibliography.
Project-URL: Homepage, https://github.com/maoji-y/refproof
Project-URL: Web app, https://maoji-y.github.io/refproof/
Project-URL: Issues, https://github.com/maoji-y/refproof/issues
Author: refproof contributors
License-Expression: MIT
License-File: LICENSE
Keywords: academic-writing,bibliography,bibtex,citations,crossref,docx,doi,hallucination,latex,references,retraction
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Education
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Text Processing :: Markup :: LaTeX
Requires-Python: >=3.9
Description-Content-Type: text/markdown

<div align="center">

# refproof

**Catch fake, wrong and retracted references before your reviewers do.**

[**Try it in your browser →**](https://maoji-y.github.io/refproof/?demo) &nbsp;·&nbsp;
[Command line](#command-line) &nbsp;·&nbsp; [GitHub Action](#github-action) &nbsp;·&nbsp; [中文说明](https://github.com/maoji-y/refproof/blob/main/README.zh-CN.md)

[![Marketplace](https://img.shields.io/badge/marketplace-refproof-blue?logo=github)](https://github.com/marketplace/actions/refproof)
[![CI](https://github.com/maoji-y/refproof/actions/workflows/ci.yml/badge.svg)](https://github.com/maoji-y/refproof/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/refproof)](https://pypi.org/project/refproof/)
[![Python](https://img.shields.io/pypi/pyversions/refproof)](https://pypi.org/project/refproof/)
![No dependencies](https://img.shields.io/badge/dependencies-none-brightgreen)
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://github.com/maoji-y/refproof/blob/main/LICENSE)

</div>

AI writing tools invent references that look perfect. People mistype DOIs, cite the wrong
year and cite papers that were later retracted. refproof looks up every entry of your
bibliography in **Crossref, arXiv and OpenAlex**, compares it with what you wrote, and tells you
which references are wrong and, when it can, what the right one is.

It reads **BibTeX, LaTeX, Word (.docx), RIS and pasted text**. No API keys are needed, and
the browser version sends no file anywhere.

<p align="center"><img src="https://raw.githubusercontent.com/maoji-y/refproof/main/docs/screenshot.png" width="760" alt="refproof finding a retracted paper, an invented reference and a wrong DOI"></p>

## What it catches

| Result | Meaning |
|---|---|
| ❌ **Not found** | No work with this title and these authors exists. The typical invented reference. |
| ❌ **Wrong DOI** | The DOI is real but belongs to a different paper. refproof finds the right DOI. |
| ❌ **DOI not found** | The DOI was never registered. |
| ❌ **Retracted** | The paper was retracted or withdrawn (Crossref + Retraction Watch data). |
| ⚠️ **Mismatch** | The paper exists, but the year, first author or title in your citation is wrong. |
| ⚠️ **Concern** | The publisher issued an expression of concern. |
| ⚠️ **Unverified** | Could not be confirmed: books, reports, theses and some non-English work are often not indexed. |
| ✅ **Verified** | Found, and title, first author and year agree. Preprints that have since been published are pointed out. |

## Quick start

### In the browser

Open **[maoji-y.github.io/refproof](https://maoji-y.github.io/refproof/?demo)**, then drop in a file
or paste your reference list. The checker runs in your browser (Python via
[Pyodide](https://pyodide.org)). Only titles, authors and DOIs go to the public Crossref,
DataCite and OpenAlex APIs.

### Command line

```bash
pipx install refproof          # or: pip install refproof, or: uvx refproof paper.bib
```

```console
$ refproof examples/demo.bib
refproof 0.1.0 · examples/demo.bib: 10 BibTeX entries

  ✖ RETRACTED     wakefield1998  examples/demo.bib:92
    Wakefield, Murch, Anthony (1998). Ileal-lymphoid-nodular hyperplasia, non-specific colitis, and…
    → This work has a retraction notice: https://doi.org/10.1016/s0140-6736(10)60175-4.

  ✖ NOT FOUND     chen2021contrastive  examples/demo.bib:67
    Chen, Hinton (2021). Contrastive diffusion priors for few-shot neural radiance fields. Advances…
    → No matching work in Crossref, arXiv or OpenAlex.
    → Closest: “Exploiting Depth Priors for Few-Shot Neural Radiance Field Reconstruction” (Chen et al., 2024), title similarity 0.70.

  ✖ WRONG DOI     lecun2015  examples/demo.bib:34
    LeCun, Bengio, Hinton (2015). Deep learning. Nature.
    → DOI 10.1038/nature14536 belongs to a different work: “Unexpected role for vitamin B2” (Clarke & Allan, 2015).
    → The cited title matches https://doi.org/10.1038/nature14539 (Nature, 2015).

  ✖ DOI NOT FOUND porteagel2020  examples/demo.bib:46
    Porté-Agel, Bastankhah, Shamsoddin (2020). Wind-turbine and wind-farm flows: A review. Boundary…
    → DOI 10.1007/s10546-019-99473-0 is not registered.
    → The cited title matches https://doi.org/10.1007/s10546-019-00473-0 (Boundary-Layer Meteorology, 2019).

  ⚠ MISMATCH      hinton2017attention  examples/demo.bib:83
    Hinton, Vaswani (2017). Attention is all you need. NeurIPS.
    → First author differs: cited as Hinton, record says Vaswani et al.

  10 checked: 1 Retracted · 2 Not found · 1 Wrong DOI · 1 DOI not found · 2 Mismatch · 3 Verified
```

(Output shortened.) More ways to run it:

```bash
refproof manuscript.docx           # Zotero / Mendeley / EndNote citations, or the typed list
refproof main.tex                  # only the entries that main.tex actually cites
refproof refs.ris --all            # also list the verified entries
pbpaste | refproof -               # a reference list copied from a PDF
refproof paper.bib -f json -o report.json
```

### GitHub Action

Check the bibliography on every push. Problems show up as annotations on the right line
of the `.bib` file and as a table in the job summary.

```yaml
# .github/workflows/references.yml
name: References
on: [push, pull_request]
jobs:
  refproof:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: maoji-y/refproof@v0
        with:
          files: paper/references.bib     # several files: separate with spaces
          fail-on: error                  # error | warning | never
```

### Python

```python
from refproof import check_references, load_file

for f in check_references(load_file("paper.bib"), mailto="you@university.edu"):
    if f.level != "ok":
        print(f.status.label, f.ref.key, *f.notes, sep="\n  ")
```

## Supported inputs

| Format | Notes |
|---|---|
| BibTeX / BibLaTeX `.bib` | `@string` macros, nested braces, LaTeX accents; errors point to the entry's line. arXiv IDs are picked up from `eprint`, `journal = {arXiv preprint …}` and URLs. |
| LaTeX `.tex` | Follows `\bibliography{…}` / `\addbibresource{…}` and checks only the cited keys, or reads a `thebibliography` block. |
| Word `.docx` | Uses the structured data that **Zotero, Mendeley and EndNote** store in the document, or Word's own citations. Without them, reads the typed list after a *References* / *Bibliography* / *参考文献* heading. |
| RIS `.ris` | Exports from EndNote, Zotero, Mendeley and publisher sites. |
| Plain text | Numbered (`[1]`, `1.`), APA, Harvard, IEEE, Vancouver and GB/T 7714 lists, one reference per line or paragraph, including lines broken by a PDF copy. |

## How it works, and why it does not cry wolf

A search engine always returns *something*, so a checker that trusts the top hit misses
invented references. One that demands an exact match flags real ones. refproof uses
these rules:

1. **DOIs are resolved, then compared.** A DOI goes to Crossref, or to its own
   registration agency (DataCite, mEDRA, JaLC, …) via doi.org. The record's title must match
   the cited title. If it does not, the DOI is wrong, and refproof searches for the cited
   title to find the right DOI.
2. **References without a DOI are searched**, by title in Crossref, among arXiv's preprints
   (via DataCite) and in OpenAlex, and by the full citation string in Crossref.
3. **A hit only counts if title, first author and year agree.** Famous titles get reused ("Attention is all you
   need" has several namesakes in Crossref), so candidates whose authors match are preferred.
   Short generic titles ("Deep learning") need the author to match too. Corporate authors
   such as "National Renewable Energy Laboratory" are skipped when comparing first
   authors.
4. **"Not found" is reserved for journal and conference papers.** Journals are almost
   completely covered by Crossref. Books, reports, theses, web pages and CJK-language work
   often are not, so these get *Unverified*, not an error.
5. **Retractions** come from Crossref's `updated-by` data (which includes Retraction Watch),
   from "RETRACTED:" titles, and from retraction notices that turn up among the search hits.

On 320 real references from a wind-energy literature review (BibTeX with and without
DOIs, plus a pasted reference list with the DOIs removed), refproof reported **no false
errors**: no real reference was called fake, wrong or retracted. The only error it raised was
a correct retraction.

## Options

| Flag | Default | |
|---|---|---|
| `-f, --format` | `text` | `text`, `markdown`, `json` or `github` (annotations + job summary) |
| `-a, --all` | off | also list verified references |
| `--fail-on` | `error` | exit with status 1 on `error`, `warning`, or `never` |
| `--mailto` | `$REFPROOF_MAILTO` | your e-mail; Crossref and OpenAlex serve polite clients faster |
| `--openalex-key` | `$OPENALEX_API_KEY` | free key from openalex.org; anonymous OpenAlex search is throttled under load |
| `--no-openalex` | off | Crossref and arXiv only |
| `--no-cache` | off | responses are otherwise cached for 14 days |
| `--input-format` | `auto` | `bibtex`, `ris`, `docx`, `tex` or `text` |

## Limitations

- A missing record is **evidence, not proof**. Check flagged references yourself before
  accusing anyone.
- Coverage of Chinese, Japanese and Korean literature without DOIs (e.g. CNKI) is limited.
  Such entries are marked *Unverified*, never *Not found*.
- refproof checks that a cited work **exists and is cited correctly**. It does not check
  whether the work supports the sentence that cites it.
- Large bibliographies take a few minutes: the tool paces itself to the APIs' rate limits.

## Contributing

Bug reports with the offending citation are the most useful thing you can send. For a
development setup: `pip install -e . pytest && pytest`. The tests run offline against
canned API responses. For the web app, run `python web/build.py` and serve `web/`.

Metadata comes from [Crossref](https://www.crossref.org/), [DataCite](https://datacite.org/)
and [OpenAlex](https://openalex.org/). Thanks to them for open APIs.

MIT licensed.
