> Cross-cutting reference manager for medical manuscripts. Single entry point for citation-key validation, journal-CSL pandoc rendering, manuscript ↔ DOCX cross-reference QC, marker conversion (``[N]`` ↔ ``[@key]``), and native Zotero CWYW field-code injection. Replaces the inline reference-handling that previously lived in ``/write-paper`` Phase 7.6 and is reused by ``/revise``, ``/peer-review``, ``/sync-submission``, and any skill that produces a journal submission. Audit-only verification stays in ``/verify-refs`` — this skill writes (renders, injects, converts); that skill only reads.
npx skills add https://github.com/Aperivue/medsci-skills --skill manage-refs
> Canonical source (issue #16). This SKILL.md is the single canonical
> reference for the reference-*workflow* (validate keys → render CSL → convert
> markers → QC cross-references → inject Zotero CWYW). Audit-only bib
> verification is owned by skills/verify-refs/SKILL.md. Any user-scope rule or
> external note about reference handling should point here (workflow) or to
> verify-refs (audit) rather than restating the "how", to prevent drift.
You are routing reference-handling work for a medical manuscript. The user is
somewhere in the lifecycle — drafting, building a circulation DOCX, swapping
CSL after a journal rejection, fixing a cross-reference defect surfaced by
QC, or wiring up live Zotero field codes for a co-author Word workflow. Pick
the right tool from the decision table; do not invent a parallel pipeline.
Reference handling spans every late-stage skill: /write-paper builds the
first DOCX, /revise rebuilds it after each reviewer round, /peer-review
emits a critique that quotes references back, /sync-submission packages the
final tarball, /find-journal informs CSL swaps on rejection cascade, and
/verify-refs audits the bibliography. Until 2026-05-01 these scripts lived
under skills/write-paper/scripts/, which made /revise and /sync-submission
silently depend on a sibling skill — a layering inversion that broke when
/write-paper was loaded into a non-research project. Moving the
lifecycle tools here turns reference handling into a first-class concern
with one decision tree, one set of CSL files, and one provenance file
(NOTICE.md) for the vendored Zotero CWYW writer.
Validated 2026-05-01 against a 21-reference meta-analysis manuscript
(a meta-analysis project's submission) for both pandoc-citeproc and Zotero-CWYW paths.
[@bibkey] resolvable in refs.bib. scripts/check_citation_keys.py is
a hard gate — UNDEFINED keys exit non-zero and block the build.
[@NEW:topic] placeholder convention: while drafting, /write-paper
may emit [@NEW:topic_slug] markers for citations the author still needs
to source. check_citation_keys.py classifies these as NEW_PLACEHOLDER
(not UNDEFINED) and exits 0 — the build is allowed to proceed during
drafting. Phase 7.6 (DOCX render) is a hard gate: zero NEW_PLACEHOLDER
entries must remain. Resolve each by adding the citation to Zotero (then
/lit-sync refreshes refs.bib) and replacing the placeholder with the
real [@bibkey]. Never let a [@NEW:...] reach a rendered DOCX.
pandoc citeproc + journal CSL or by the Zotero Word plugin (CWYW). See
~/.claude/rules/manuscript-references.md.
inject_zotero_cwyw.py fetchesitem data live from http://localhost:23119. Any HTTP failure aborts
with a non-zero exit so partial bibliographies never reach the user.
md_marker_convert.py willnever guess a Zotero key for a number; unmapped markers stay as [N]
and are reported on stderr.
scripts/check_xref.py--strict exits 1 on any MISSING_DOCX / MISSING_BODY / MISMATCH,
blocking pipelines that try to ship a DOCX whose Table/Figure citations
don't match captions. --allow-separate-attachments downgrades the two
rows a separate-attachment submission legitimately produces; it never
downgrades a MISSING_BODY whose float IS in the rendered DOCX.
PubMed/CrossRef stays in /verify-refs. Always invoke /verify-refs
after a render before signing off — one read-only audit, one writer.
| Situation | Tool | Why |
|---|---|---|
| Validate [@bibkey] ↔ refs.bib (UNDEFINED / UNUSED keys) | scripts/check_citation_keys.py | Hard build gate, runs in seconds |
| Single-author submission lockdown, frozen output | scripts/render_pandoc.sh -j <journal> | Reproducible, CI-friendly |
| Cascade rejection (e.g., ER → JVIR → CVIR) | render_pandoc.sh with new -j | CSL swap reformats references in seconds |
| Verify a journal CSL renders the in-text format / DOI / journal-name style the author guide actually requires | scripts/check_csl_render.py --csl <x>.csl --bib refs.bib --journal <key> | A stub/"dependent" CSL inherits its parent's format, which may differ from the guide (parenthetical vs superscript, DOI kept, full journal names). Run BEFORE submission, not after the proof PDF |
| Reference list prints FULL journal names but the journal wants NLM abbreviations | scripts/fill_journal_abbrev.py | Resolves each entry DOI → PMID → PubMed NLM shortjournal into the .bib so CSL form="short" renders abbreviations; authoritative source, never invents abbreviations |
| Reviewer revision: add 1–2 refs to a Word doc with co-authors live | Zotero Word plugin (user GUI) | Minimal disruption to track-changes flow |
| Reviewer revision: bulk reference change | Edit markdown SSOT, re-run render_pandoc.sh | Consistency, no cherry-pick risk |
| Migrate [N] numeric markers → [@key] for pandoc | scripts/md_marker_convert.py --to-keys | Mapping-driven, partial conversion safe |
| Convert [@key] → [N] for round-trip / debug | scripts/md_marker_convert.py --to-numbers | Same map, opposite direction |
| Wire native Zotero CWYW field codes into a .docx (live Refresh in Word) | scripts/inject_zotero_cwyw.py | Co-author Word workflow, post-circulation editability |
| Manuscript ↔ rendered DOCX cross-reference QC | scripts/check_xref.py --strict | Submission gate (P0 blocker on mismatch) |
| Figures/tables submitted as separate attachments (radiology, most medical journals) | check_xref.py --strict --allow-separate-attachments | Downgrades MISSING_DOCX to WARN; MISSING_BODY/MISMATCH remain P0 |
| v_(N+1) docx build-time regeneration check | check_xref.py --vN-docx-md5 <prev>.docx [--vN-md <prev>.md] | Defense-in-depth: identity = unmodified seed copy; missing diff lines = body not regenerated |
| Duplicate bibliography in the built artifact | scripts/check_reference_duplication.py --docx <built>.docx (or --text <rendered>.md) | Fires when the reference list is duplicated — DUP_REF_HEADING / REF_NUMBER_RESTART / REF_SIGNATURE_DUP (Major). Catches the hybrid hand-typed ## References list + pandoc --citeproc auto-bibliography, which renders two lists (the second often after the legends). Run after any citeproc build |
| Publisher markup in a .bib title (renders as garbage) | scripts/check_bib_title_markup.py --bib refs.bib --strict | CrossRef ships <scp>WHO</scp> / <i>IDH</i> in titles and a DOI-add stores them verbatim; BBT then escapes them ({$<$}scp{$>$}) or strips them without restoring the space (andTERTPromoter, 1p/19q,IDH). verify_refs proves the reference is *true*; this proves it will *print*. TITLE_MARKUP / TITLE_FUSION (Major) |
| Master pre-submission gate (recommended before any submission) | scripts/pre_submission_gate.sh | Chains check_citation_keys → check_bib_title_markup → verify_refs --strict → render_pandoc (optional) → check_xref --strict; single artifact qc/pre_submission_gate.json |
| Direct render with a built-in reference audit | scripts/render_pandoc.sh (audits the .bib via /verify-refs first; blocks on FABRICATED/MISMATCH/duplicates) | Defense-in-depth so even a direct render call cannot ship hallucinated citations; best-effort (skips with a warning if /verify-refs is not alongside), opt out with -S. The master gate passes -S since it audits in stage 2 |
| Bibliographic audit against PubMed / CrossRef | delegate to /verify-refs | Audit-only — keep writer/auditor separation |
User provides manuscript.md with [@bibkey] citations + refs.bib.
python "${CLAUDE_SKILL_DIR}/scripts/check_citation_keys.py" manuscript.md refs.bib— exits non-zero on UNDEFINED keys. Fix and re-run.
"${CLAUDE_SKILL_DIR}/scripts/render_pandoc.sh" \
-j european-radiology \
-i manuscript.md \
-b refs.bib \
-o manuscript_final.docx
For the current inventory and what each style renders, read
citation_styles/README.md — that table is the registry. render_pandoc.sh also lists
what is on disk when -j names a style it cannot find, so ask the script rather than
trusting a list written here. Two standing fallbacks: use radiology for RYAI and
vancouver for JVIR (neither has a dedicated CSL).
python3 "${CLAUDE_SKILL_DIR}/scripts/check_xref.py" \
--md manuscript.md --docx manuscript_final.docx \
--out qc/xref_audit.json --strict
Treat submission_safe: false as a halt. Route fixes by symptom — see
the table in references/check_xref_symptoms.md.
/verify-refs for the PubMed/CrossRef auditbefore sign-off.
User has a markdown SSOT and wants reviewers to edit citations directly in
Word. Each reference must already exist as a Zotero item; the user supplies
a [N] → ZoteroKey mapping.
python3 "${CLAUDE_SKILL_DIR}/scripts/md_marker_convert.py" \
--input manuscript.md --output manuscript_keys.md \
--map ref_map.json --to-keys
Optionally stage with --active-ns 1,2,3,4,19 for a sample build first
(validated on an active meta-analysis project: 5-ref sample reduces Word Refresh blast radius
when debugging).
[@key] markers, OR pre-build a .docx some other way that still contains
plain [@key] text.
python3 "${CLAUDE_SKILL_DIR}/scripts/inject_zotero_cwyw.py" \
--input manuscript_keys.docx --output manuscript_cwyw.docx \
--user-id 16613550 --keys-from keys.txt
The script fetches Zotero metadata via the local connector (port 23119);
any HTTP failure aborts with non-zero exit.
the output in Word → Zotero tab → Add/Edit Bibliography once. After
that, Refresh keeps citations and bibliography in sync as authors
edit.
the markdown SSOT and rebuild the whole .docx instead of regex-patching
the post-CWYW file. Zotero's rendered [N] superscripts can collide
with plain [N] markers and corrupt the field codes.
User got rejected from journal A and /find-journal recommended journal B.
citation_styles/ (or fetch fromhttps://citationstyles.org/styles and drop in).
render_pandoc.sh -j <new-csl> against the same manuscript.md +refs.bib.
check_xref.py --strict./verify-refs if any new references were added during theinter-journal revision.
User shipped a manuscript and a reviewer flagged a Table/Figure mismatch.
check_xref.py --strict on the current manuscript.md + .docx.qc/xref_audit.json. Body caption is the SSOT — fix manuscript.mdand rebuild, never patch the .docx by hand.
references/check_xref_symptoms.md for theMISSING_BODY / MISSING_DOCX / MISMATCH triage table.
(the default in European Radiology, Radiology, AJR, JVIR, KJR, and most
medical journals), pass --allow-separate-attachments. It downgrades two
rows, and the run reports them apart because their evidence differs:
MISSING_DOCX — a --docx was supplied and proved the float is not inthe rendered main document. That is what a separate attachment looks like.
MISSING_BODY with no --docx supplied — nothing was checked. The floatis either separately attached, as you declared, or a caption nobody wrote.
Excused on your word, printed as EXCUSED WITHOUT EVIDENCE, and counted in
summary.downgraded_unchecked.
MISMATCH stays P0. So does MISSING_BODY when the float is in the
rendered DOCX — that is SSOT drift, and no attachment policy makes the build
pipeline an acceptable single source of truth for a caption.
Run once with --docx before submitting. The flag is a declaration, not a
verification; supplying the DOCX is what converts an excuse into evidence.
When building v_(N+1) from a frozen v_N, the v_(N+1) docx MUST differ
from v_N docx by content — a byte-identical copy is a silent seed-copy
that will revert markdown edits at peer review. check_xref.py carries
two flags for the build-time companion to the submission-time gate
in scripts/verify_package_integrity.py --assert-vN-docx-changed:
python3 "${CLAUDE_SKILL_DIR}/scripts/check_xref.py" \
--md manuscript_v2.md \
--docx manuscript_v2.docx \
--vN-docx-md5 manuscript_v1.docx \
--vN-md manuscript_v1.md \
--strict
--vN-docx-md5 alone: MD5 identity check. Identical bytes = FAIL.--vN-docx-md5 + --vN-md: additionally extracts the markdown-only diffbetween v_N and v_(N+1) and verifies each ≥40-char diff line appears
verbatim (whitespace-normalized, case-insensitive) in the new docx
body XML. Missing diff lines = body did not pick up the markdown edits.
Output records the result under vN_docx_check in qc/xref_audit.json.
Either failure mode causes a non-zero exit even without --strict.
The single entry point that combines workflows A and D plus /verify-refs
into one aborting chain. Use this immediately before submission or before
circulating a v_N package to senior co-authors.
bash "${CLAUDE_SKILL_DIR}/scripts/pre_submission_gate.sh" \
--md manuscript/manuscript.md \
--bib manuscript/_src/refs.bib \
--docx submission/<journal>/manuscript.docx \
--allow-separate-attachments # omit if the journal accepts inline figures/tables
Stage order (first failure aborts):
check_citation_keys.py manuscript.md refs.bib — UNDEFINED / UNUSED keysverify_refs.py refs.bib --strict — PubMed / CrossRef per-entry verificationrender_pandoc.sh -j <csl> -i ... -b ... -o ... — invoked only when --docx is omittedcheck_xref.py --md ... --docx ... --strict [--allow-separate-attachments]On success the chain writes qc/pre_submission_gate.json (plus the
per-stage artifacts qc/reference_audit.json and qc/xref_audit.json)
with submission_safe: true. On any failure the JSON records the failing
stage and exit code, and the script exits non-zero — do not submit until
the failing stage passes.
Critical: the gate does not reimplement any check. It calls the existing
scripts as subprocesses. If you find yourself wanting to add a check, add it
to the underlying script (the gate then picks it up automatically).
Entries written as author = {Surname AB and Surname2 CD} (family + initials, no comma) make BibTeX treat the last token as the family name, rendering "AB S, CD S2". Always store author = {Family, Full Given}. Concatenated initials even with a comma (Family, AB) still collapse to a single initial under CSL initialize-with, so use the full forename from PubMed efetch.
/verify-refs compares bib content against PubMed but does not see the rendered output; grep the rendered docx and the bib separately:
unzip -p out.docx word/document.xml | sed 's/<[^>]*>//g' | grep -oE "[A-Z]{2} [A-Z], [A-Z]{2} [A-Z]" # corruption signature in output
grep -nE 'author\s*=\s*\{[A-Z][a-z]+ [A-Z]{1,3}( |\})' refs.bib # no-comma source entries
This skill defines three submission gates and one user approval gate:
check_citation_keys.py exits non-zero onUNDEFINED keys. The pipeline halts; the user reviews and fixes.
check_xref.py --strict exits 1 onany MISSING_DOCX / MISSING_BODY / MISMATCH row. The user reviews
qc/xref_audit.json and resolves before proceeding. Under
--allow-separate-attachments, check summary.downgraded_unchecked as well as
submission_safe: a non-zero count means rows passed without being checked.
/verify-refs and confirm submission_safe: true in
qc/reference_audit.json. This skill never marks the bibliography
audited on its own.
Zotero → Add/Edit Bibliography manually after the first
inject_zotero_cwyw.py build. The skill cannot automate this and warns
on stderr that it is required.
scripts/_vendor_citation_writer.py is vendored from
alisoroushmd/zotero-mcp @ ed5dfb71, MIT licensed. See
NOTICE.md and LICENSE.zotero-mcp.
~/.claude/rules/manuscript-references.md — global rule (decision treethis skill implements)
~/.claude/rules/agent-skill-routing.md — skill router (this skill is thereference-handling row)
~/.claude/rules/zotero-workflow.md — BBT auto-export, MCP setup/verify-refs — read-only audit (PubMed / CrossRef + first-authorcross-check)
/lit-sync — Zotero ↔ Obsidian sync, refs.bib provider/write-paper Phase 7.6 — calls this skill (one-line delegation)/revise, /sync-submission, /find-journal — call this skill onrebuild / re-render / cascade
inject_zotero_cwyw.py writes astub ADDIN ZOTERO_BIBL field; Word's Zotero Refresh treats an empty
stub as user-customized and refuses to populate it. User must run
Add/Edit Bibliography once. Subsequent Refresh works as expected.
Validated on Word for Mac, an active meta-analysis project.
zotero_to_csl_json that fetches Zotero's native CSL-JSON; do not bypass
this patch.
web-API fallback yet (would need ZOTERO_API_KEY). On failure the script
aborts with non-zero exit so partial builds never ship.
Some passages in this skill cite a path of the form ~/.claude/rules/<name>.md. Those are the
maintainer's personal global rules, kept outside this repository. They are **not shipped with
this skill** and will not exist on your machine; they appear only as provenance for where a
convention came from. If one of them looks like it is standing in for an instruction you actually
need, that is a bug — please open an issue, because the instruction belongs here.
Assists in writing high-quality content by conducting research, adding citations, improving hooks, iterating on outlines, and providing real-time feedback on each section. Transforms your writing process from solo effort to collaborative partnership.
Identifies high-quality leads for your product or service by analyzing your business, searching for target companies, and providing actionable contact strategies. Perfect for sales, business development, and marketing professionals.
Use this skill to query your Google NotebookLM notebooks directly from Claude Code for source-grounded, citation-backed answers from Gemini. Browser automation, library management, persistent auth. Drastically reduced hallucinations through document-only responses.
Efficient database search tool for bioRxiv preprint server. Use this skill when searching for life sciences preprints by keywords, authors, date ranges, or categories, retrieving paper metadata, downloading PDFs, or conducting literature reviews.
Query and analyze scholarly literature using the OpenAlex database. This skill should be used when searching for academic papers, analyzing research trends, finding works by authors or institutions, tracking citations, discovering open access publications, or conducting bibliometric analysis across 240M+ scholarly works. Use for literature searches, research output analysis, citation analysis, and academic database queries.
Access USPTO APIs for patent/trademark searches, examination history (PEDS), assignments, citations, office actions, TSDR, for IP analysis and prior art searches.
Multiagent AI system for scientific research assistance that automates research workflows from data analysis to publication. This skill should be used when generating research ideas from datasets, developing research methodologies, executing computational experiments, performing literature searches, or generating publication-ready papers in LaTeX format. Supports end-to-end research pipelines with customizable agent orchestration.
Automated LLM-driven hypothesis generation and testing on tabular datasets. Use when you want to systematically explore hypotheses about patterns in empirical data (e.g., deception detection, content analysis). Combines literature insights with data-driven hypothesis testing. For manual hypothesis formulation use hypothesis-generation; for creative ideation use scientific-brainstorming.
Take aperivue/manage-refs from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.