Manage-Refs Skill
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.
Why This Skill Exists
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.
Anti-Hallucination Guarantees
Citekey discipline (Phase 0): every in-text citation must be
[@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.
No hand-typed References list — references are always rendered by
pandoc citeproc + journal CSL or by the Zotero Word plugin (CWYW). See
~/.claude/rules/manuscript-references.md.
Zotero metadata is never invented — inject_zotero_cwyw.py fetches
item data live from http://localhost:23119. Any HTTP failure aborts
with a non-zero exit so partial bibliographies never reach the user.
Marker conversion is mapping-driven — md_marker_convert.py will
never guess a Zotero key for a number; unmapped markers stay as [N]
and are reported on stderr.
Cross-reference QC is a submission gate — 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.
Audit boundary: this skill writes; bibliographic correctness against
PubMed/CrossRef stays in /verify-refs. Always invoke /verify-refs
after a render before signing off — one read-only audit, one writer.
Decision Tree
| 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 |
| 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) |
| Bibliographic audit against PubMed / CrossRef |
delegate to /verify-refs |
Audit-only — keep writer/auditor separation |
Workflows
A. Pandoc citeproc (default for solo authors and final submissions)
User provides manuscript.md with [@bibkey] citations + refs.bib.
- Gate:
python "${CLAUDE_SKILL_DIR}/scripts/check_citation_keys.py" manuscript.md refs.bib
— exits non-zero on UNDEFINED keys. Fix and re-run.
- Render:
"${CLAUDE_SKILL_DIR}/scripts/render_pandoc.sh" \
-j european-radiology \
-i manuscript.md \
-b refs.bib \
-o manuscript_final.docx
Bundled CSLs (in citation_styles/): european-radiology, radiology,
american-journal-of-roentgenology, cardiovascular-and-interventional-radiology,
korean-journal-of-radiology, vancouver, vancouver-superscript,
springer-basic-brackets, springer-vancouver-brackets. Use
radiology for RYAI; use vancouver for JVIR (no dedicated CSL).
- QC:
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.
- Audit hand-off: invoke
/verify-refs for the PubMed/CrossRef audit
before sign-off.
B. Zotero CWYW (co-author Word workflow)
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.
- Convert markers:
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).
- Render to .docx with pandoc (workflow A) so the body has plain text
[@key] markers, OR pre-build a .docx some other way that still contains
plain [@key] text.
- Inject CWYW:
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.
- First-build instruction (REQUIRED — see Known Limitation #1): open
the output in Word → Zotero tab → Add/Edit Bibliography once. After
that, Refresh keeps citations and bibliography in sync as authors
edit.
- Surgical patches are unsafe: for ref additions in later rounds, 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.
C. Cascade rejection re-render (find-journal hand-off)
User got rejected from journal A and /find-journal recommended journal B.
- Confirm the new CSL exists in
citation_styles/ (or fetch from
https://citationstyles.org/styles and drop in).
- Re-run
render_pandoc.sh -j <new-csl> against the same manuscript.md +
refs.bib.
- Re-run
check_xref.py --strict.
- Re-run
/verify-refs if any new references were added during the
inter-journal revision.
D. Cross-reference QC only
User shipped a manuscript and a reviewer flagged a Table/Figure mismatch.
- Run
check_xref.py --strict on the current manuscript.md + .docx.
- Inspect
qc/xref_audit.json. Body caption is the SSOT — fix manuscript.md
and rebuild, never patch the .docx by hand.
- See
references/check_xref_symptoms.md for the
MISSING_BODY / MISSING_DOCX / MISMATCH triage table.
Quality Gates
This skill defines three submission gates and one user approval gate:
- Gate 1 (citekey integrity):
check_citation_keys.py exits non-zero on
UNDEFINED keys. The pipeline halts; the user reviews and fixes.
- Gate 2 (cross-reference integrity):
check_xref.py --strict exits 1 on
any MISSING_DOCX / MISSING_BODY / MISMATCH row. The user reviews
qc/xref_audit.json and resolves before proceeding.
- Gate 3 (audit hand-off): before sign-off, the user must run
/verify-refs and confirm submission_safe: true in
qc/reference_audit.json. This skill never marks the bibliography
audited on its own.
- User approval gate (CWYW first build): the user must perform Word →
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.
Provenance
scripts/_vendor_citation_writer.py is vendored from
alisoroushmd/zotero-mcp @ ed5dfb71, MIT licensed. See
NOTICE.md and LICENSE.zotero-mcp.
Related
~/.claude/rules/manuscript-references.md — global rule (decision tree
this skill implements)
~/.claude/rules/agent-skill-routing.md — skill router (this skill is the
reference-handling row)
~/.claude/rules/zotero-workflow.md — BBT auto-export, MCP setup
/verify-refs — read-only audit (PubMed / CrossRef + first-author
cross-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 on
rebuild / re-render / cascade
Known Limitations
- First-build empty BIBL field (CWYW):
inject_zotero_cwyw.py writes a
stub 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.
- Webpage / non-journal item types: handled by the patched
zotero_to_csl_json that fetches Zotero's native CSL-JSON; do not bypass
this patch.
- Surgical post-build regex patches are unsafe — see Workflow B step 5.
- Local Zotero required for CWYW — port 23119 must be reachable; no
web-API fallback yet (would need
ZOTERO_API_KEY). On failure the script
aborts with non-zero exit so partial builds never ship.
1---2name: manage-refs3description: 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.4---56# Manage-Refs Skill78You are routing reference-handling work for a medical manuscript. The user is9somewhere in the lifecycle — drafting, building a circulation DOCX, swapping10CSL after a journal rejection, fixing a cross-reference defect surfaced by11QC, or wiring up live Zotero field codes for a co-author Word workflow. Pick12the right tool from the decision table; do not invent a parallel pipeline.1314## Why This Skill Exists1516Reference handling spans every late-stage skill: `/write-paper` builds the17first DOCX, `/revise` rebuilds it after each reviewer round, `/peer-review`18emits a critique that quotes references back, `/sync-submission` packages the19final tarball, `/find-journal` informs CSL swaps on rejection cascade, and20`/verify-refs` audits the bibliography. Until 2026-05-01 these scripts lived21under `skills/write-paper/scripts/`, which made `/revise` and `/sync-submission`22silently depend on a sibling skill — a layering inversion that broke when23`/write-paper` was loaded into a non-research project. Moving the24lifecycle tools here turns reference handling into a first-class concern25with one decision tree, one set of CSL files, and one provenance file26(`NOTICE.md`) for the vendored Zotero CWYW writer.2728Validated 2026-05-01 against a 21-reference meta-analysis manuscript29(a meta-analysis project's submission) for both pandoc-citeproc and Zotero-CWYW paths.3031## Anti-Hallucination Guarantees32331. **Citekey discipline (Phase 0)**: every in-text citation must be34 `[@bibkey]` resolvable in `refs.bib`. `scripts/check_citation_keys.py` is35 a hard gate — UNDEFINED keys exit non-zero and block the build.3637 **`[@NEW:topic]` placeholder convention**: while drafting, `/write-paper`38 may emit `[@NEW:topic_slug]` markers for citations the author still needs39 to source. `check_citation_keys.py` classifies these as `NEW_PLACEHOLDER`40 (not UNDEFINED) and exits 0 — the build is allowed to proceed during41 drafting. Phase 7.6 (DOCX render) is a hard gate: zero NEW_PLACEHOLDER42 entries must remain. Resolve each by adding the citation to Zotero (then43 `/lit-sync` refreshes refs.bib) and replacing the placeholder with the44 real `[@bibkey]`. Never let a `[@NEW:...]` reach a rendered DOCX.452. **No hand-typed References list** — references are always rendered by46 pandoc citeproc + journal CSL or by the Zotero Word plugin (CWYW). See47 `~/.claude/rules/manuscript-references.md`.483. **Zotero metadata is never invented** — `inject_zotero_cwyw.py` fetches49 item data live from `http://localhost:23119`. Any HTTP failure aborts50 with a non-zero exit so partial bibliographies never reach the user.514. **Marker conversion is mapping-driven** — `md_marker_convert.py` will52 never guess a Zotero key for a number; unmapped markers stay as `[N]`53 and are reported on stderr.545. **Cross-reference QC is a submission gate** — `scripts/check_xref.py`55 `--strict` exits 1 on any `MISSING_DOCX` / `MISSING_BODY` / `MISMATCH`,56 blocking pipelines that try to ship a DOCX whose Table/Figure citations57 don't match captions.586. **Audit boundary**: this skill writes; bibliographic correctness against59 PubMed/CrossRef stays in `/verify-refs`. Always invoke `/verify-refs`60 after a render before signing off — one read-only audit, one writer.6162## Decision Tree6364| Situation | Tool | Why |65|---|---|---|66| Validate `[@bibkey]` ↔ `refs.bib` (UNDEFINED / UNUSED keys) | `scripts/check_citation_keys.py` | Hard build gate, runs in seconds |67| Single-author submission lockdown, frozen output | `scripts/render_pandoc.sh -j <journal>` | Reproducible, CI-friendly |68| Cascade rejection (e.g., ER → JVIR → CVIR) | `render_pandoc.sh` with new `-j` | CSL swap reformats references in seconds |69| 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 |70| Reviewer revision: bulk reference change | Edit markdown SSOT, re-run `render_pandoc.sh` | Consistency, no cherry-pick risk |71| Migrate `[N]` numeric markers → `[@key]` for pandoc | `scripts/md_marker_convert.py --to-keys` | Mapping-driven, partial conversion safe |72| Convert `[@key]` → `[N]` for round-trip / debug | `scripts/md_marker_convert.py --to-numbers` | Same map, opposite direction |73| 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 |74| Manuscript ↔ rendered DOCX cross-reference QC | `scripts/check_xref.py --strict` | Submission gate (P0 blocker on mismatch) |75| Bibliographic audit against PubMed / CrossRef | **delegate** to `/verify-refs` | Audit-only — keep writer/auditor separation |7677## Workflows7879### A. Pandoc citeproc (default for solo authors and final submissions)8081User provides `manuscript.md` with `[@bibkey]` citations + `refs.bib`.821. **Gate**: `python "${CLAUDE_SKILL_DIR}/scripts/check_citation_keys.py" manuscript.md refs.bib`83 — exits non-zero on UNDEFINED keys. Fix and re-run.842. **Render**:85 ```bash86 "${CLAUDE_SKILL_DIR}/scripts/render_pandoc.sh" \87 -j european-radiology \88 -i manuscript.md \89 -b refs.bib \90 -o manuscript_final.docx91 ```92 Bundled CSLs (in `citation_styles/`): `european-radiology`, `radiology`,93 `american-journal-of-roentgenology`, `cardiovascular-and-interventional-radiology`,94 `korean-journal-of-radiology`, `vancouver`, `vancouver-superscript`,95 `springer-basic-brackets`, `springer-vancouver-brackets`. Use96 `radiology` for RYAI; use `vancouver` for JVIR (no dedicated CSL).973. **QC**:98 ```bash99 python3 "${CLAUDE_SKILL_DIR}/scripts/check_xref.py" \100 --md manuscript.md --docx manuscript_final.docx \101 --out qc/xref_audit.json --strict102 ```103 Treat `submission_safe: false` as a halt. Route fixes by symptom — see104 the table in `references/check_xref_symptoms.md`.1054. **Audit hand-off**: invoke `/verify-refs` for the PubMed/CrossRef audit106 before sign-off.107108### B. Zotero CWYW (co-author Word workflow)109110User has a markdown SSOT and wants reviewers to edit citations directly in111Word. Each reference must already exist as a Zotero item; the user supplies112a `[N] → ZoteroKey` mapping.1131. **Convert markers**:114 ```bash115 python3 "${CLAUDE_SKILL_DIR}/scripts/md_marker_convert.py" \116 --input manuscript.md --output manuscript_keys.md \117 --map ref_map.json --to-keys118 ```119 Optionally stage with `--active-ns 1,2,3,4,19` for a sample build first120 (validated on an active meta-analysis project: 5-ref sample reduces Word Refresh blast radius121 when debugging).1222. **Render to .docx** with pandoc (workflow A) so the body has plain text123 `[@key]` markers, OR pre-build a .docx some other way that still contains124 plain `[@key]` text.1253. **Inject CWYW**:126 ```bash127 python3 "${CLAUDE_SKILL_DIR}/scripts/inject_zotero_cwyw.py" \128 --input manuscript_keys.docx --output manuscript_cwyw.docx \129 --user-id 16613550 --keys-from keys.txt130 ```131 The script fetches Zotero metadata via the local connector (port 23119);132 any HTTP failure aborts with non-zero exit.1334. **First-build instruction** (REQUIRED — see Known Limitation #1): open134 the output in Word → Zotero tab → **Add/Edit Bibliography** once. After135 that, **Refresh** keeps citations and bibliography in sync as authors136 edit.1375. **Surgical patches are unsafe**: for ref additions in later rounds, edit138 the markdown SSOT and rebuild the whole .docx instead of regex-patching139 the post-CWYW file. Zotero's rendered `[N]` superscripts can collide140 with plain `[N]` markers and corrupt the field codes.141142### C. Cascade rejection re-render (find-journal hand-off)143144User got rejected from journal A and `/find-journal` recommended journal B.1451. Confirm the new CSL exists in `citation_styles/` (or fetch from146 https://citationstyles.org/styles and drop in).1472. Re-run `render_pandoc.sh -j <new-csl>` against the same `manuscript.md` +148 `refs.bib`.1493. Re-run `check_xref.py --strict`.1504. Re-run `/verify-refs` if any new references were added during the151 inter-journal revision.152153### D. Cross-reference QC only154155User shipped a manuscript and a reviewer flagged a Table/Figure mismatch.1561. Run `check_xref.py --strict` on the current `manuscript.md` + `.docx`.1572. Inspect `qc/xref_audit.json`. Body caption is the SSOT — fix `manuscript.md`158 and rebuild, never patch the .docx by hand.1593. See `references/check_xref_symptoms.md` for the160 `MISSING_BODY` / `MISSING_DOCX` / `MISMATCH` triage table.161162## Quality Gates163164This skill defines **three submission gates** and **one user approval gate**:165166- **Gate 1 (citekey integrity)**: `check_citation_keys.py` exits non-zero on167 UNDEFINED keys. The pipeline halts; the user reviews and fixes.168- **Gate 2 (cross-reference integrity)**: `check_xref.py --strict` exits 1 on169 any `MISSING_DOCX` / `MISSING_BODY` / `MISMATCH` row. The user reviews170 `qc/xref_audit.json` and resolves before proceeding.171- **Gate 3 (audit hand-off)**: before sign-off, the user must run172 `/verify-refs` and confirm `submission_safe: true` in173 `qc/reference_audit.json`. This skill never marks the bibliography174 audited on its own.175- **User approval gate (CWYW first build)**: the user must perform Word →176 Zotero → Add/Edit Bibliography manually after the first177 `inject_zotero_cwyw.py` build. The skill cannot automate this and warns178 on stderr that it is required.179180## Provenance181182`scripts/_vendor_citation_writer.py` is vendored from183`alisoroushmd/zotero-mcp` @ `ed5dfb71`, MIT licensed. See184[`NOTICE.md`](./NOTICE.md) and [`LICENSE.zotero-mcp`](./LICENSE.zotero-mcp).185186## Related187188- `~/.claude/rules/manuscript-references.md` — global rule (decision tree189 this skill implements)190- `~/.claude/rules/agent-skill-routing.md` — skill router (this skill is the191 reference-handling row)192- `~/.claude/rules/zotero-workflow.md` — BBT auto-export, MCP setup193- `/verify-refs` — read-only audit (PubMed / CrossRef + first-author194 cross-check)195- `/lit-sync` — Zotero ↔ Obsidian sync, `refs.bib` provider196- `/write-paper` Phase 7.6 — calls this skill (one-line delegation)197- `/revise`, `/sync-submission`, `/find-journal` — call this skill on198 rebuild / re-render / cascade199200## Known Limitations2012021. **First-build empty BIBL field (CWYW)**: `inject_zotero_cwyw.py` writes a203 stub `ADDIN ZOTERO_BIBL` field; Word's Zotero Refresh treats an empty204 stub as user-customized and refuses to populate it. User must run205 Add/Edit Bibliography once. Subsequent Refresh works as expected.206 Validated on Word for Mac, an active meta-analysis project.2072. **Webpage / non-journal item types**: handled by the patched208 `zotero_to_csl_json` that fetches Zotero's native CSL-JSON; do not bypass209 this patch.2103. **Surgical post-build regex patches are unsafe** — see Workflow B step 5.2114. **Local Zotero required for CWYW** — port 23119 must be reachable; no212 web-API fallback yet (would need `ZOTERO_API_KEY`). On failure the script213 aborts with non-zero exit so partial builds never ship.