Tutorial
Four ways to find papers, one way in
Whatever route surfaces a PMID — a citation you already have, a PICO question, a snowball from a key paper, or a researcher's back-catalog — /ref:add is always the explicit, deliberate step that actually creates a record (D12). What you're holding often isn't a bare PMID, though: a URL, a downloaded PDF, a folder of PDFs, a .bib/.csl.json export, or a DOI. /ref:add-url, /ref:add-pdf, and the source-aware /ref:import resolve those to a PMID first, then call the same underlying add step — so the identity guarantee holds no matter which door you came in. This tutorial walks all four discovery routes plus the intake commands for whatever form the paper takes. Commands used: /ref:add, /ref:add-url, /ref:add-pdf, /ref:add-fetch, /ref:import, /ref:search-pubmed, /ref:update-queries, /ref:related, /ref:person, and /ref:discover.
The journey
/ref:add is the single, explicit gate every PMID passes through (D12), so duplicate detection, citekey allocation and the "metadata-only is not a failure" rule live in exactly one place.The example PMIDs, 99000101…99000108, are placeholders outside PubMed's real range. Blocks labelled output from a scratch library were produced by running the plugin's scripts against a throwaway library, standing in by hand for the PubMed MCP calls. Blocks labelled illustrative output need the network or a live MCP tool and follow the output format in the script source.
Route 1 — you already have something to add
Most of the time you already know what you want: a citation from a paper you're reading, a list a colleague emailed, an export from another reference manager. /ref:add takes one or more PMIDs directly — this is the base case every other route eventually feeds into.
output from a scratch library
› /ref:add 99000101 99000102 99000103 99000101: added (citekey=alvarez2023predictive) 99000102: added (citekey=nakamura2024surface) 99000103: added (citekey=okoye2022transcriptomic) — no abstract available — metadata-only record, not fabricated (§3a)
/ref:add only takes PMIDs as arguments, so if a colleague sent you pmids.txt (one per line), have Claude read the file and pass its contents as the argument list: /ref:add $(cat pmids.txt), or just paste the list. Every PMID still gets its own independent added / already_present / failed line.added with a metadata-only note is the honest outcome — never a silently fabricated abstract.When what you have isn't a bare PMID
PMID is still the identity key everything resolves to, but plenty of what actually lands in front of you isn't a PMID yet — a link, a downloaded PDF, a whole folder of PDFs from a shared drive, a .bib/.csl.json export from another reference manager, or a bare DOI copied off a reference list. Four commands cover these, each resolving a candidate PMID first and then calling the same add step:
/ref:add-url <url...>— extracts PMID/PMCID/DOI clues from PubMed, PMC, DOI, and publisher URLs (locally first, then a page fetch if needed), confirms ambiguous matches, adds the resolved PMIDs, and fetches full text unless--no-fetchis passed./ref:add-pdf <path...>— extracts DOI/PMID/PMCID/title clues from local PDFs withpdftotext(no network call), resolves each to a PMID, adds the metadata, then attaches every PDF to its paper./ref:add-fetch <pmid...>— for when you already have PMIDs and just want add-then-fetch in one step instead of running/ref:addand/ref:fetchseparately./ref:import <item...>— the source-aware front door. Hand it a mix of PMIDs, URLs, PDF paths, a folder of PDFs,.bib/.csl.jsonfiles, or bare DOIs in one call. It splits the inputs by type, routes URLs and PDFs through the same identification helpers as/ref:add-urland/ref:add-pdf, expands directories to the PDFs they contain, resolves bibliography-file entries and bare DOIs to PMIDs through PubMed MCP (asking for confirmation on anything ambiguous), then adds and — unless--no-fetchis passed — fetches everything that resolved.
/ref:import is the one to reach for whenever the source type is mixed or you don't want to figure out which specific command applies; /ref:add-url and /ref:add-pdf are worth using directly when you already know you only have one type of thing.
illustrative output
› /ref:import 99000109 https://doi.org/10.1038/s41586-026-00001-2 ~/Downloads/nguyen2025striatal.pdf identify: 99000109: manual -> 99000109 https://doi.org/10.1038/s41586-026-00001-2: doi -> 99000110 ~/Downloads/nguyen2025striatal.pdf: pmid -> 99000111 add: 99000109: added (citekey=singh2024cortical) 99000110: added (citekey=weber2026striatal) 99000111: already_present fetch: 99000109: acquired 99000110: abstract_only 99000111: duplicate_noop
.bib or .csl.json file tells /ref:import what to look for; the entries still have to resolve to a PMID through PubMed MCP before anything is added, the same as a DOI or a title clue would. And as with every route here, one input's failure — an unresolved PDF, an ambiguous DOI, a bad URL — never blocks the rest.Route 2 — turn a PICO question into a saved search
Give Claude a plain research question. It drafts a PICO-framed boolean PubMed query (MeSH + free text) using its own clinical/scientific judgment, runs it, and freezes the exact expression, source and result PMIDs as an immutable run — /ref:search-pubmed itself never touches PubMed or parses PICO; it only persists what it's handed.
output from a scratch library
› /ref:search-pubmed "Does surface-based transcriptomic decoding predict receptor density?" --slug transcriptomic-decoding --create # Claude drafts this expression, runs it, then saves the run: { "run_id": "run-2a9f0c6be142", "query": "(\"transcriptome\"[MeSH] OR transcriptomic) AND (\"receptors, neurotransmitter\"[MeSH] OR receptor density) AND (predict* OR decod*)", "source": "pubmed", "retrieved_at": "2026-09-16T09:04:11.000000+00:00", "pmids": ["99000104", "99000105", "99000106"] }
The saved run is a list of PMIDs, nothing more — it doesn't add anything to the library by itself. Read the run's PMIDs and hand them to /ref:add:
output from a scratch library
› /ref:add 99000104 99000105 99000106 99000104: added (citekey=lindqvist2024receptor) 99000105: added (citekey=chen2025decoding) 99000106: already_present
/ref:update-queries transcriptomic-decoding re-runs the exact stored expression — it never re-derives a new query from your original question — appends a new immutable run, and reports added/removed PMIDs since the last run. Add whatever's new the same way, through /ref:add.Route 3 — snowball from a paper you already have
/ref:related <pmid> follows a known paper two directions: backward extracts its reference list from already-committed full text (no network call), and forward asks PubMed's find_related_articles for similar papers. Read this carefully before quoting it as a citation graph — see the note below.
output from a scratch library
› /ref:related 99000104 --direction backward { "available": true, "count": 2, "candidates": [ { "candidate": "Smith J, et al. Receptor mapping in cortex. J Neurosci 2021.", "resolved": false, "direction": "backward", "method": "reference_list" }, { "candidate": "Diaz R, et al. Transcriptomic gradients revisited. Nat Commun 2020.", "resolved": false, "direction": "backward", "method": "reference_list" } ] }
illustrative output
› /ref:related 99000104 --direction forward { "count": 2, "zero_results": false, "note": null, "rows": [ { "candidate": "99000107", "resolved": true, "direction": "forward", "method": "find_related_articles:pubmed_pubmed", "already_in_library": false }, { "candidate": "99000105", "resolved": true, "direction": "forward", "method": "find_related_articles:pubmed_pubmed", "already_in_library": true } ] }
pubmed_pubmed is similarity, not "cited by." The live PubMed MCP tool has no true citation-graph link type — the default is word-weighted title/abstract/MeSH similarity. Every forward row records exactly which link_type produced it, so this is never presented as citation data it isn't. Backward candidates are raw reference-list text, not resolved PMIDs; most don't carry one. Look one up yourself if it's worth the effort — don't auto-resolve an entire reference list.Either direction only surfaces candidates — already_in_library: false is the signal to act on:
output from a scratch library
› /ref:add 99000107 99000107: added (citekey=park2024receptor)
Route 4 — a researcher's back-catalog
Confirm a person's identity first — name similarity alone never establishes it (§3d). Then /ref:discover builds an author-search query from their name variants and ORCID, runs it, and stores the hits as candidates on that person's record, never as library additions.
output from a scratch library
› /ref:person create ecker-c --name "Ecker, Christine" --orcid 0000-0000-0000-0001 { "slug": "ecker-c", "name_variants": ["Ecker, Christine"], "orcid": "0000-0000-0000-0001", "confirmed_publications": [], "candidate_publications": [], "rejected_publications": [] } › /ref:discover --person ecker-c { "slug": "ecker-c", "discovery_runs": [{ "query": "Ecker C[Author] AND 0000-0000-0000-0001[Author - Identifier]", "retrieved_at": "2026-09-16T09:11:03.000000+00:00", "candidate_count": 2 }], "candidate_publications": [ { "pmid": "99000108", "title": "Cortical thickness trajectories in a longitudinal cohort" }, { "pmid": "99000105", "title": "Transcriptomic decoding of surface-based imaging phenotypes" } ] }
A candidate isn't this person's confirmed publication until you link a specific author-list position — the evidenced identity match §3c requires:
output from a scratch library
› /ref:person confirm-publication ecker-c --pmid 99000108 --author-index 3 { "slug": "ecker-c", "confirmed_publications": [{ "pmid": "99000108", "author_index": 3 }], "candidate_publications": [ … 99000105 still pending … ] }
Confirming an identity match still doesn't create a paper record — that's still /ref:add:
output from a scratch library
› /ref:add 99000108 99000108: added (citekey=ecker2026cortical)
/ref:person reject-publication ecker-c --pmid <id> records that permanently — rejected PMIDs are never re-suggested by a later /ref:discover run.What you now have
<LIBRARY>/
papers/99000101/ … 99000108/
meta.json # every route above ends here, via /ref:add
queries/
transcriptomic-decoding.yaml # immutable runs from /ref:search-pubmed + /ref:update-queries
papers/99000104/
related.json # backward + forward candidates, upserted not overwritten
people/
ecker-c.json # confirmed / candidate / rejected publication state
Once papers are in, get their full text with the /ref:fetch tutorial steps in Systematic review, or jump straight to Thesis chapter for the read-screen-extract-synthesize path. Command reference: /ref:add, /ref:add-url, /ref:add-pdf, /ref:add-fetch, /ref:import, /ref:search-pubmed, /ref:update-queries, /ref:related, /ref:discover.