SuperAPI AI Directory

markdown-to-pdf

Office & productivity

View repository

Updated 10-16 01:35

About this skill

Markdown to PDF

Convert one or more Markdown files into styled PDFs using WeasyPrint and the Python markdown library. The default styling is neutral; apply your own brand stylesheet via --css.

How to use

Run the conversion script via uv run:

uv run "${SKILL_DIR}/scripts/convert.py" <files...> [-o output_dir] [--css custom.css]

${SKILL_DIR} is the directory containing this SKILL.md. The script resolves assets/style.css relative to its own location, so it works at any path. Its dependencies (markdown, weasyprint) are declared in the inline script metadata at the top of convert.py; uv run reads that block and installs them.

Steps

  1. Identify target .md files from the request. If none specified, look in the current directory and ask which to convert.
  2. Run the conversion:
uv run <skill-dir>/scripts/convert.py file1.md file2.md
  • Use -o <dir> to place PDFs in a specific output directory.
  • Use --css <path> to override the default stylesheet (e.g., netresearch-branding-skill/assets/markdown-pdf.css).
  • Glob patterns like *.md are supported.
  • Use --allow-scheme <scheme> (repeatable) only when the document needs images, stylesheets or fonts over a scheme other than https or data (see below).
  1. Report which PDF files were created and where.

Default styling

The bundled assets/style.css provides:

  • system fonts (no external font fetches)
  • neutral grayscale headers
  • monospace code blocks
  • A4 page size, sensible margins
  • page numbers in footer

Remote and local resources

WeasyPrint loads the images, stylesheets and fonts that the Markdown (including raw HTML in it) and the --css file reference. The script lets it load only https: and data: URLs. Any other scheme (http:, file:, ftp:) stops the conversion with refused to load <url> and exit code 1; no PDF is written. Pass --allow-scheme http or --allow-scheme file only for a document you trust. Relative paths such as ![logo](logo.png) are not resolved, because the HTML has no base URL.

Companion skills

  • netresearch-branding-skill ships a markdown-pdf.css brand asset. Netresearch users: install both skills, then pass --css "$CLAUDE_PLUGIN_ROOT/.../netresearch-branding-skill/.../assets/markdown-pdf.css".
  • That brand CSS expects two wrapper elements this script does not generate: .page-header (with an .header-logo image) and .page-footer (with .footer-info / .footer-page). Passing --css with a branded stylesheet yields a PDF with no logo and no footer — no error, just missing brand elements. For compliant output, build the HTML yourself: wrap the body in the .page-header / .page-footer divs the CSS expects, then call weasyprint directly. See netresearch-branding-skill's SKILL.md.

Known pitfalls

  • Bullet list right after a lead-in line, no blank line between them: python-markdown (unlike CommonMark) starts a list only when a blank line precedes it. Intro:\n- item renders as literal - item text, not a <ul> — silently. Always leave a blank line between a lead-in sentence and its list.
  • Such rendering bugs raise no error and don't affect the exit code. Before calling a conversion done, render the first page to a PNG (pymupdf/fitz: page.get_pixmap(dpi=150).save(...)) and inspect it — don't trust ✓ converted ... (N KB) alone.

Output format

Per file:

✓ converted README.md → README.pdf (12.3 KB)
✓ converted RFC-001.md → RFC-001.pdf (4.7 KB)

Errors

Error Action
No .md files matched List directory contents and ask user
WeasyPrint missing uv run convert.py installs it from the script's inline metadata; if it was started as python3 convert.py, rerun it with uv run
--css file not found Surface the missing path; do not fall back silently
refused to load <url> The document references a scheme other than https/data. Tell the user which URL; rerun with --allow-scheme <scheme> only if they trust the document