Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

openpaper

Find a legally free copy of a paper. Then find everything around it.

Two things researchers do constantly, and no single tool did both:

  1. A paper is behind a paywall. Somewhere there is usually a legal free copy — in PubMed Central, an institutional repository, a preprint server, or the publisher's own open archive. Finding it by hand means checking five sites.
  2. One good paper turns up. The papers it cites, the papers citing it, and the papers like it are exactly the reading list you want — and assembling that by hand is an afternoon.

openpaper does both from one command, and downloads what is openly available.

export OPENPAPER_EMAIL=you@example.com

# where can I legally read this?
python3 scripts/openpaper.py get 10.1136/bmj.n71

# build the reading list around a paper I like
python3 scripts/openpaper.py snowball 10.1161/CIR.0000000000001184 \
        --year-from 2020 --min-links 2 --out ./lit

# download everything that is open
python3 scripts/openpaper.py fetch --from ./lit/cluster-*.json --out ./lit/pdf

Out come .csv (opens in Excel), .bib (imports into Zotero, EndNote, Mendeley), .json (full records), and a folder of PDFs named year-author-title.pdf.

Why it exists

The pieces all existed separately. Citation-mapping tools (Connected Papers, Research Rabbit, Litmaps, Inciteful) draw you a graph but never fetch a PDF. PDF finders (the Unpaywall extension, Zotero's Find Full Text, LibKey) work one paper at a time in a browser and know nothing about citation structure. Nothing joined "find the neighbours" to "and get me the text of all of them."

No shadow libraries

openpaper will not use Sci-Hub, LibGen, Sci-Net or any mirror, and contains no paywall bypass. This is a design decision, not a limitation to work around — and for current literature it costs you very little:

  • Sci-Hub stopped taking in new articles around December 2020 – February 2021; its reported archive size was identical (88,343,822 items) in December 2021 and July 2022. For anything published from 2022 onward there is no coverage measurement at all.
  • Meanwhile the legal share kept climbing. Of the randomised trials cited in Cochrane reviews, only 20.7% of those published 2020–2023 remained behind a paywall, against 60.0% for 1980–1999 (Learned Publishing 2026).

So for recent work — new guidelines, this year's trials — the legal route is not the compromise. It is the one that has the paper.

There is also an institutional risk that rarely gets mentioned: publishers police their licences at the organisation level. IEEE suspended off-campus access for the whole University of Central Arkansas after a compromised account was used to harvest content; the library had to disable the account before access was restored (UCA Library).

When a paper genuinely is closed, openpaper prints the legal ways to get it — institutional access, Research4Life/HINARI, interlibrary loan, or a reprint request it will draft for you.

Sources

All free, all public, none requiring an API key as of 2026-08-15:

Source Used for
OpenAlex metadata, references, citations, related work, OA locations
Unpaywall open-access locations per DOI
Europe PMC full text (PDF and JATS XML) for the PMC open subset
Crossref canonical bibliographic records

How ranking works

Nothing is hidden. A candidate paper is ordered by:

  1. seed_links — how many of your seed papers it connects to. Linked to three of your seeds beats linked to one, however famous it is. This is the Wohlin snowballing idea: relevance is a property of the local network.
  2. cites_per_year — citations divided by age, so a strong 2024 paper is not buried under a 2009 classic.

Neither number judges quality. They order the reading queue; you still read.

Peer review is the default

Preprints, conference abstracts and dissertations are excluded unless you ask for them. Citing a preprint as though it were a peer-reviewed paper is a real error in clinical writing, not a formatting slip — so the safe behaviour is the default one. The engine says how many it set aside every run; --include-preprints brings them back.

Detection catches both the obvious case (type: preprint) and the sneaky one — a record labelled article whose host is medRxiv, bioRxiv, SSRN or Research Square.

What it flags

  • Retracted articles — cross-checked, never taken on one source's word. OpenAlex alone flags the 2020 Lancet Commission on dementia as retracted while Europe PMC and Crossref record no such notice, so a single flag is reported as unverified and only agreement between sources is reported as fact.
  • Preprints — if you opt them in, routes stay tagged preprint: submitted version, not peer reviewed, possibly different from what was published.
  • Author manuscripts — accepted versions whose pagination will not match the published record. Cite the DOI.
  • Licence — recorded per download in _fetch-log.json.

Install

Needs Python 3.8+. Nothing else — no pip install.

As a Claude Code plugin:

/plugin marketplace add ChienNguyen23/openpaper
/plugin install openpaper

Or just run the script directly; it is self-contained.

Options worth knowing

Flag Does
--min-links 2 keep only work connected to ≥2 seeds — the single best noise filter
--oa-only only papers with a free copy
--year-from 2020 recent literature only
--no-forward / --no-backward references only / citing papers only
--include-preprints bring back preprints/abstracts/theses (excluded by default)
--per-seed 300 dig deeper per seed

Responses are cached for a week under ~/.cache/openpaper, so re-running a query costs nothing.

The second tool: litsearch

scripts/litsearch.py builds a reference set you can defend in front of a committee — protocol declared before searching, five search lanes across two databases, age limits by citation role (an original 1978 instrument paper is kept; a 2015 prevalence figure is flagged), four-tier PICO relevance grading, seven post-checks, and a PRISMA-S paragraph for the methods chapter.

L="python3 scripts/litsearch.py"
$L plan --topic "..." --purpose review   # write a protocol, then fill it in
$L search protocol.json                  # five lanes -> run.json + screening sheet
$L apply run.json --decisions decisions.json
$L gate run-screened.json                # seven checks -> READY / NOT-READY
$L prisma run-screened.json              # methods-chapter declaration
$L audit thesis.docx                     # grade an EXISTING reference list
$L verify thesis.docx --quantitative-only  # pair cited sentences with abstracts

Measured, not felt

tests/test_core.py holds 52 regression cases — every one a bug actually found or a rule a committee actually enforces. benchmarks/ holds a 295-reference gold set drawn from four committee-approved Vietnamese medical theses (anonymized) and a ledger:

Matcher version Resolve rate*
baseline (title-only) 80.0%
current (full-string + dual-index + parser fixes) 94.9%

* Resolve rate = the share of entries matched to an indexed record. The gold set carries no per-item answer key yet, so this measures retrieval, not verified correctness — spot checks are clean, but treat the number accordingly. Vietnamese-language references are deliberately refused (VN journals are not internationally indexed; guessing produced wrong DOIs) and are excluded from this set.

python3 tests/test_core.py --net
python3 benchmarks/run_bench.py --sample 60

Licence

MIT.

About

Find legal full text, grow citation clusters, build defensible reference sets — stdlib Python, no API keys. Claude Code plugin included.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages