Create and inspect researcher identity records: name variants, ORCID, and confirmed, candidate and rejected publication matches.
/ref:person create <slug> --name "<Last, First>" [--orcid <id>]
/ref:person show <slug>
/ref:person list
Arguments
- create
- Mints
people/<slug>.json with one name variant. The slug is yours and library-global. A duplicate is refused and the conflicting record is named. It is never suffixed or overwritten.
- show
- The full record, including
discovery_runs once /ref:discover has run.
- list
- Slug and name variants for every person.
The script also implements confirm-publication --slug --pmid --author-index and reject-publication --slug --pmid, which /ref:discover points you to. The /ref:person command file lists only create/show/list; /ref:verify review-person-identity reaches the same functions and also logs a correction record.
What happens
- Resolves the library root.
- Runs
person.py with the matching action and prints its JSON verbatim.
Reads & writes
Writes people/<slug>.json (create). Fields: slug, name_variants, orcid, affiliations, confirmed_publications, candidate_publications, rejected_publications.
Example
output from a scratch library
› /ref:person create moreau-c --name "Moreau, Claire" --orcid 0000-0002-1825-0097
{
"slug": "moreau-c",
"name_variants": ["Moreau, Claire"],
"orcid": "0000-0002-1825-0097",
"affiliations": [],
"confirmed_publications": [],
"candidate_publications": [],
"rejected_publications": []
}
› /ref:person create moreau-c --name "Moreau, C"
error: person 'moreau-c' already exists at people/moreau-c.json
› /ref:person list
[
{"slug": "moreau-c", "name_variants": ["Moreau, Claire"]},
{"slug": "tanaka-h", "name_variants": ["Tanaka H"]}
]
Under the hood
person.py {create|show|list|confirm-publication|reject-publication} --repo <root> --slug … [--name …] [--orcid …] [--pmid …] [--author-index N]
See also
/ref:discover · /ref:publications · /ref:verify · PI report tutorial
/ref:publications
phase 2read-only
List a person's confirmed publications with their authorship role, or derive a coauthor declaration for a date window.
/ref:publications --person <id> [--role sole|first|last|middle|unresolved]
/ref:publications --person <id> --coauthors --since <date> [--to <date>]
Arguments
- --person
- Required person slug.
- --role
- Filter the role list. Roles are mutually exclusive: one author is
sole, index 0 is first, the final index is last, anything else is middle, and an incomplete author list gives unresolved.
- --coauthors --since [--to]
- A collaborator declaration (e.g. for NSF/NIH), compared at year granularity.
What happens
- Reads
confirmed_publications only; candidates never count.
- Roles: classifies each confirmed
author_index against authorship.json.
- Coauthors: an author at a position another person has confirmed is grouped by that identity (
confirmed_identity). Group authors stay one named group. A name matching another person's variant with no confirmed link goes to unconfirmed_candidates, and everyone else is keyed by exact_name.
- Every paper in the window with an incomplete author list appears in
gaps. None of these lists may be dropped when summarizing.
Reads & writes
Reads people/*.json, papers/<pmid>/meta.json, authorship.json. Writes nothing. contribution_flags (shared_first / shared_senior / corresponding) are not part of this output.
Example
output from a scratch library
› /ref:publications --person moreau-c
[
{"pmid": "38000001", "author_index": 2, "role": "last", "author_count": 3},
{"pmid": "38000002", "author_index": 0, "role": "first", "author_count": 2},
{"pmid": "38000003", "author_index": 0, "role": "sole", "author_count": 1}
]
› /ref:publications --person moreau-c --coauthors --since 2023 --to 2024
{
"person": "moreau-c",
"since": "2023",
"until": "2024",
"coauthors": [
{"name": "Lindqvist E", "identity_method": "exact_name", "affiliation": null,
"most_recent_pub": "2023", "pmids": ["38000001"]},
{"name": "Okafor A", "identity_method": "exact_name", "affiliation": null,
"most_recent_pub": "2023", "pmids": ["38000001"]}
],
"unconfirmed_candidates": [
{"name": "Tanaka H", "candidate_person": "tanaka-h", "pmids": ["38000002"]}
],
"gaps": [],
"scope_note": "derived from library holdings, not a complete publication record (§3c)"
}
Under the hood
publications.py --repo <root> --person <id> [--role …] [--coauthors --since … [--to …]]
See also
/ref:report · /ref:person · /ref:verify
Create and inspect grant records: funder, award number, approved award aliases, title, PI and aims.
/ref:grant create <slug> --funder "<name>" --award "<award number>" [--title "…"] [--pi <person-slug>] [--aims "…"]
/ref:grant add-alias <slug> --alias "<award string>"
/ref:grant show <slug>
/ref:grant list
Arguments
- create
- Mints
grants/<slug>.json. The award number seeds approved_aliases. A duplicate slug is refused and the conflicting record is named.
- add-alias
- Keeps another string the funder uses for the same award, e.g.
HL123456 next to R01 HL123456. Existing aliases are never overwritten, and re-adding one is a no-op.
- show / list
- Full record, or slug/funder/award for all grants.
Why explicit aliases? Funders report one award under several normalized or legacy strings, but two similar strings can also be two different awards. Matching is exact against approved aliases, so merging them is always your decision.
What happens
- Resolves the library root.
- Runs
grant.py and prints its JSON verbatim.
- On the next
/ref:weave, graph_people.py links each funding.json observation whose award string exactly matches an alias as publication_acknowledges_grant, carrying the observation's evidence_kind.
Reads & writes
Writes grants/<slug>.json: slug, funder, award_number, approved_aliases, title, pi, aims, publication_links (filled by /ref:verify review-grant-link).
Example
output from a scratch library
› /ref:grant create hl123456 --funder "NHLBI" --award "R01 HL123456" --title "Blood pressure and brain health" --pi moreau-c
› /ref:grant add-alias hl123456 --alias "HL123456"
{
"aims": null,
"approved_aliases": ["R01 HL123456", "HL123456"],
"award_number": "R01 HL123456",
"funder": "NHLBI",
"pi": "moreau-c",
"publication_links": [],
"slug": "hl123456",
"title": "Blood pressure and brain health"
}
› /ref:weave --regenerate-only
# graph_people.py half; both GrantList strings now match one grant
{
"researcher_authored_publication": 3,
"publication_acknowledges_grant": 2,
"publication_supports_aim": 0,
"researcher_lab_membership": 0,
"publication_supports_aim_note": "unpopulated -- no mechanism in any phase links a publication to a specific grant aim (§5a)",
"researcher_lab_membership_note": "unpopulated -- no /ref:lab command exists in PLAN.md; labs/<slug>.json has no writer yet"
}
Under the hood
grant.py {create|add-alias|show|list} --repo <root> --slug … [--funder …] [--award …] [--alias …] [--title …] [--pi …] [--aims …]
See also
/ref:verify · /ref:weave · /ref:fetch (JATS funding extraction)
/ref:discover
phase 2PubMed
Run a manually started PubMed author search for one researcher and store the results as candidates awaiting your confirmation.
/ref:discover --person <id>
Arguments
- --person
- Required person slug.
- --grant
- Not implemented: grant records have no candidate-publication fields yet. The script refuses with an error.
What happens
- Reads the person record and builds an author query from name variants (and ORCID, if present).
- Calls PubMed search with that exact query, then writes the candidates (at least
pmid, title) to a temp file.
discover.py appends a discovery_runs entry and adds new candidates. PMIDs already confirmed or rejected are skipped.
- You confirm each real match at its author position, or reject it. The agent never treats a candidate as confirmed.
Reads & writes
Updates people/<slug>.json: candidate_publications, discovery_runs. Does not add papers to the library; ingest confirmed papers with /ref:add.
Example
output from a scratch library (candidate list supplied by hand)
› /ref:discover --person moreau-c
# PubMed query: Moreau C[Author] → 4 hits
{
"candidate_publications": [
{"pmid": "38000001", "title": "Drug X lowers systolic blood pressure in adults with hypertension"},
{"pmid": "38000002", "title": "Drug X raises systolic blood pressure at 12 weeks"},
{"pmid": "38000003", "title": "Systolic blood pressure and cognitive decline"},
{"pmid": "37999999", "title": "An unrelated Moreau paper"}
],
"confirmed_publications": [],
…
"discovery_runs": [
{"query": "Moreau C[Author]", "retrieved_at": "2026-09-15T10:15:26.979997+00:00", "candidate_count": 4}
]
}
# confirm Moreau's real positions, reject the stranger (person.py actions)
person.py confirm-publication --slug moreau-c --pmid 38000001 --author-index 2
person.py reject-publication --slug moreau-c --pmid 37999999
› /ref:discover --grant hl123456
error: --grant discovery is not implemented in phase 2 (grants have no candidate-publication fields yet); use --person
Under the hood
person.py show, then discover.py --repo <root> --person <id> --query-text "<exact query>" --candidates-file <json>. The PubMed call is made by the command, never by the script.
See also
/ref:person · /ref:verify · /ref:search-pubmed
/ref:report
phase 2--citations: phase 11
Generate a reproducible publication report for one researcher and year window, as a manifest, a CSV and Markdown.
/ref:report --person <id> --from <date> --to <date> [--label <slug>] [--citations [--stale-days N]]
Arguments
- --person
- Required person slug.
- --from / --to
- Required. Compared at year granularity (
publication_year).
- --label
- Output folder name. Default
<person>-<from>-<to>.
- --citations
- Add PMC-indexed citing-article counts from
/ref:audit --citations observations.
- --stale-days N
- Flag a count older than N days as stale (default 180).
What happens
- Takes confirmed publications only. Papers with no
meta.json or no year are excluded, never guessed.
- Classifies role as
/ref:publications does and sorts by year, then PMID.
- Writes the CSV and Markdown, then a manifest recording the policies used. Rerunning with unchanged data reproduces identical CSV/Markdown; only
generated_at differs.
- Each exported row now includes provenance fields (
extraction_tier, abstract_available, full_text, and checked_at) so freshness and source state travel with the report.
- With
--citations, each count carries its source and retrieval date. No observation reads unknown, never 0, and the number is never called "citations".
Not implemented yet: grouping by grant or lab. This is the basic single-person report.
Reads & writes
Reads people/<slug>.json, meta.json, authorship.json, citation observations. Writes reports/<label>/manifest.json, publications.csv (pmid, citekey, doi, year, journal, title, author_role, plus extraction_tier, abstract_available, full_text, checked_at, citation_count, citation_source, citation_retrieved_at, citation_coverage, citation_stale with --citations), report.md.
Example
output from a scratch library
› /ref:report --person moreau-c --from 2023 --to 2024
{
"person": "moreau-c",
"from": "2023",
"to": "2024",
"date_basis": "publication_year",
"missing_date_handling": "excluded",
"identity_review_policy": "confirmed_publications_only",
"dedup_policy": "unique_by_pmid",
"publication_count": 3,
"generated_at": "2026-09-15T10:15:27.854144+00:00",
"includes_citations": false
}
# reports/moreau-c-2023-2024/publications.csv
pmid,citekey,doi,year,journal,title,author_role
38000001,okafor2023drug,10.1000/a1,2023,Hypertension,Drug X lowers systolic blood pressure in adults with hypertension,last
38000002,moreau2024drug,10.1000/a2,2024,J Hypertens,Drug X raises systolic blood pressure at 12 weeks,first
38000003,moreau2024systolic,10.1000/a3,2024,Neurology,Systolic blood pressure and cognitive decline,sole
› /ref:report --person moreau-c --from 2023 --to 2024 --label moreau-2023-2024-cit --citations
# report.md, no /ref:audit --citations run yet
| PMID | Year | Role | Title | Citing articles (PMC) | Source | Retrieved | Stale |
|---|---|---|---|---|---|---|---|
| 38000001 | 2023 | last | Drug X lowers systolic blood pressure in adults with hypertension | unknown | — | — | — |
| 38000002 | 2024 | first | Drug X raises systolic blood pressure at 12 weeks | unknown | — | — | — |
| 38000003 | 2024 | sole | Systolic blood pressure and cognitive decline | unknown | — | — | — |
Total unique publications: 3
Under the hood
report.py --repo <root> --person <id> --from … --to … [--label …] [--citations] [--stale-days N]; role logic from publications.classify_role, observations from audit.latest_real_observation.
See also
/ref:publications · /ref:audit · PI report tutorial