Asking Questions
/paper-rag:ask answers a question grounded in your active library. Retrieval and prose generation are split cleanly: the underlying query.py script only ranks and returns chunks as JSON — it never writes prose. Claude reads that JSON and writes the cited answer.
/paper-rag:ask <question> [--k 5] [--type text|figure|abstract] [--pmid PMID]
[--where '<json>'] [--embedding-model M] [--dense-only] [--lexical-only] [--rrf-k 60]How retrieval works
Each query runs two retrieval legs and fuses their rankings:
- Dense leg — your question is embedded with the library's embedding model and matched against Chroma via nearest-neighbor search.
- Lexical leg — a BM25 search over the same chunks' text, using the index built at ingest time.
Dense and lexical live in two separate pools — different stores, built independently at ingest time, each queried on its own at ask time:
ingest.py writes new chunks into both; each ask writes nothing, it only reads both, independently, then RRF fuse combines the two rankings. If one pool is stale or missing (e.g. a deleted bm25/ dir), the other still answers on its own — see --dense-only / --lexical-only below. The two rankings are combined with Reciprocal Rank Fusion (RRF): each chunk's score is 1/(rrf_k + dense_rank) + 1/(rrf_k + lexical_rank) (a term is omitted if the chunk didn't appear in that leg's results). This rewards chunks that rank well in either leg — a chunk ranked highly by exact keyword match but poorly by embedding similarity (or vice versa) still surfaces near the top, which plain dense-only search would miss. --rrf-k (default 60) controls how much the fusion favors top ranks over lower ones — lower values weight rank position more aggressively.
Use --dense-only or --lexical-only to isolate one leg, e.g. for debugging why a particular chunk isn't surfacing.
If the BM25 index for the collection is missing, the query silently falls back to dense-only and prints a warning to stderr — this shouldn't normally happen, since ingesting always rebuilds the index, but can happen if a home's bm25/ directory was deleted by hand.
Filtering results
--k N(default5) — number of chunks returned, after fusion.--claims-k N(default3) — claim hits in the defaultmergedstrategy.--strategy merged|chunks|claims|mixed— see Claims. Ignored with--type.--type text|figure|abstract|claim— restrict to one row type (single search).--pmid PMID— restrict to one paper.--where '<json>'— a raw Chroma-style filter, for anything--type/--pmiddon't cover. Supports$and,$or,$eq,$ne,$in,$nin, and bare equality, applied identically to both the dense and lexical legs (the lexical leg re-implements this filter logic itself, so scoped queries don't leak un-tagged papers into BM25 results).
--type and --pmid are shorthand that get folded into the same filter --where builds internally — you can't combine --where with --type/--pmid to add clauses; --where replaces them if given. Passing both --type and --pmid (without --where) combines them with $and.
Example — scope a query to one paper's figures:
/paper-rag:ask what does figure 2 show --pmid 31978945 --type figureExample — scope to a project tag with --where (see Tags & Homes for tagging):
/paper-rag:ask summarize the methods --where '{"tags": "meta-analysis"}'Claims
See Extracting Claims for how claims are made and checked.
Papers can carry extracted claims: short, standalone assertions written by Claude at ingest and stored as claim rows beside the chunks (see /paper-rag:extract-claims). Each claim records the ids of the chunks that support it (source_chunk_ids).
By default ask uses the merged strategy:
- one hybrid search over claims (
--claims-k), one over chunks (--k); - each claim hit gets its supporting chunks attached as
source_chunks(--no-expand-claimsturns this off); - chunks already covered by a claim's sources are dropped from the chunk list.
Claude then writes the answer from the chunk text in source_chunks; the claim is a pointer to the right paper and passage, not the quoted wording. Papers without claims are found through their chunks alone, so merged equals plain chunk search on a library with no claims. --strategy chunks|claims|mixed run the alternatives, and /paper-rag:eval-retrieval compares them on your own labelled questions.
Claims are checked when stored: every source chunk must belong to the paper, each claim must carry an evidence_span quoted verbatim from a source chunk, and every number in the claim (and in effect_value / uncertainty_interval) must appear in those sources. Optional structured fields (population, intervention, comparator, outcome, direction, effect_value, effect_measure, uncertainty_interval, study_design) are stored as metadata and returned on claim hits; they are for display and comparison, not for filtering. Each claim also gets a source_level (abstract, fulltext or mixed), derived from the types of the chunks it cites. It is stored as metadata, so --where '{"source_level": "abstract"}' works with --type claim.
Embedding model
--embedding-model M queries a specific model's collection instead of the home's default. If nothing was ever ingested with that model, the query returns an empty result and a warning listing which collections do exist — relay this warning rather than treating an empty answer as "no matching papers."
Citations and the References block
Each returned chunk carries id, type, doc_key, text, and — when applicable — pmid, title, section, page, path, dense_rank, lexical_rank, and rrf_score. From these, Claude:
- Grounds every claim in a retrieved chunk, citing inline by PMID and title (e.g. "(Kim et al., PMID 12345678)"), noting section/page where useful.
- For
type: "figure"hits, mentions the figure and links itspath(the saved PNG). - For
type: "abstract"hits, cites it as the paper's abstract, with no page/section. - Says plainly when no relevant chunks were returned, rather than guessing.
After the prose answer, Claude collects the distinct PMIDs (or doc_keys, if a cited paper has no PMID) actually cited, runs /paper-rag:cite on them, and appends the BibTeX output verbatim under a ## References heading — see Citing & Filtering for what that BibTeX looks like.
