Pandoc → DOCX → PDF Pipeline
Wenn ein Markdown-Dokument als ansehnliches PDF gerendert werden muss (Kunden-Angebote, Anlagen, Vertragsdokumente). Funktioniert lokal, ohne Cloud-Tool, ohne Browser-Print.
Use-Case
- Ein Markdown-Dokument liegt vor (oder wird gerade geschrieben)
- Es soll als professionelles PDF an einen Kunden gehen
- Hauptdokument hat optisch konsistenten Look (gleiche Schrift, blaue Headlines, saubere Tabellen)
- Browser-Print-to-PDF ist nicht reproduzierbar (Tabs gehen verloren, kein versionierbarer Build)
Originaler Trigger: Becker-Angebot V3 Anlagen 06.05.2026 — die alte angebot-v3-anlagen.pdf wurde aus einer temporär bearbeiteten Browser-HTML gerendert die nicht im Repo lag, danach war keine reproduzierbare Source mehr da.
Pipeline
angebot.md
↓ pandoc + theme-font-patch
angebot.docx
↓ LibreOffice headless
angebot.pdf
Drei Schritte, ca. 30 Sekunden Render-Zeit.
Schritt 1 — pandoc Markdown → DOCX
pandoc angebot.md -o angebot.docx --from markdown+raw_texWichtig:
- Kein
--reference-docwenn das Reference-Dokument keine Table-Styles definiert. Pandoc rendert dann Markdown-Tabellen zu flachen Listen (Spalten untereinander statt nebeneinander). Default-Stiles sind robuster, weil pandoc seine eigenen Table-Styles mitbringt. --from markdown+raw_texdamit\newpageals Page-Break interpretiert wird (statt als Literal-Text).- YAML-Frontmatter wird ignoriert wenn er korrekt mit
---umschlossen ist. Kein extra Cleanup nötig.
Schritt 2 — Theme-Font auf Calibri patchen
Pandoc-Default verwendet Theme-Schrift “Aptos Display” + “Aptos” (Microsoft-365-Default). LibreOffice fällt auf Times-Roman zurück wenn diese Fonts nicht installiert sind. Auf Mac und Linux nicht installiert. Lösung: Theme-Schrift im docx auf Calibri setzen.
# Unpack
python3 ~/.claude/plugins/marketplaces/anthropic-agent-skills/skills/docx/scripts/office/unpack.py \
angebot.docx /tmp/unpacked/
# In /tmp/unpacked/word/theme/theme1.xml
# - <a:majorFont>...<a:latin typeface="Aptos Display" .../> → typeface="Calibri" panose="020F0302020204030204"
# - <a:minorFont>...<a:latin typeface="Aptos" .../> → typeface="Calibri" panose="020F0302020204030204"
# Pack
python3 ~/.claude/plugins/marketplaces/anthropic-agent-skills/skills/docx/scripts/office/pack.py \
/tmp/unpacked/ angebot.docx --original angebot.docxCalibri ist auf macOS, Windows, Linux universell verfügbar (oder hat einen ordentlichen Fallback wie Liberation Sans). Konsistente Sans-Serif-Optik.
Wenn das Hauptdokument einen anderen Font verwendet (z.B. Helvetica, Inter), den entsprechenden Font hier eintragen.
Schritt 3 — LibreOffice DOCX → PDF
/Applications/LibreOffice.app/Contents/MacOS/soffice \
--headless --convert-to pdf \
--outdir <output-dir> \
angebot.docxRender-Zeit ca. 5 Sekunden für ein 13-Seiten-Dokument.
Sanity-Check vor Versand
Immer mit Read auf das gerenderte PDF mit pages: 1-3:
- Tabellen rendern als Tabellen, nicht als flache Liste
- Schrift ist Calibri oder gleichwertig (nicht Times Roman)
- Headlines sind blau und linksbündig (Pandoc-Default mit Calibri sieht ordentlich aus)
- Keine Korrekturen verloren gegangen
- Page-Breaks an den richtigen Stellen (nach
\newpagein MD)
Wenn Layout schief: zurück zu Schritt 1, prüfen ob --reference-doc das Problem war.
Layout-Optionen
Pandoc-Default sieht für Anlagen-Dokumente und Vertragsdokumente sauber aus: blaue Headlines, schwarze Body-Schrift, Sans-Serif, einfache Tabellen mit grauen Trennlinien.
Wenn mehr Marketing-Look gewünscht (KPI-Boxen, Hero-Header, Logo-Wortmarke, mehrspaltiges Layout): pandoc reicht nicht. Dann HTML+CSS+Print-CSS via Headless-Chrome oder direkt InDesign / Affinity Publisher. Aufwand deutlich höher.
Default-Pandoc-Pipeline ist der Sweet-Spot für substanzielle Anlagen-Dokumente wo Inhalt > Optik. Marketing-Hauptdokumente bleiben in ihrem nativen Tool (z.B. Word direkt, oder dem HTML-Renderer der die Original-PDF erzeugt hat).
Wann diese Pipeline NICHT nehmen
- Wenn das Dokument PNG-Logos, SVG-Diagramme oder komplexe Multi-Column-Layouts enthält (KPI-Boxen, Side-Floats, Brand-Header) — das geht in pandoc nicht zuverlässig
- Wenn das Hauptdokument in einem anderen Tool gepflegt wird (das bestehende Tool nutzen, nicht parallele Source aufbauen)
- Wenn die Quelle nicht in Markdown gepflegt werden soll (z.B. weil der Kunde im DOCX-Format gegenliest)
Lessons aus Becker-V3-Run 2026-05-06
- Reference-Doc-Falle: mein erster Anlauf war
pandoc anlagen.md -o anlagen.docx --reference-doc=hauptdokument.docx, weil ich Stil-Konsistenz wollte. Resultat: alle Tabellen flach, Hero-Headers zentriert. Pandoc übernimmt aus Reference-Doc nur die Stiles die dort definiert sind, und das Hauptdokument war von Hand erstellt ohne Table-Styles. Default ist sicherer. - Theme-Font ist mehrere Layer tief: im pandoc-default-docx steht in
styles.xmlnurw:asciiTheme="minorHAnsi", was auftheme1.xmlverweist, was wiederum die Schrift definiert. Wenn man die Schrift nur instyles.xmländern will, muss man die Theme-Referenzen alle ersetzen — viele Edits. Theme-Patch intheme1.xmlist ein einziger Edit pro Font (major + minor) und propagiert automatisch. - Calibri ist der pragmatische Default-Font. Inter wäre Brand-konformer (siehe
assets/firma/email-signatures/), ist aber auf den meisten Systemen nicht installiert und Fallback-Verhalten ist unvorhersehbar. Calibri als Standard-Office-Font ist universell verfügbar oder hat sauberen Fallback.
Related
- SKILL §6b — wann diese Pipeline im Email-Review-Kontext greift
- anthropic-skills —
docx-Skill liefert dieunpack.py/pack.pyHelper - _index — Becker-V3-Run vom 2026-05-06/07 (Pipeline erstmals produktiv genutzt)