# Markdown To PDF

> markdown-to-pdf

- Skill: `neoeinstein/markdown-to-pdf` (Agent Skill)
- Install (CLI): `npx skillmds@latest add neoeinstein/markdown-to-pdf`
- Raw SKILL.md: https://api.skillmd.com/api/skills/neoeinstein/markdown-to-pdf/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: neoeinstein (https://skillmd.com/u/neoeinstein)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/neoeinstein/markdown-to-pdf

---


# markdown-to-pdf

Converts a Markdown file to a styled **PDF or HTML** via Typst — no pandoc or LaTeX.
Requires `zsh` and the `typst` CLI (`brew install typst`); Typst auto-downloads the packages
it needs on first run, then works offline.

## Usage

```zsh
${CLAUDE_PLUGIN_ROOT}/scripts/markdown-to-pdf <input.md> [output]      # → input.pdf
${CLAUDE_PLUGIN_ROOT}/scripts/markdown-to-pdf --format html <input.md> # → input.html
```

Other flags: `--brand <path>`, `--classification <level>`, `--init-brand [--global]`,
`--check`. Run with `--help` for the full list.

**Invoke unsandboxed** — `typst compile` writes temp/output files and fetches packages on
first run, which the default Bash sandbox blocks.

## Frontmatter

Optional YAML sets per-document metadata (title block + `classification` lookup):

```yaml
---
title: Quarterly Review
subtitle: Reliability and cost
author: [Marcus Griep, Platform Team]
date: 2026-07-14
classification: Confidential
---
```

Booleans `justify` and `hyphenate` also work here. `brand:` selects a brand kit for the
document — a bare name (resolved to
`~/.config/markdown-to-pdf/brands/<name>/brand.typ`) or a path (relative to the doc, or
absolute). The `--brand` flag overrides it.

## Branding

A `brand.typ` exporting `#let brand = (...)` — a partial dict deep-merged over the default
theme — overrides `palette`, `fonts`, `page` (incl. `numbering`), `paragraph`
(`justify`/`hyphenate`), `logo`, `classifications`, and `footer-note`. Resolution, unless `--brand` is given: project `.markdown-to-pdf/brand.typ`
→ `~/.config/markdown-to-pdf/brand.typ`.

`--init-brand [--global]` scaffolds a commented starter — **that file documents every key.**
Authoring it is plain Typst; load the **`typst` skill** (same plugin) for the language.

## Diagrams

Fenced ` ```mermaid `, ` ```dot `, and ` ```graphviz ` blocks render as diagrams (WASM, no
external tools), fetched only when used. Other languages stay syntax-highlighted code.

## Callouts

GitHub-style alerts render as colored callouts: `> [!NOTE]`, `> [!TIP]`, `> [!IMPORTANT]`,
`> [!WARNING]`, `> [!CAUTION]`. Their colors and titles are theme-configurable (`callouts`).

## Math

Inline `$…$` auto-renders (via mitex) when the body carries a LaTeX token (`\ ^ _ { }`), is an
equation (`$p = 0.5$`), or is a short variable (`$x$`, `$p_{99}$`). Currency (`$3.2K`), env vars
(`$PATH`, `$PATH=$HOME`), long tokens (`$HOME$`), and `$` inside code stay literal. Use a
` ```math ` fenced block for display; escape `\$` to force a literal that would otherwise render.

## Gotchas

- **Errors** → run `--check` (typst version, package reachability, brand resolution); report
  what's missing rather than installing it yourself.
- **Image paths** resolve against the document's directory; a brand's `logo` path against
  `brand.typ`.
- **HTML** export is experimental (prints a disclaimer); page headers/footers are omitted.
- **Math** — inline `$…$` converts with a LaTeX token, an `=` equation, or a short variable (see
  Math); currency, `$PATH`, `$FOO=$BAR`, and code `$` stay literal. Use ` ```math ` for display;
  escape `\$` to force a literal.
- **Tildes** — a lone `~` (e.g. `~16%`, `~$1K`) is kept literal; `~~text~~` is strikethrough.

