aperivue/render-pdf-doc
> Render academic Markdown documents (English or Korean) to publication-quality PDF via pandoc + xelatex. handouts, anchor docs (Q&A grids), and reference tables. Auto-infers pipe-table column widths from content (label column shrinks to fit, data columns share remaining width). CJK-aware font fallback for Korean text (Apple SD Gothic Neo on macOS, Noto Sans CJK KR on Linux). filling (/fill-protocol), figures (/make-figures).
npx skills add https://github.com/Aperivue/medsci-skills --skill render-pdf-doc
Markdown + frontmatter → publication-quality academic PDF (English or Korean).
In real circulation cycles for academic PDFs, two recurring failure patterns appear:
Manual fixes work but the same pattern recurs across proposals, briefings, IRB covers, exemption applications. This skill focuses on layout (CJK fonts + table column widths). Bibliography and CSL are handled by /manage-refs.
| Task | Skill |
|---|---|
| Manuscript + bibliography → DOCX/PDF | /manage-refs scripts/render_pandoc.sh (CSL + .bib) |
| Filling an institutional .docx form | /fill-protocol |
| ICMJE COI form | /fill-icmje-coi |
| Figure / PPTX | /make-figures, /present-paper |
| This skill: non-bib academic markdown → PDF (proposal, briefing, anchor doc, IRB cover) | /render-pdf-doc |
mainfont + CJKmainfont. The default fallback is OS-detected.redact_internal: true option.tbl-colwidths has reported PDF regressions (issues 6089/9200).# macOS
brew install pandoc
brew install --cask mactex-no-gui # xelatex + xeCJK (~5 GB)
# Linux
sudo apt-get install pandoc texlive-xetex texlive-lang-cjk fonts-noto-cjk
# Windows (PowerShell) — run in Git Bash afterwards
winget install --id JohnMacFarlane.Pandoc
winget install --id MiKTeX.MiKTeX # xelatex; installs missing LaTeX packages on demand
# No CJK font download needed: Malgun Gothic ships with Windows 7+ and is the default here.
Detection:
bash scripts/check_deps.sh
Windows / Git Bash note. MiKTeX's binary directory
(%LOCALAPPDATA%\Programs\MiKTeX\miktex\bin\x64) is often not on the Git Bash PATH,
so xelatex can read as [MISS] even after install. Both check_deps.sh and
render_pdf.sh now auto-probe that location; if xelatex still isn't found, add the
directory to your PATH (or run from the *MiKTeX Console → Settings*-configured shell).
The Windows CJK/main font default is Malgun Gothic (preinstalled); override per document
via frontmatter, or with --font / --cjk-font.
---
title: "Paper 2 Calibration Anchor — Q&A Grid"
author: "<Author Group>"
date: "2026-05-01"
mainfont: "Apple SD Gothic Neo" # macOS default
CJKmainfont: "Apple SD Gothic Neo"
geometry: "margin=0.85in"
fontsize: 11pt
linestretch: 1.25
colorlinks: true
---
For Linux/CI, use Noto Sans CJK KR; on Windows, use Malgun Gothic. The render script auto-detects the default per OS.
python scripts/infer_colwidths.py input.md > input.colwidths.md
The script:
max(len(header), max(len(cell))) (CJK = 2 cells, ASCII = 1).Override per-table via attribute: {tbl-colwidths="[20,40,40]"} after caption — passes through unchanged.
bash scripts/render_pdf.sh -i input.colwidths.md -o output.pdf
Or one-shot:
bash scripts/render_pdf.sh -i input.md -o output.pdf --infer-colwidths
xelatex silently drops any character the chosen font does not cover — the PDF
renders with the glyph simply missing, no error or warning. Academic markdown
routinely carries glyphs a default Latin font misses: transition arrows (→ ↑ ↓),
math operators (− ≤ ≥ ± √ ∪ × ≈ ≠), stats Greek (κ μ σ β), bullets/marks (• ★ ✓),
and CJK. Scan the source first so a silent drop is caught before it ships:
python3 scripts/scan_glyph_coverage.py input.md --strict
# real cmap check when you have the font file + fonttools:
python3 scripts/scan_glyph_coverage.py input.md --font "/path/to/body.otf" --strict
It groups the risky glyphs by class (advisory), or — with --font + fonttools
— reports which are genuinely absent from the font's cmap. If risky glyphs are
present, ensure mainfont/CJKmainfont cover them (a CJK-capable font such as
*Apple SD Gothic Neo* / *Noto Sans CJK* usually covers arrows + Hangul but can
still miss the true-minus − U+2212 and ★). **The DOCX is authoritative; the
PDF is a convenience copy** — never let a PDF render drop a glyph the document
needs.
Open the PDF. Check:
Starter markdown in templates/ (English default; a Korean variant *_ko.md ships alongside each):
anchor-doc.md — Q&A gridproposal-cover.md — research-proposal cover pagebriefing-handout.md — meeting brief (1-page)reference-table.md — comparison-table formatEach template marks slots with a <!-- TODO: --> marker.
| Anti-pattern | Consequence |
|---|---|
| Equal dash split (\|---\|---\|---\|) | A column with only a short label gets the same width → cramped data columns |
| CJKmainfont not set | Hangul falls back to Times New Roman (broken Latin glyphs or blanks) |
| Change history / version (e.g. v3.2.2) / PI attribution exposed in a circulation PDF | Confuses the first recipient; leaks internal information |
| Quarto tbl-colwidths for PDF | PDF regression in Quarto 1.4+ — trust HTML only |
scripts/render_pdf.sh — pandoc + xelatex wrapper, OS font detectionscripts/infer_colwidths.py — auto-generates pipe-table separator dash ratiosscripts/check_deps.sh — checks for pandoc / xelatex / CJK fonttemplates/ — 4 starters (English) + their *_ko.md Korean variantsreferences/pandoc_korean_cheatsheet.md — collection of frontmatter patterns (Korean-PDF reference)references/known_pitfalls.md — em-dash line breaks, smart quotes, etc. (Korean-PDF reference)retype a number from prose, and do not carry one forward from an earlier draft — a table that
was correct in v3 is not evidence it is correct in v4.
/manage-refs separately — this skill does not handle bib..docx or .eml aco-author sent) unmodified as its own artifact. The PDF is a derivative, not a replacement, and
the next round is diffed against that source. If the source was itself AI-drafted by a
collaborator, treat every number, denominator, and author-year in it as unverified: re-derive
each from the underlying paper or analysis output before it reaches the PDF.
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.
Take aperivue/render-pdf-doc 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.
The instructions reference brew, apt.
Without those the skill loads but fails at the first command.