Skip to content

Build pipeline

When you run make publish, a lot happens inside the container. This is the path from your source to a finished artifact. It applies to both templates — in core you can read every piece of it under .pandoc/.

From make to artifact

  1. make publish runs the engine's publish.sh inside the Keystone image, with your manuscript/, assets/, fonts/, and config mounted in.
  2. publish.sh reads publish.txt, concatenates the listed manuscript files in order, merges the system and user shortcuts, resolves metadata, and invokes Pandoc with the right options for the requested format.
  3. Pandoc parses the Markdown into its document model and runs Keystone's Lua filters over it (below).
  4. Pandoc's writer for the format emits the result — XeLaTeX to PDF, the EPUB archive, or a DOCX/ODT built from a styled reference document.
  5. The artifact lands in artifacts/, named <project>-<target>[-<edition>]-<date>.

The Lua filters

The heart of the engine is four Lua filters, run in this order. Order matters — each depends on the previous one having finished:

  1. shortcuts.lua — expands shortcut names into handler classes and attributes, so everything downstream sees plain handler elements. System shortcuts ship in the image; your shortcuts.yaml layers on top. See The shortcut system.
  2. keystone.lua — validates and enriches metadata (required fields per target, date, cover image, draft watermark, code theme) and injects the font and style definitions for the format.
  3. divs.lua — the dispatcher. It routes every fenced div and span to its handler and emits format-specific output. See Handlers.
  4. page-furniture.lua — composes the PDF running headers, footers, and page numbers from your metadata, resolving placeholders like {chapter}. It runs last so any handlers inside header text have already rendered.

The EPUB pre-scan

EPUB embeds only the fonts your book actually uses, and Pandoc needs that list before the main run. For EPUB builds, publish.sh does a quick pre-scan pass first — expanding shortcuts and walking the document to find referenced font families — then embeds exactly those fonts in the real build. Other formats skip this step.

Where it lives

In core, all of this is in your project under .pandoc/: publish.sh and import.sh, the filters/ directory (the Lua filters and the per-handler directories under filters/divs/), and metadata/ (the target bundles). In core-slim the same files live inside the prebuilt image. To change any of it, use core and see Customizing.