paperful
Fill the gaps in your Zotero library.
paperful fills the gaps in your Zotero library. It fetches the PDFs your items are missing, keeps them in a folder tree that mirrors your collections, and attaches them back.
Work happens on disk (out/, state/). Zotero is a library adapter: read the catalogue in, write PDFs and metadata patches back. It is a local CLI, not a Zotero plugin and not a hosted service.
Why paperful
Most tools in this space do one job well: find an OA PDF inside Zotero, tidy attachments, or lint a .bib. paperful is for bulk missing-PDF fetch with a resumable disk ledger:
- Open access first (Unpaywall, OpenAlex, arXiv, bioRxiv/medRxiv, Europe PMC, Semantic Scholar, CORE, optional Google Scholar)
- Campus EZProxy when you have a subscription
- Sci-Hub is opt-in and off by default
- Collection-shaped folders, identifier lint, proposed metadata patches you apply yourself
If you only need “Find Available PDF” for a handful of items, stay in Zotero. If you need a resumable CLI over a messy library, paperful is the tool.
How it works
A typical run:
- Scope a collection (or the whole library)
- Prepare identifiers (verify or fill DOI)
- Hit only the sources that match the item’s metadata
- Write PDFs under
out/and appendstate/manifest.jsonl - Optionally attach into Zotero 10+
run never rewrites bibliographic fields. lint is read-only. fix-metadata --apply is the write-back step.
Getting started
Python 3.10+ and uv. Zotero running with the local API enabled.
git clone https://github.com/glen-w/Paperful.git
cd Paperful
uv sync
cp config.example.toml config.toml
uv run paperful doctor
uv run paperful run --collection interesting --dry-run
Status
First usable CLI (0.1). 0.x flags and report JSON may still move; 1.0 will lock attach behaviour and paperful.run_report.v1.