Export Nighthawk markdown reports to PDF on macOS. Use this skill when the user asks to generate, export, or produce a PDF from a Nighthawk notes file.
Converts a Nighthawk markdown report (notes/Nighthawk-*.md) to a styled PDF.
Always probe before choosing an approach:
which pandoc wkhtmltopdf md-to-pdf 2>/dev/null
python3 -c "import weasyprint" 2>/dev/null && echo "weasyprint: ok" || echo "weasyprint: not installed"
pandoc "notes/Nighthawk-YYYY-MM-DD-topic.md" \
-o "notes/Nighthawk-YYYY-MM-DD-topic.pdf" \
--pdf-engine=wkhtmltopdf \
-V geometry:margin=1in -V fontsize=11pt
# fallback engines in order: xelatex, pdflatex
This is the verified working approach on macOS. It handles Mermaid diagrams by pre-rendering them to hi-res PNG via Puppeteer, then embedding them inline before weasyprint processes the document.
Do NOT use SVG — weasyprint renders SVG shapes but drops all text (missing font resolution). Always use PNG.
python3 -m venv /tmp/pdf-venv
/tmp/pdf-venv/bin/pip install --quiet markdown weasyprint
Run this for each report that contains a ```mermaid block:
# Extract the mermaid source
awk '/^```mermaid$/,/^```$/' notes/Nighthawk-YYYY-MM-DD-topic.md | sed '1d;$d' > /tmp/diagram.mmd
# Render to hi-res PNG (--width 3000 --scale 3 ensures readable text in PDF)
npx @mermaid-js/mermaid-cli -i /tmp/diagram.mmd -o /tmp/diagram.png --width 3000 --scale 3
Write the following to /tmp/build_pdf.py and run with the venv:
import pathlib, re, base64, markdown
from weasyprint import HTML
MD_IN = "/Volumes/Extreme SSD/src/project-nighthawk/notes/Nighthawk-YYYY-MM-DD-topic.md"
PNG_IN = "/tmp/diagram.png" # omit if no Mermaid diagram
PDF_OUT = "/Volumes/Extreme SSD/src/project-nighthawk/notes/Nighthawk-YYYY-MM-DD-topic.pdf"
CSS = """
body { font-family: Georgia, serif; font-size: 11pt; line-height: 1.6; padding: 40px; max-width: 900px; margin: auto; }
h1 { font-size: 20pt; border-bottom: 2px solid #333; padding-bottom: 8px; margin-top: 24px; }
h2 { font-size: 15pt; border-bottom: 1px solid #666; margin-top: 20px; }
h3 { font-size: 13pt; margin-top: 16px; }
code { font-family: 'Courier New', monospace; background: #f4f4f4; padding: 2px 4px; border-radius: 3px; font-size: 9pt; }
pre { background: #f4f4f4; padding: 12px; border-radius: 4px; border-left: 3px solid #666; page-break-inside: avoid; }
pre code { background: none; padding: 0; }
table { border-collapse: collapse; width: 100%; margin: 12px 0; page-break-inside: avoid; }
th { background: #333; color: white; padding: 8px; text-align: left; }
td { padding: 6px 8px; border: 1px solid #ccc; }