Skip to content

Commands ​

Every /paper-rag:* slash command wraps a Python script, invoked as:

uv run --project ${CLAUDE_PLUGIN_ROOT} python ${CLAUDE_PLUGIN_ROOT}/scripts/<script>.py ...

This page tabulates each command's syntax and flags as implemented (scripts/*.py, via typer). For the reasoning behind each command's behavior, see the Guide or Concepts.

Reading this reference. Each command lists its syntax, a flag table, and one worked example. Commands are grouped by what they do to the library, not alphabetically — start with Homes & setup if you're new.

Overview ​

Homes & setup ​

CommandScriptPurpose
/paper-rag:initinit.pyInitialize or re-register a paper-rag home.
/paper-rag:useinit.py --use-onlySwitch the active home.
/paper-rag:whoamiinit.py --whoamiSet the default author filter for mine.

Ingest & remove ​

CommandScriptPurpose
/paper-rag:ingestingest.pyIngest a paper by PMID, URL, or local file.
/paper-rag:removeremove.pyRemove one or more papers from the active library.
/paper-rag:tagtag.pyPatch tags on already-ingested papers without re-ingesting.
CommandScriptPurpose
/paper-rag:pubmed-searchsearch_pubmed.pySearch PubMed itself (not the local library) for a deduplicated PMID set.
/paper-rag:mesh-updatemesh_update.pyDownload/build the local MeSH descriptor index used by search's concept mode.

Ask ​

CommandScriptPurpose
/paper-rag:askquery.pyRetrieve claims and chunks for a question via hybrid dense + BM25 search.
/paper-rag:extract-claimsclaims.pyStore Claude-extracted, verified claims per paper (or batch all papers missing them).
/paper-rag:eval-retrievaleval_retrieval.pyCompare chunk, claim and merged search on labelled questions.

Cite & mine ​

CommandScriptPurpose
/paper-rag:citecite.pyGenerate BibTeX for one or more papers.
/paper-rag:minemine.pyFilter bibliographic metadata (not a vector search).

/paper-rag:init ​

Initialize or re-register a paper-rag home. Runs scripts/init.py.

Syntax: /paper-rag:init <path> [--name NAME] [--use]

FlagTypeDefaultDescription
path (positional)stringrequiredDirectory to initialize as a home.
--namestringdirectory basenameName to register the home under.
--use / --no-useflagunset (becomes current only if it's the first home)Force this home to become (or not become) the active current home.

Example:

/paper-rag:init ~/papers/oncology --name onc --use

/paper-rag:use ​

Switch the active home. Runs scripts/init.py --use-only.

Syntax: /paper-rag:use <name>

FlagTypeDefaultDescription
name (positional)stringrequiredA name already registered via /paper-rag:init.

Example:

/paper-rag:use onc

/paper-rag:whoami ​

Set the default author filter for /paper-rag:mine. Runs scripts/init.py --whoami.

Syntax: /paper-rag:whoami <name>

FlagTypeDefaultDescription
name (positional)stringrequiredAuthor family-name substring to match, case-insensitively, against each paper's author list.

Example:

/paper-rag:whoami Ecker

/paper-rag:ingest ​

Ingest a paper by PMID, URL, or local file. Runs scripts/ingest.py.

Syntax: /paper-rag:ingest <pmid|url|path> [--pmid PMID] [--title TITLE] [--tags a,b] [--force] [--ocr] [--describe-figures] [--embedding-model M] [--require-fulltext]

FlagTypeDefaultDescription
target (positional)stringrequiredPMID, URL, or local file path.
--pmidstringnoneForce the PMID for a URL/local-file target.
--titlestringnoneOverride/set the paper's title.
--tagscomma-separated stringnoneTags to attach to this paper's chunks.
--forceflagoffRe-ingest even if already present, replacing existing chunks.
--ocrflagoffRun OCR during docling conversion (scanned PDFs).
--describe-figuresflagoffGenerate captions for uncaptioned figures.
--embedding-modelstringhome's config.json → BAAI/bge-small-en-v1.5Embedding model for this ingest.
--require-fulltextflagoffAbort rather than fall back to metadata-only ingest.

Example:

/paper-rag:ingest 31978945 --tags neuroimaging --describe-figures

/paper-rag:remove ​

Remove one or more papers from the active library. Runs scripts/remove.py.

Syntax: /paper-rag:remove <doc_key|pmid ...> [--all] [--yes] [--embedding-model M]

FlagTypeDefaultDescription
targets (positional, variadic)stringsnonedoc_key(s)/PMID(s) to remove.
--allflagoffRemove every ingested paper instead of specific targets.
--yesflagoffSkip the confirmation prompt (required for non-interactive use).
--embedding-modelstringhome's config.json defaultTarget a specific model's collection.

Example:

/paper-rag:remove 31978945 --yes

Search PubMed itself (not the local library) for a deduplicated PMID set. Runs scripts/search_pubmed.py. See Searching PubMed for a full walkthrough.

Syntax: /paper-rag:pubmed-search --mode direct --query "..." or /paper-rag:pubmed-search --mode concepts --concepts '[...]' [--sensitivity broad|balanced|precise] [--max-results N] [--page-size N]

FlagTypeDefaultDescription
--modestring (direct|concepts)requireddirect passes --query straight to ESearch; concepts compiles a Boolean query from --concepts.
--querystringnoneRaw PubMed query string (--mode direct only).
--conceptsJSON stringnoneArray of {"name", "terms", "required", "expand"} objects (--mode concepts only). required/expand default true.
--sensitivitystring (broad|balanced|precise)balancedHow aggressively concept compilation narrows the query — see Searching PubMed.
--max-resultsint1000Stop paginating once this many PMIDs are collected (hard ceiling: 10,000).
--page-sizeint500ESearch page size per request.

There is no question mode — that would need an LLM classifying the question into a framework, and this project has none. Claude extracts concepts itself and calls concepts mode instead.

Example:

/paper-rag:pubmed-search --mode concepts --concepts '[{"name":"population","terms":["autism","autism spectrum disorder"]},{"name":"modality","terms":["MRI","structural MRI"]}]'

/paper-rag:mesh-update ​

Download/build the local MeSH descriptor index used by /paper-rag:pubmed-search's concepts mode. Runs scripts/mesh_update.py. Independent of any paper-rag home — cached once at ~/.cache/paper-rag/mesh (override with PAPER_RAG_MESH_CACHE_DIR).

Syntax: /paper-rag:mesh-update [--year YYYY] [--force]

FlagTypeDefaultDescription
--yearintcurrent yearWhich year's MeSH descriptor release to fetch.
--forceflagoffRe-download and rebuild even if already cached.

Downloads NLM's public-domain descriptor XML (300MB+) the first time — a few minutes on a normal connection, instant on every run after (cached).

Example:

/paper-rag:mesh-update

/paper-rag:ask ​

Retrieve chunks for a question via hybrid dense + BM25 search. Runs scripts/query.py; Claude writes the prose answer from the returned JSON.

Syntax: /paper-rag:ask <question> [--k 5] [--claims-k 3] [--strategy merged|chunks|claims|mixed] [--no-expand-claims] [--type text|figure|abstract|claim] [--pmid PMID] [--where '<json>'] [--embedding-model M] [--dense-only] [--lexical-only] [--rrf-k 60]

FlagTypeDefaultDescription
question (positional)stringrequiredThe question text.
--kint5Number of ranked chunks to return (total hits for a single filtered search).
--claims-kint3Claim hits in the merged strategy.
--strategystring (merged|chunks|claims|mixed)mergedmerged: separate claim and chunk searches, claims first. mixed: one search over every row type. Ignored when --type is given.
--expand-claims / --no-expand-claimsflagonAttach each claim hit's supporting chunks as source_chunks and drop chunks they already cover.
--typestring (text|figure|abstract|claim)noneRestrict to one row type (single search, no strategy).
--pmidstringnoneRestrict to one paper.
--whereJSON stringnoneRaw Chroma-style filter; overrides --type/--pmid if given.
--embedding-modelstringhome's config.json defaultQuery a specific model's collection.
--dense-onlyflagoffSkip the BM25 lexical leg.
--lexical-onlyflagoffSkip the dense embedding leg.
--rrf-kint60Reciprocal Rank Fusion constant (lower = more weight on top ranks).

Example:

/paper-rag:ask what sample sizes were used --k 8 --where '{"tags": "meta-analysis"}'

/paper-rag:extract-claims ​

Store atomic claims for ingested papers. Claude reads the chunks, writes claims, re-reads each claim's source chunks to verify it, then scripts/claims.py add stores them as claim rows. Runs scripts/claims.py. See Extracting Claims for the full walkthrough.

Syntax: /paper-rag:extract-claims <doc_key|pmid> or /paper-rag:extract-claims --all-missing

claims.py subcommands:

SubcommandDescription
chunks <doc_key|pmid>List a paper's text and abstract chunks with ids.
add <doc_key|pmid> [--file F] [--skip-span-check] [--skip-number-check]Replace the paper's claims from a JSON list. Rejects unknown source_chunk_ids, a missing or non-verbatim evidence_span, an invalid direction, and numbers not present in the source chunks. Optional structured fields are stored as metadata, and source_level (abstract, fulltext or mixed) is derived from the cited chunks.
status [--missing]List papers with claim counts; --missing keeps only papers with none.

/paper-rag:eval-retrieval ​

Score chunks, claims and merged search on labelled questions. Runs scripts/eval_retrieval.py.

Syntax: /paper-rag:eval-retrieval <questions.json> [--k 5] [--claims-k 3] [--strategies chunks,claims,merged]

Input is a JSON list of {"question", "relevant_pmids"} (see evals/questions.example.json). Output is per-strategy means of hit, recall and mrr, plus per-question detail.

/paper-rag:cite ​

Generate BibTeX for one or more papers. Runs scripts/cite.py.

Syntax: /paper-rag:cite [doc_key|pmid ...] [--all]

FlagTypeDefaultDescription
targets (positional, variadic)stringsnonedoc_key(s)/PMID(s) to cite.
--allflagoffCite every paper in the library that has a metadata.json.

Example:

/paper-rag:cite 31978945 22222222

/paper-rag:mine ​

Filter bibliographic metadata (not a vector search). Runs scripts/mine.py.

Syntax: /paper-rag:mine [--author NAME] [--as first|last|any] [--year Y|Y-Y] [--journal J] [--keyword K] [--pub-type T]

FlagTypeDefaultDescription
--authorstringauthor_name in config.json, else unfilteredCase-insensitive substring match against author family names.
--asstring (first|last|any)anyRestrict author match to first/last/any position.
--yearstring (Y or Y1-Y2)noneSingle year or inclusive range.
--journalstringnoneCase-insensitive substring match against journal name.
--keywordstringnoneCase-insensitive substring match against paper keywords.
--pub-typestringnoneCase-insensitive substring match against publication types.

Example:

/paper-rag:mine --as first --year 2020-2024

/paper-rag:tag ​

Patch tags on already-ingested papers without re-ingesting. Runs scripts/tag.py.

Syntax: /paper-rag:tag <doc_key|pmid ...> [--set a,b] [--add a,b] [--remove a,b] [--all] [--embedding-model M]

FlagTypeDefaultDescription
targets (positional, variadic)stringsnonedoc_key(s)/PMID(s) to tag.
--setcomma-separated stringnoneReplace the tag list entirely. Exactly one of --set/--add/--remove is required.
--addcomma-separated stringnoneAdd tags to the existing set.
--removecomma-separated stringnoneRemove tags from the existing set.
--allflagoffApply to every ingested paper instead of specific targets.
--embedding-modelstringhome's config.json defaultTarget a specific model's collection.

Example:

/paper-rag:tag --all --add reviewed

Last updated: