Skip to content

OpenDigitalCC/pandoc-wrapper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pandoc-wrapper

Turn Markdown into polished, branded PDFs. You write Markdown with a small YAML header; the pipeline merges in a brand (colours, fonts, logo, cover), renders it through Pandoc and XeLaTeX with a Lua filter and an Eisvogel-based LaTeX template, and produces a professional document - title page, table of contents, styled tables, charts, callout boxes, endnote references and all.

No LaTeX knowledge required to author. One command to build:

md-to-pdf report.md

Why it exists

The pipeline grew out of a single shell script, compile.sh (2018), written to assemble and version a multi-part report - "An Open Digital Approach for the NHS" - from Markdown fragments for OpenUK. That script proved the idea: authors write Markdown, the machine handles layout, versioning and branding.

It then generalised. md-to-pdf.sh added a brand system so the same content could be produced under different visual identities, a Lua filter for richer constructs (styled datatables, charts, callout boxes), and a professional LaTeX template. In mid-2026 it was hardened into a real tool: robust YAML parsing, a three-layer template architecture over a vendored upstream Eisvogel, brands as self-contained external folders, an installer and a Debian package, and Claude "skills" so an assistant can draft documents that build first time.

The goal is a pipeline that has matured past a personal wrapper - usable and shareable by others, with brands managed independently.

Use cases

  • Reports, briefings, and policy documents that need to look professional.
  • The same content rendered under several organisations' brands.
  • Print-ready output (crop marks, binding-aware layout) as well as digital.
  • AI-assisted drafting: an assistant with the skill writes house-format, ready-to-build Markdown.

How it works

Three layers keep content, features, and identity independent:

  • Base template (look): page geometry, title page, headers/footers, TOC. eisvogel-wrapper.latex (pristine Eisvogel 3.4.0 + two small inserts) is the default; mvp.latex is a minimal standalone alternative; letter.latex is a window-envelope letter format (address block, date/refs, optional letterhead); beamer.latex produces classic beamer slides, and slides.latex a modern full-bleed slide deck - both wired to the brand palette. Selectable per brand or per document with template:.
  • Pipeline preamble (pipeline-preamble.tex): the portable shim that loads every LaTeX package the filter's output needs (tables, boxes, charts). Any template that pulls it in supports the full feature set - see pandoc/documentation/TEMPLATE-CONTRACT.md.
  • Brand (identity): colours, fonts, heading colours, title-page logo/cover. Each brand is a folder <name>/template.yaml plus its assets.

A build flows: gather Markdown → parse front matter → merge the brand → run the Lua filter (boxes, datatables, charts → LaTeX) → render to PDF with XeLaTeX.

Install

From the Debian package (pulls Pandoc and the required TeX Live sets):

sudo apt install ./pandoc-wrapper_1.0.0_all.deb

Or from a checkout, per-user or system-wide:

./scripts/install.sh            # ~/.local
./scripts/install.sh --system   # /usr/local

Versioning and releasing

The VERSION file is the single source of truth; scripts/bump-version.sh stamps it into the driver (SCRIPT_VERSION) and the man page.

./scripts/build-deb.sh            # bumps the PATCH version, then builds the deb
./scripts/build-deb.sh --no-bump  # build the current VERSION (test builds)
./scripts/build-deb.sh 2.0.0      # set an exact version, then build
scripts/bump-version.sh minor     # or major / patch / X.Y.Z, without building

So each released deb bumps the patch automatically; minor and major are deliberate (bump-version.sh, or pass X.Y.Z). The SBOM reads VERSION, so it stays in step. Commit the version bump (VERSION + the stamped files) with the release.

Writing documents

Every document starts with YAML front matter:

---
title: "Document Title"
subtitle: "Document Subtitle"
brand: plain
---

Then write Markdown. The house conventions - definition lists over bold labels, the ::: callout boxes, datatable and chart blocks, footnote citations, British English - are documented with rendered examples in pandoc/documentation/Markdown-authoring-guide.md.

Output formats

The same pipeline produces four kinds of document. A document chooses its format with the template: field in its front matter (a brand sets the default):

Format template: What it is
Report (default) eisvogel-wrapper (or mvp) Title page, TOC, styled body - briefings, policy docs, reports.
Featured featured A designed graphical cover (brand-colour band, logo, "Document overview" panel, classification chip, circular cover image, decorative accents) then a section-based body - proposals and client-facing reports.
Letter letter No title page; recipient address positioned for a DL window envelope, date and our-ref/your-ref, optional letterhead (full-page artwork or a built logo + contact footer).
Slides (beamer) beamer A beamer slide deck; standard beamer theme/colortheme with the brand palette wired in.
Slides (modern) slides A flat, full-bleed slide deck (pure xelatex): solid brand-colour grounds, bold type, per-slide colour roles, auto-boxed images.

All four share the brand system (colours, fonts, identity). Each format's fields and examples are in pandoc/documentation/Markdown-authoring-guide.md (see the Letters and Slides sections); man md-to-pdf lists them too.

Drafting with Claude (skills)

pandoc/skills/ packages the house format as a skill for Claude Code and for claude.ai. With it installed, Claude writes Markdown that already follows the conventions and builds without fixing up - useful for anyone producing documents for this pipeline. Install/upload instructions are in pandoc/skills/README.md.

Brands

plain is the bundled default and the brand to copy when making a new one. Your organisation brands live outside this repo, in a base folder you manage (its own repo or a synced folder), pointed to by a config file:

# ~/.config/pandoc-wrapper/config
brands_dir = /path/to/your/brands

Resolution is: MD_TO_PDF_BRANDSbrands_dir in the config → the bundled default. Run md-to-pdf --help or man md-to-pdf for the full mechanism. To start a new brand:

cp -r /usr/share/pandoc-wrapper/brands/plain  ~/your-brands/acme
# edit acme/template.yaml; drop acme/logo.png and acme/cover.pdf in

See pandoc/brands/plain/README.md for the brand folder layout.

Repository layout

md-to-pdf.sh                     the driver (Bash)
man/md-to-pdf.1                  man page
sbom.json                        CycloneDX SBOM (generated by tools/make-sbom.pl)
scripts/                         extract-frontmatter.pl, install.sh, build-deb.sh
tools/                           make-sbom.pl + sbom-config.json
pandoc/
├── templates/                   eisvogel-wrapper, mvp, pipeline-preamble,
│   │                            document-filters.lua, conformance-test.md
│   └── vendor/                  pristine upstream Eisvogel (provenance)
├── brands/plain/                the bundled default brand (copy-me reference)
├── skills/                      the pandoc-markdown skill (claude.ai + Claude Code)
└── documentation/
    ├── Markdown-authoring-guide.md   how to write documents
    ├── TEMPLATE-CONTRACT.md          how to write a compatible template
    └── document-filters-README.md    the Lua filter internals

Supply chain (SBOM)

sbom.json is a CycloneDX 1.6 Software Bill of Materials listing the project's own files (with SHA-256 hashes and licences), the vendored/derived Eisvogel template, and the runtime dependencies (pandoc, the TeX Live sets, YAML::XS). Regenerate it after changing what ships:

perl tools/make-sbom.pl          # edit tools/sbom-config.json to add components

The .deb ships a freshly generated copy at /usr/share/doc/pandoc-wrapper/sbom.json.

Status and roadmap

The pipeline is stable and packaged. Outstanding/forward-looking work (document versioning, a slides template, automated tests, driver hardening) is tracked in RECOMMENDATIONS.md.

Licence

The tool and the bundled plain brand are BSD-3-Clause - see LICENSE. The bundled templates derive from BSD-3-Clause upstreams whose copyright notices are retained: eisvogel-wrapper.latex from Eisvogel (© Pascal Wagler, John MacFarlane; pristine copy under pandoc/templates/vendor/), and mvp.latex from the pandoc default template (© John MacFarlane; dual GPL-2+/BSD-3-Clause, used under BSD-3). Pandoc and TeX Live are runtime dependencies, not bundled.

Organisation brands are not covered by this licence: they contain logos and brand identities owned by the respective organisations and are managed in a separate, private repository (all rights reserved).

About

"Markdown-to-branded-PDF publishing pipeline — Pandoc + XeLaTeX with an external brand system and multiple formats (report, featured cover, letter, beamer & modern slides), plus boxes, datatables and charts via a Lua filter.

Topics

Resources

License

Stars

Watchers

Forks

Contributors