Commands · Organize
Projects, reading state, screening, notes, and review decisions
These commands record your judgement: which projects a paper belongs to, how far you have read it, whether it passed screening, what you think of it, which extracted claims you accept, and which papers report the same study. Acquisition and extraction never write any of this, and regenerating derived files never overwrites it.
Commands
Create research projects, give them questions, and add papers with project-specific relevance, priority, and reading state.
/ref:project create <slug> [--scope "<text>"]
/ref:project add-question <slug> --id <qid> --text "<text>"
/ref:project add-paper <slug> <pmid> [--relevance "<text>"] [--priority N] [--reading-status <state>]
/ref:project show <slug>
/ref:project list
Arguments
- create <slug>
- Creates
projects/<slug>/project.yaml and an empty papers.yaml. The slug is validated, and a duplicate is refused with the existing project named.
- add-question <slug>
--id <qid> (passed to the script as --question-id) and --text. Question IDs only need to be unique within their project.
- add-paper <slug> <pmid>
- Adds a membership record.
--reading-status is one of to_screen, to_read, reading, read. If the paper is already a member, the existing record is returned unchanged.
- show <slug>
- Prints the project and its membership list, plus a summary with paper count, question count, reading-state breakdown, and source/completeness counts.
- list
- Prints each project's slug, scope, question count, reading-state breakdown, and source/completeness counts, so it can double as a quick project dashboard.
What happens
- Resolves the library root, then runs the matching
project.py action.
- Prints the JSON result verbatim. On a slug collision, Claude asks you for another name instead of adding a suffix, so references never point at a surprise project.
Reads & writes
Writes projects/<slug>/project.yaml and papers.yaml. Both are JSON despite the extension, and both are written atomically. Membership is one record per PMID per project, so each project's relevance, priority, and reading state are independent.
Examples
output from a scratch library
› /ref:project create thesis-ch3 --scope "Cortical thickness in autism"
{
"slug": "thesis-ch3",
"scope": "Cortical thickness in autism",
"questions": []
}
› /ref:project add-paper thesis-ch3 31000001 --relevance "Core adult evidence" --priority 1 --reading-status to_read
{
"pmid": "31000001",
"relevance": "Core adult evidence",
"priority": 1,
"reading_status": "to_read",
"why_saved": null,
"screening": null,
"added_at": "2026-09-15T10:14:33.760136+00:00"
}
› /ref:project create thesis-ch3
error: project 'thesis-ch3' already exists at projects/thesis-ch3
Under the hood
project.py create|add-question|add-paper|show|list --repo … [--slug …] [--question-id …] [--text …] [--pmid …] [--relevance …] [--priority N] [--reading-status …]
See also
/ref:queue · /ref:screen · selector grammar · Thesis chapter tutorial
Set or show a paper's reading state, priority, and why-saved note within one project.
/ref:queue set --project <slug> --pmid <pmid> [--status <state>] [--priority N] [--why "<text>"]
/ref:queue show --project <slug> [--pmid <pmid>]
Arguments
- set
- Updates only the fields you pass.
--status is one of to_screen, to_read, reading, read. --why sets why_saved.
- show
- With
--pmid, prints that one membership. Without it, prints the whole project queue, including reading-state and source/completeness summaries, so the queue doubles as a quick dashboard.
- --project <slug>
- Required for both.
What happens
- Finds the paper's membership record in
papers.yaml and updates it in place.
- If the PMID is not a member yet, the command errors and points you to
/ref:project add-paper.
Why only here: reading state records what a human has actually read. Fetching full text or promoting claims never sets it, so --read selects papers you have read, not papers a model processed.
Reads & writes
Reads and writes projects/<slug>/papers.yaml.
Examples
output from a scratch library
› /ref:queue set --project thesis-ch3 --pmid 31000001 --status reading --why "Largest adult sample"
{
"added_at": "2026-09-15T10:14:33.760136+00:00",
"pmid": "31000001",
"priority": 1,
"reading_status": "reading",
"relevance": "Core adult evidence",
"screening": null,
"why_saved": "Largest adult sample"
}
› /ref:queue set --project thesis-ch3 --pmid 31000003 --status read
error: pmid '31000003' is not a member of project 'thesis-ch3' (add it first via /ref:project)
Under the hood
queue.py set|show --repo … --project … [--pmid …] [--status …] [--priority N] [--why …]
See also
/ref:project · /ref:status
Record a project-specific include, exclude, or pending decision, with a reason, for one paper.
/ref:screen --project <slug> --pmid <pmid> --decision included|excluded|pending --reason "<text>" [--run <query-run-id>]
Arguments
- --project <slug>
- Required.
- --pmid <pmid>
- Required. The paper does not have to be in the library or the project yet.
- --decision
- Required:
included, excluded, or pending.
- --reason "<text>"
- Required, so every exclusion can be explained later, for example in a PRISMA flow.
- --run <id>
- Optional. Links the decision to the saved search run it came from, stored as
search_run.
What happens
- Appends a
{pmid, decision, reason, timestamp[, search_run]} record to screening.jsonl. Earlier decisions stay in the log.
- Mirrors the latest decision onto the membership's
screening field, so --screened can filter without replaying the log.
- If the PMID is not a member yet, it is added with no relevance note. You can screen first and annotate later.
Reads & writes
Appends to projects/<slug>/screening.jsonl and updates papers.yaml. The script also has a history action that the command file does not expose.
Example
output from a scratch library
› /ref:screen --project thesis-ch3 --pmid 31000002 --decision included --reason "Reports adult cortical thickness"
{
"pmid": "31000002",
"decision": "included",
"reason": "Reports adult cortical thickness",
"timestamp": "2026-09-15T10:14:34.166756+00:00"
}
Under the hood
screen.py decide --repo … --project … --pmid … --decision … --reason "…" [--run …]
See also
/ref:search-pubmed · /ref:review --prisma · Systematic review tutorial
Append your own dated thoughts to a paper's notes.md, or print what is already there.
/ref:note <pmid> <text>
/ref:note <pmid> --show
Arguments
- <pmid> <text>
- Appends
<text> as a new entry, separated by --- and a UTC timestamp.
- <pmid> --show
- Prints the whole notes file, or nothing if it doesn't exist yet.
What happens
- Checks that
papers/<pmid>/ exists. If not, it errors and suggests /ref:add.
- Appends the entry or prints the file.
notes.md is authoritative user content. This is the only command that writes to it, and no generated view ever overwrites it. /ref:search --scope notes labels its matches personal_note, never evidence.
Reads & writes
Appends to papers/<pmid>/notes.md.
Example
output from a scratch library
› /ref:note 31000001 Check whether site effects were modelled.
appended to <library>/papers/31000001/notes.md
› /ref:note 31000001 --show
---
2026-09-15T10:14:34.335329+00:00
Check whether site effects were modelled.
Under the hood
note.py append|show --repo … --pmid … [--text "…"]
See also
/ref:search --scope notes · /ref:pull-annotations
Record a human review decision as a correction overlay: accept, edit, or reject a claim, and review grant links, author contributions, and identity matches.
/ref:verify claim <pmid> <claim_id> accept|edit|reject [--replacement <json-file>] [--rationale "…"] [--reviewer "…"]
/ref:verify grant-link <pmid> <grant-slug> accept|reject --evidence-locator "…" [--award-number "…"] [--rationale "…"] [--reviewer "…"]
/ref:verify author-contribution <pmid> <author_index> shared_first|shared_senior|corresponding --evidence "<statement>" [--reviewer "…"]
/ref:verify person-identity <pmid> <person-slug> <author_index> accept|reject [--rationale "…"] [--reviewer "…"]
/ref:verify show <pmid>
Arguments
- claim
- Reviews one claim from the paper's registry. An unknown
claim_id is refused. Reviewing a superseded claim is allowed. reject also marks the claim in the registry, so it drops out of default synthesis. edit takes a replacement JSON file.
- grant-link
- Records a reviewed link on
grants/<slug>.json, replacing any earlier link for that PMID, with match_method: "manual_review". It never adds the award number to the grant's aliases. That takes a deliberate /ref:grant add-alias.
- author-contribution
- Sets an independent
shared_first, shared_senior, or corresponding flag in authorship.json. It refuses without an explicit evidence statement, because these roles are never inferred from author position. author_index is 0-based.
- person-identity
- Accepts or rejects that author N is a given person. It delegates to
/ref:person's confirm/reject machinery, then logs a correction record so the audit trail matches the other review kinds.
- show <pmid>
- Revalidates all corrections against the current claim registry, then prints them. Corrections whose evidence changed show as
pending_review.
- --reviewer
- Defaults to
user.
What happens
- Validates the target, then appends a record to
corrections.json with correction_id, target_type, target_id, decision, original_value, replacement_value, rationale, reviewer, timestamp, evidence_locator, and status.
- Applies any side effects for that kind: registry reject, grant link, authorship flag, or person link.
- Corrections are an overlay, not an edit to extracted data. If re-extraction leaves the evidence unchanged, they carry over. If it materially changes, they flip to
pending_review, never silently reapplied or dropped.
Reads & writes
Appends to papers/<pmid>/corrections.json. Depending on the kind, also writes the claim registry, grants/<slug>.json, papers/<pmid>/authorship.json, or person records. verify.py also has a review-appraisal action for RoB2, NOS, and AMSTAR-2 domains, which /ref:review calls.
Examples
output from a scratch library
› /ref:verify author-contribution 31000001 0 shared_first --evidence ""
error: author_contribution flag 'shared_first' refused: an explicit evidence statement is required, never inferred from author position (§3c)
› /ref:verify author-contribution 31000001 0 shared_first --evidence "These authors contributed equally to this work."
{
"author_index": 0,
"flag": "shared_first",
"evidence_statement": "These authors contributed equally to this work.",
"reviewer": "user",
"timestamp": "2026-09-15T10:14:35.548943+00:00"
}
illustrative output
› /ref:verify claim 31000001 <claim_id> reject --rationale "Effect reported for adolescents, not adults"
{
"correction_id": "cor-…",
"target_type": "claim",
"target_id": "<claim_id>",
"decision": "reject",
"original_value": { "population": "…", "intervention": "…", "comparator": "…", "outcome": "…" },
"replacement_value": null,
"rationale": "Effect reported for adolescents, not adults",
"reviewer": "user",
"timestamp": "…",
"evidence_locator": "…",
"status": "active"
}
Under the hood
verify.py review-claim | review-grant-link | review-author-contribution | review-person-identity | show --repo … --pmid …. Command words map to script flags: --replacement → --replacement-file, --evidence → --evidence-statement, the flag word → --flag, the grant slug → --grant, the person slug → --person.
See also
/ref:extract · /ref:grant · /ref:person · /ref:report · Concepts
Group PMIDs that report the same underlying investigation, and record the datasets and methods papers share.
/ref:study create-study <study-id> --pmid <pmid…> --confidence confirmed|likely|uncertain --evidence "<why>"
/ref:study create-dataset <dataset-id> --name "<display name>" [--pmid <pmid…>] [--notes "…"]
/ref:study create-method <method-id> --name "<display name>" [--pmid <pmid…>] [--context "…"] [--locator "…"]
/ref:study list-studies | list-datasets | list-methods
Arguments
- create-study
- Needs at least one PMID, a confidence, and a non-empty
--evidence such as a shared trial registration or an explicit "we previously reported…". It is refused without evidence. New studies start with review_state: "unreviewed".
- create-dataset
- Records a cohort or dataset that papers reuse. Linking two papers to the same dataset does not make them one study.
- create-method
- Records a protocol, tool, or control, with optional context and a source locator.
- list-studies · list-datasets · list-methods
- Print the corresponding JSONL file as a JSON array.
What happens
- Allocates the ID as a library-global slug. A collision is refused with the conflicting record named, never silently suffixed.
- Appends the row under the library lock.
Why grouping is explicit: several papers from one trial shouldn't count as independent evidence, but shared authors or a shared dataset don't prove two papers report the same trial. /ref:compare and --study <id> therefore only trust groupings you have stated.
Reads & writes
Appends to studies/studies.jsonl, studies/datasets.jsonl, or studies/methods.jsonl.
Examples
output from a scratch library
› /ref:study create-study asd-multisite --pmid 31000001 31000002 --confidence likely --evidence "Same cohort registration cited in both methods sections"
{
"study_id": "asd-multisite",
"pmids": [
"31000001",
"31000002"
],
"confidence": "likely",
"evidence": "Same cohort registration cited in both methods sections",
"review_state": "unreviewed",
"created_at": "2026-09-15T10:14:35.054841+00:00",
"updated_at": "2026-09-15T10:14:35.054841+00:00"
}
› /ref:study create-study asd-x --pmid 31000001 --confidence likely --evidence ""
error: evidence is required: why these PMIDs are the same investigation (§3b)
› /ref:study create-dataset abide-ii --name "ABIDE II" --pmid 31000001
{
"dataset_id": "abide-ii",
"name": "ABIDE II",
"pmids": [
"31000001"
],
"notes": null,
"created_at": "2026-09-15T10:14:35.247166+00:00"
}
Under the hood
study.py create-study|create-dataset|create-method|list-studies|list-datasets|list-methods --repo … [--id …] [--pmid …] [--confidence …] [--evidence …] [--name …] [--notes …] [--context …] [--locator …]
See also
/ref:compare · /ref:methods · /ref:review --prisma · --study selector