agentleFS
THEROCKSSSTHEROCKSSS/hermes-skills-portfolio/skills/markdown-to-pdf/SKILL.md

markdown-to-pdf

Skill1 starsChanged 3 months agoMITView on GitHub

Use when the user wants to convert a Markdown file into a styled PDF — via weasyprint, pandoc, or puppeteer — including choosing a theme (default, dark, print-friendly), embedding syntax-highlighted code, or producing a shareable report/handout from notes.

  • Installs packages

11 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

2 rules. 0 are common, 1 is distinctive, and 1 is very specific to this project.

  • 0

    Common

    Most of the 8 edited versions we read keep these.

  • 1

    Distinctive

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Read the markdown file

    line 151
  2. Very specific:

    Page breaks land mid-section: Add page-break-before: always on h1 only (not every heading level) or every chapter starts a new page …

    line 162

“Common” is measured: kept by at least 6 in 10 of the 8 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

markdown-to-pdf

Overview

Convert markdown files to PDF with customizable styling. The agent handles markdown parsing, CSS styling, and PDF generation with options for themes, page size, and syntax highlighting.

When to Use

  • The user wants to convert a markdown document to PDF.
  • The user wants a styled PDF report from markdown.
  • The user says "convert this to PDF", "make a PDF from markdown", or "export as PDF".

Prerequisites

# Option 1: weasyprint (recommended, pure Python)
pip install weasyprint markdown

# Option 2: puppeteer (Node.js, better rendering)
npm install puppeteer markdown-it

# Option 3: pandoc (system package)
# Linux: apt install pandoc
# macOS: brew install pandoc

Using weasyprint (Python)

import markdown
from weasyprint import HTML

def md_to_pdf(md_path: str, pdf_path: str, css: str = ""):
    """Convert markdown to PDF with optional CSS styling."""
    with open(md_path, 'r') as f:
        md_content = f.read()

    html_body = markdown.markdown(md_content, extensions=['codehilite', 'tables', 'fenced_code'])

    default_css = """
    body { font-family: 'Inter', sans-serif; max-width: 800px; margin: 40px auto; line-height: 1.6; color: #333; }
    h1 { font-size: 2em; border-bottom: 2px solid #eee; padding-bottom: 0.3em; }
    h2 { font-size: 1.5em; border-bottom: 1px solid #eee; padding-bottom: 0.3em; }
    code { background: #f4f4f4; padding: 2px 6px; border-radius: 3px; font-family: 'Fira Code', monospace; font-size: 0.9em; }
    pre { background: #f8f8f8; padding: 16px; border-radius: 5px; overflow-x: auto; }
    pre code { background: none; padding: 0; }
    table { border-collapse: collapse; width: 100%; }
    th, td { border: 1px solid #ddd; padding: 8px 12px; text-align: left; }
    th { background: #f4f4f4; font-weight: bold; }
    blockquote { border-left: 4px solid #ddd; margin-left: 0; padding-left: 16px; color: #666; }
    """

    html = f"""
    <html><head><style>{css or default_css}</style></head>
    <body>{html_body}</body></html>
    """

    HTML(string=html).write_pdf(pdf_path)
    return pdf_path

Using pandoc (simplest)

# Basic conversion
pandoc input.md -o output.pdf

# With a template and table of contents
pandoc input.md -o output.pdf --toc --template=eisvogel

# With syntax highlighting
pandoc input.md -o output.pdf --highlight-style=tango

Using puppeteer (best rendering)

const markdownIt = require('markdown-it');
const puppeteer = require('puppeteer');
const fs = require('fs');

async function mdToPdf(mdPath, pdfPath) {
    const md = fs.readFileSync(mdPath, 'utf-8');
    const htmlBody = markdownIt({ html: true, highlight: true }).render(md);

    const html = `
    <html><head>
    <style>
        body { font-family: system-ui; max-width: 800px; margin: 40px auto; padding: 20px; }
        code { background: #f4f4f4; padding: 2px 6px; border-radius: 3px; }
        pre { background: #f8f8f8; padding: 16px; border-radius: 5px; overflow-x: auto; }
        table { border-collapse: collapse; width: 100%; }
        th, td { border: 1px solid #ddd; padding: 8px; }
    </style>
    </head><body>${htmlBody}</body></html>
    `;

    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.setContent(html, { waitUntil: 'networkidle0' });
    await page.pdf({ path: pdfPath, format: 'A4', margin: { top: '1in', bottom: '1in' } });
    await browser.close();
    return pdfPath;
}

Custom Themes

Dark theme

DARK_CSS = """
body { background: #1a1a2e; color: #e0e0e0; font-family: 'Inter', sans-serif; max-width: 800px; margin: 40px auto; }
h1, h2, h3 { color: #fff; border-bottom-color: #333; }
code { background: #16213e; color: #e94560; }
pre { background: #16213e; border: 1px solid #333; }
a { color: #e94560; }
table th { background: #16213e; }
table th, table td { border-color: #333; }
"""

Print-friendly

PRINT_CSS = """
body { font-family: 'Georgia', serif; max-width: none; margin: 0; font-size: 12pt; line-height: 1.5; }
h1 { font-size: 20pt; page-break-before: always; }
h1:first-of-type { page-break-before: avoid; }
h2 { font-size: 16pt; }
pre, code { font-family: 'Courier New', monospace; font-size: 10pt; }
table { font-size: 10pt; }
@page { margin: 1in; }
"""

Workflow

  1. Read the markdown file
  2. Choose the conversion method (weasyprint for Python, puppeteer for best rendering, pandoc for simplicity)
  3. Apply CSS styling (default, dark, or print-friendly)
  4. Generate the PDF
  5. Return the file path

Common Pitfalls

  1. Missing system dependencies. weasyprint needs cairo, pango, and gdk-pixbuf system libraries — it fails at import time, not at write_pdf, if these are absent. Ubuntu: apt install libpango-1.0-0 libpangoft2-1.0-0. macOS: brew install pango.
  2. Code blocks render as plain text. Without the codehilite extension (Python) or a highlight.js include (JS), fenced code loses highlighting. Install pygments for Python highlighting.
  3. Images don't appear in the PDF. Local image paths must be absolute or relative to the HTML file being rendered, not relative to the original markdown file's directory. Use file:// URLs or embed images as base64.
  4. Page breaks land mid-section. Add page-break-before: always on h1 only (not every heading level) or every chapter starts a new page needlessly; add page-break-inside: avoid on tables and code blocks so they don't split across pages.
  5. Emoji show as boxes or blanks. weasyprint doesn't ship a color emoji font. Install Noto Color Emoji or replace emoji with text before conversion.
  6. PDF is unexpectedly huge. Embedded images at original resolution bloat file size. Resize to max 1000px width and use JPEG for photos before embedding.

Verification Checklist

  • Output PDF file exists at the expected path and is non-zero bytes
  • Page count is plausible for the source document's length (check with pdfinfo output.pdf or open it)
  • Fenced code blocks show syntax highlighting, not plain monospace text
  • Every image referenced in the markdown actually renders in the PDF (no broken-image icons)
  • The chosen theme (default/dark/print) is visibly applied — colors and fonts match what was requested

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.