Make pdf
Skill PSPDFKit-labs/nutrient-skills/plugins/make-pdf/skills/make-pdf
Generate finished PDFs from Markdown or HTML via the Nutrient DWS Build API - single files or whole directories - with compliance-grade output options (accessible PDF/UA, archival PDF/A, text watermarks) and built-in conformance verification. Use when the user asks to make, generate, export, or batch-convert PDFs from Markdown, HTML, notes, or reports, especially when PDFs must be accessible (PDF/UA, WCAG/ADA/EAA), archival (PDF/A), or watermarked - or to check whether an existing PDF carries valid PDF/UA or PDF/A markers. For processing an existing PDF (sign, redact, OCR, merge), use document-processor-api instead.From its SKILL.md
npx -y skills add PSPDFKit-labs/nutrient-skills --skill make-pdfAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 15 stars15 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
8.3 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
Nutrient Make PDF
Turn a Markdown or HTML file into a finished PDF through the Nutrient DWS Build API. The differentiator over local chromium --print-to-pdf or Pandoc is the output stage: the same call can emit tagged, accessible PDF/UA or archival PDF/A, and stamp a diagonal text watermark — compliance work a plain HTML-to-PDF pipeline cannot do.
Quick Start
All paths below are relative to this skill's directory (the directory containing scripts/ and assets/).
- Export the API key before generating (not needed for
--html-onlyor the smoke test):export NUTRIENT_API_KEY="nutr_sk_..."(the same variable the siblingdocument-processor-apiscripts use;NUTRIENT_DWS_API_KEYis accepted as a fallback)
- Generate:
uv run scripts/make-pdf.py --input report.md --out report.pdf
The markdown-it-py and nutrient-dws packages are fetched automatically on first use.
Common Tasks
- Standard PDF from Markdown:
uv run scripts/make-pdf.py --input notes.md --out notes.pdf - Accessible PDF/UA (tagged, for WCAG/ADA/EAA requirements): add
--accessible - Archival PDF/A: add
--pdfa(conformance via--pdfa-level, one ofpdfa-1a/1b/2a/2b/2u/3a/3u, defaultpdfa-2b; only valid together with--pdfa) - Draft watermark: add
--watermark DRAFT - Memo layout instead of the default document layout:
--template memo - Dark theme:
--theme dark - Title-page metadata:
--title,--subtitle,--author,--date(or set them in Markdown frontmatter; CLI flags win) - Inspect the rendered HTML without calling the API (offline, no key):
--html-only(Markdown input only — errors on.htmlinput, which already is the HTML) - Debug layout alongside the PDF:
--output-htmlwrites the intermediate HTML next to the PDF - Batch: point
--inputat a directory (with--out <dir>, required) to convert every.md/.htmlin it — see Batch Conversion below
--accessible and --pdfa are mutually exclusive (one output type per build). Check exact arguments with uv run scripts/make-pdf.py --help.
Input Rules
.mdinput is converted to HTML with a CommonMark+GFM parser (tables, strikethrough, task lists), then wrapped in the selected template with the theme CSS inlined — one self-contained HTML file is uploaded..htmlinput is uploaded as-is; template, theme, and metadata flags do not apply and a warning names any that were passed. Use it when you already have styled HTML.- YAML frontmatter in Markdown (
title,subtitle,author,date,template,theme) controls the cover block; CLI flags override frontmatter. When no title is given anywhere, the first#heading (or the filename) becomes the document title, so accessible output always has a real title. - External images require network fetches on the DWS side and referenced local images are not uploaded in v1 — embed images as
data:URIs if they must appear.
Verification (built in)
Compliance outputs are verified, not just labeled. With --accessible or --pdfa, the generated PDF is automatically checked after the build (--no-verify opts out); exit code 3 means "generated but failed verification" — the PDF is kept on disk so you can inspect it. If the verifier itself cannot run, the build still exits 3 rather than silently passing; --no-verify is the explicit way to accept unverified output. Passing --verify without a compliance flag is rejected up front — a standard PDF has no conformance claim to check.
Two assurance levels, and be honest about which one ran:
- Structural checks (always available, via
scripts/verify-pdf.py): the PDF/UA-1 claim marker (pdfuaidXMP part 1 — PDF/UA-2 documents are out of scope), tagged-structure signals (MarkInfo,StructTreeRoot), language,DisplayDocTitle, and a non-empty document title — or the PDF/A identification (pdfaidpart + conformance, matched against the requested level). These catch real failures but are not a full conformance audit. - Full audit (optional): if
verapdfis installed on PATH, the verifier also runs veraPDF for a genuine conformance validation and reports its verdict. Recommend installing veraPDF when the user's requirement is regulatory (ADA/EAA deadlines, records retention).
The verifier also works standalone on any PDF, including ones this skill did not create:
uv run scripts/verify-pdf.py --input existing.pdf --profile pdfua
uv run scripts/verify-pdf.py --input archive-dir/ --profile pdfa --pdfa-level pdfa-2b
Batch Conversion
--input <directory> converts every .md, .markdown, .html, and .htm file directly in that directory (non-recursive), up to 4 concurrently:
uv run scripts/make-pdf.py --input reports/ --out pdfs/ --accessible
--out <dir>is required for directory input; outputs are named<stem>.pdf.- Per-document metadata comes from each file's frontmatter, first
#heading, or filename — global--title/--subtitleare rejected for directory input. Shared flags (--template,--theme,--author,--date,--watermark, compliance and verify flags) apply to every file. - Failures don't stop the batch: a summary on stderr lists converted/verified/failed counts, stdout still prints only created file paths. Exit 0 = all good, 1 = at least one build failed, 3 = builds succeeded but at least one verification failed.
- Batch mode never overwrites existing outputs (and refuses inputs that would collide on the same output name) — point
--outat a fresh directory or remove stale files when regenerating.
Layout Honesty (Chromium limits)
DWS renders HTML with headless Chromium (printToPDF). That means standard print CSS works (@page size and margins, page-break-*/break-* rules, @media print), but CSS Paged Media features Chromium does not implement will silently not render: position: running() running headers/footers, counter(page), and target-counter() TOC page numbers. Do not promise page-numbered TOCs or running headers from CSS. If the user needs those, say so and offer the trade-offs (front-matter TOC without page numbers, or a different toolchain).
Chaining Other Document Operations
Generation is one step. Related operations live in sibling plugins from the same marketplace:
- Sign, redact, or merge the produced PDF: the
document-processor-apiskill —/plugin install nutrient-dws@nutrient-skills. Its scripts read the sameNUTRIENT_API_KEY; run them from that skill's own directory, e.g.uv run scripts/sign.py --input report.pdf --out report-signed.pdf. - Make an EXISTING PDF accessible (auto-tag for PDF/UA): the
remediate-pdfskill —/plugin install remediate-pdf@nutrient-skills. This skill generates new PDFs; that one fixes old ones (and bundles the sameverify-pdf.py).
Implementation Rules
- Fail fast with a clear message when
NUTRIENT_API_KEY(or theNUTRIENT_DWS_API_KEYfallback) is missing (unless--html-only). - Never log the API key or request headers.
- Write outputs to explicit paths and print each created file path (one path per line on stdout; progress on stderr). A debug HTML path prints as soon as the file exists, even if a later build step fails.
- Non-zero exit on any failure; do not claim success unless the output file exists and is non-empty.
Validation
Before calling this skill done after changes:
uv run scripts/smoke-test.py— offline (no network, no key): every template x theme combination, Markdown feature survival (headings, tables, code blocks), verifier checks against constructed fixtures, and batch discovery.- Generate one real PDF if a key is available; for compliance outputs let the built-in verification run (or run
verify-pdf.pyexplicitly) rather than only checking the file is non-empty.
What ships with it: 8 files
55.3 KB alongside SKILL.md, 3 of them executable
assets/
- sample/sample.md1.2 KB
- templates/document.html429 B
- templates/memo.html482 B
- themes/dark.css2.2 KB
- themes/light.css2.2 KB
scripts/
- make-pdf.pyruns22.6 KB
- smoke-test.pyruns11.7 KB
- verify-pdf.pyruns14.5 KB