md2office turns a plain Markdown report into a Word document and PDF that look like they came from a publisher — title & classification in the headers, wide autofit tables, shaded monospace code, and a static table of contents.
The migration risk register from the bundled sample — the Aurora Order Service Migration Report (examples/sample.md). A pipe table in Markdown on the left; on the right, the same table typeset by md2office — autofit width, explicit borders, ready for print.
# 7. Risks and Mitigations The risk register below was maintained throughout the migration and reviewed at each phase gate. The "status" column reflects the position at the time of this report. | # | Risk | Likelihood | Impact | Mitigation | Status | | -- | ---------------------------------------------------------- | ---------- | ------ | ---------------------------------------------------------------------- | -------- | | R1 | Order duplication introduces duplicate records | Medium | High | Reconciliation job with full daily comparison; duplicate key in store | Closed | | R2 | Cutover exceeds the zero-downtime window | Medium | High | Parallel-run parity gate; rehearsed cutover checklist | Closed | | R3 | Pricing rules diverge between platforms | Medium | High | Shared rule package; per-order diff in reconciliation report | Closed | | R4 | Secrets exposed in Git or logs | Low | High | Gatekeeper policy; scan in pipeline; vault-only secret resolution | Closed | | R5 | Legacy hosts still receive traffic after decommission | Medium | Medium | Ingress ACL on legacy fleet; traffic audit for two weeks | Closed | | R6 | Image registry downtime blocks releases | Low | Medium | Registry replicated across regions; cached base images | Accepted | | R7 | Team skill gap on Kubernetes operations | Medium | Low | Pairing sessions; runbooks in the repository; staged permissions | Active | Table 5 — Migration risk register.
The risk register below was maintained throughout the migration and reviewed at each phase gate. The "status" column reflects the position at the time of this report.
| # | Risk | Likelihood | Impact | Mitigation | Status |
|---|---|---|---|---|---|
| R1 | Order duplication introduces duplicate records | Medium | High | Reconciliation job with full daily comparison; duplicate key in store | Closed |
| R2 | Cutover exceeds the zero-downtime window | Medium | High | Parallel-run parity gate; rehearsed cutover checklist | Closed |
| R3 | Pricing rules diverge between platforms | Medium | High | Shared rule package; per-order diff in reconciliation report | Closed |
| R4 | Secrets exposed in Git or logs | Low | High | Gatekeeper policy; scan in pipeline; vault-only secret resolution | Closed |
| R5 | Legacy hosts still receive traffic after decommission | Medium | Medium | Ingress ACL on legacy fleet; traffic audit for two weeks | Closed |
| R6 | Image registry downtime blocks releases | Low | Medium | Registry replicated across regions; cached base images | Accepted |
| R7 | Team skill gap on Kubernetes operations | Medium | Low | Pairing sessions; runbooks in the repository; staged permissions | Active |
Table 5 — Migration risk register.
Everything a document build needs, in one import — no scripts to copy between repos.
Pass a Word reference template (.docx/.dotx) via --template for a custom cover and header classification. No template? Pandoc's built-in default gives a clean standard look.
Title and bilingual classification go into every page header and the core document metadata automatically.
Pandoc tables are rewritten to 100% autofit width with explicit borders, so LibreOffice stops crushing them.
SourceCode and VerbatimChar get Consolas 9pt and light-grey shading.
Headless LibreOffice with a fresh per-run profile, so concurrent conversions don't lock each other out.
md2office doctor checks pandoc, LibreOffice, python-docx, and the fonts the PDF needs.
One pipeline: pandoc builds the DOCX against your reference template, the package post-processes it, LibreOffice renders the PDF.
Frontmatter title, tables, fenced code, mermaid blocks.
Renders against your reference template with the Lua filters.
Headers, classification, table width, code style, TOC.
Headless DOCX → PDF export, ready to share or print.
Install, run doctor, convert. That's it.
# 1. install pip install md2office # 2. check prerequisites md2office doctor # 3. convert (supply your own reference template) md2office docx --template template.dotx report.md report.docx --classification "Protected A" md2office pdf --template template.dotx report.md report.pdf
No template handy? Omit --template and pandoc's built-in reference document is used instead — still clean, just without a custom cover or header classification. The title still defaults to your YAML frontmatter.
One Markdown file becomes one document. Keep everything a document needs in a single folder, and point md2office at the master file.
docs/ report.md # master document chapter-2.md # optional: long sections as separate files images/ diagram.png template.dotx # your Word reference template (user-supplied) output/ # generated files (gitignore this) report.docx report.pdf
--- title: Developer Guide author: Platform Team version: 1.2.0 --- # Overview Reference images relative to this file: 
Images and attachments resolve relative to the Markdown file's folder, which is automatically on pandoc's resource path. Add more with -r <dir>.
The title:, classification:, author, and version in YAML frontmatter are written into the page headers and cover metadata.
Fenced code blocks get monospace 9pt and shading automatically. Mermaid blocks (```mermaid) render when mmdc is installed.
A static table of contents is inserted at the top. Drop a \newpage, or pass --page-breaks sections to start each Heading1 on a new page.
cd docs md2office pdf --template ../template.dotx report.md ../output/report.pdf
Multi-chapter books: md2office doesn't assemble multiple files. Keep one master file per document, or combine chapters first (e.g. cat chapters/*.md > book.md) and convert once.
Everything is exposed on the CLI and through ConvertOptions.
| Option | Default | Meaning |
|---|---|---|
title | frontmatter | Document title; written into headers + core metadata |
template | None | Word reference template; falls back to pandoc's built-in default |
classification | Unclassified | Non classifié | Sensitivity label in every page header |
number_sections | False | Pass --number-sections to pandoc |
code_style | True | Consolas 9pt + shading on code styles |
page_breaks | "none" | "sections" puts each Heading1 on a new page |
font | "default" | "arial" switches the document font |
mermaid | "auto" | Render ``` ```mermaid``` blocks (needs mmdc) |
keep_docx | False | Keep the intermediate DOCX when producing a PDF |
Use it directly from Python — no shell needed.
import md2office md2office.to_docx("report.md", "report.docx", template="template.dotx", title="My Report", classification="Protected A") md2office.to_pdf("report.md", "report.pdf", template="template.dotx") # fine-grained control from md2office import ConvertOptions, to_pdf opts = ConvertOptions(template="template.dotx", number_sections=True, font="arial", page_breaks="sections") to_pdf("report.md", "report.pdf", options=opts)