CLI
The stationery executable: render a document file to PDF and pictures, print what is on its pages, list or install font packs, find the examples, and install the skill for coding agents.
stationery render#
Render the Document a Ruby file defines.
stationery render app/pdfs/invoice_pdf.rb # writes app/pdfs/invoice_pdf.pdf
stationery render invoice.rb --out - > invoice.pdf # PDF to stdout
stationery render pdfs.rb --class InvoicePdf --strict # pick one; fail on layout warnings
stationery render examples/report.rb --debug # layout outlines
stationery render invoice.rb --png # also invoice-1.png, … beside the PDF
stationery render report.rb --png-only --pages 1,3-4 --dpi 144
stationery render examples/shipping_label.rb --zpl # writes shipping_label.zpl, 203 dpi| Option | Meaning |
|---|---|
-o, --out PATH | Where to write the PDF (default: the file's name with .pdf); - writes to stdout. |
-c, --class NAME | The document class to render when the file defines several. |
--zpl | Write ZPL for a label printer instead of a PDF (default: the file's name with .zpl); see Label printers. |
--dpi DPI | The label printer's resolution for --zpl: 152, 203 (default), 300 or 600. For --png, pixels per inch of the pictures (default 96: an A4 page is 794 × 1123 px). |
--strict | Exit 1 without writing when layout reports warnings. |
--debug | Render with debug: true when the document supports it. |
--png | Also write a PNG of each page beside the PDF: invoice-1.png, invoice-2.png, … |
--png-only | Write the PNGs and no PDF. |
--pages LIST | The pages to picture, as 2 or 1,3-4 (default: all). |
-h, --help | Show help. |
render loads the file and renders the Stationery::Document it defines, then reports pages (or labels) and bytes. Layout warnings print to stderr.
The pictures are drawn by to_png (see Pictures of a render), in Ruby with nothing to install, and each file is reported on a line of its own (wrote invoice-1.png (page 1, 794 x 1123 px)), so an agent that rendered a document can open what it made.
stationery inspect#
What is on each page, as text.
stationery inspect invoice.pdf # what is on each page, as text
stationery inspect invoice.rb # render it first, with its warnings
stationery inspect invoice.pdf --json # Inspector#layout as JSON| Option | Meaning |
|---|---|
--json | Print the layout as JSON. |
-c, --class NAME | The document class to render when a Ruby file defines several. |
-h, --help | Show help. |
inspect prints what is on each page for an agent that cannot read a picture, and for a diff between two renders: the file's metadata, conformance claims, print hints, attachments and signatures, the outline, then each page with its size, its text lines (x, baseline y, font, size), images, links and form fields with their rectangles in points from the top-left corner, the structure tree of a tagged PDF and the warnings of the render. Sections with nothing in them are left out, and so are the dates, so two renders of one document print the same. It is Inspector#layout (see Testing) and needs the pdf-reader gem.
examples/invoice.rb
pages 1
title Invoice
Page 1 595.3 x 841.9 pt
Text (x, baseline y, font, size, text)
44.0 65.5 OpenSans-Bold 22 Invoice INV-2026-042
44.0 115.6 OpenSans-Bold 9 Invoice date
134.0 115.6 OpenSans-Regular 9 26 September 2026
Images (x, y, width x height, pixels)
437.9 40.0 113.3 x 34 240 x 72 px
Links (x, y, width x height, target)
329.2 596.5 65.6 x 11.6 mailto:[email protected]stationery verify#
Check PDFs in the engines viewers are built on.
stationery verify invoice.pdf report.pdf # every engine installed
stationery verify invoice.rb # render it first
stationery verify invoice.pdf --engines qpdf,poppler # these, and fail if one is missing
stationery verify locked.pdf --password 1234 --json| Option | Meaning |
|---|---|
--engines LIST | The engines to run, comma-separated: qpdf, poppler, mupdf, pdfium, pdfjs, pdfkit. Without it, every one installed. |
--password PASSWORD | The user password of encrypted files. Poppler and MuPDF take it on their command lines, where other processes of the machine can see it. |
--json | Print the report as JSON. |
-c, --class NAME | The document class to render when a Ruby file defines several. |
-h, --help | Show help. |
verify reads each file with qpdf, Poppler, MuPDF, PDFium, pdf.js and PDFKit, the engines of the Linux desktop viewers, Chrome and Edge, Firefox, and Preview and Safari, and holds what each reads against what the file holds. Any error or warning an engine gives fails it, and so does a page count, a text line, a link, the outline, a form field, an attachment, a signature or a structure tree it reads otherwise. It exits 0 when every engine passes every file, 1 otherwise or when no engine is installed, and 2 on a usage error. It needs the pdf-reader gem, and the engines are tools you install: see Viewers.
invoice.pdf
qpdf ok (qpdf version 12.4.2)
poppler ok (poppler 26.09.0)
mupdf ok (mutool 1.28.5)
pdfjs FAILED (pdfjs-dist 6.3.289)
page 1: link not found: {uri: "https://example.com/terms"}
not run: pdfium (pip install pypdfium2 (STATIONERY_PYTHON names the Python that has it))self.preview#
Documents that need arguments.
A document whose initialize needs arguments renders from def self.preview, which returns an instance built with sample data — the same method is handy in tests and Rails previews:
class ExampleInvoice < Stationery::Document
def self.preview
new(number: "INV-2026-042", items: [["Brand workshop", 1, 2400.0]],
customer: "Müller & Söhne GmbH", due: "26 October 2026")
end
def initialize(number:, items:, customer:, due:)
super()
# …
end
endstationery fonts#
List and install font packs.
stationery fonts list # packs, licenses, what is in vendor/fonts
stationery fonts install noto_sans liberation_serif # into vendor/fonts/<pack>/
stationery fonts install noto_sans --into app/fonts --force
stationery fonts install liberation_sans --from ~/Downloads/liberation-fonts-ttf-2.1.5.tar.gz # offlinefonts install downloads pinned files over HTTPS, checks every SHA-256 before writing anything, and writes the license next to the fonts. Files already present are kept unless --force. --from takes a directory or a .tar.gz holding the same files (still SHA-checked). See Fonts.
stationery examples#
The examples that ship with the gem.
stationery examples # the examples in the gem, what each shows
stationery examples invoice # the path of examples/invoice.rb there
stationery examples invoice --source # its code
stationery render "$(stationery examples invoice)" --out invoice.pdfexamples lists the documents under examples/ of the installed gem with the first sentence of their header comment. With a name it prints the path of that file, to read, copy or hand to stationery render; -s, --source prints the file itself. The Examples page has their previews.
stationery help lists the commands.
stationery skill#
The skill for coding agents that ships with the gem.
stationery skill install # for the agents it finds, else Claude Code
stationery skill install --target claude --project # into ./.claude/skills/stationery
stationery skill install --dir ~/agent-skills # into any skills directory
stationery skill status # current, outdated or missing, per agent
stationery skill print # SKILL.md and its files, as one document| Option | Meaning |
|---|---|
--target NAME | claude (~/.claude/skills), codex (~/.codex/skills), agents (~/.agents/skills, read by OpenCode and others) or all. Without it, install writes to each whose directory exists, and to Claude Code when none does; status reports all three. |
--project | The skills directory under the current directory (./.claude/skills, …) instead of the home directory. |
--dir DIR | This skills directory instead; the skill goes to DIR/stationery. |
--force | Replace a skill named stationery that the gem did not write. |
-h, --help | Show help. |
install writes SKILL.md and the files beside it (reference/*.md, from the README; recipes/*.md, an invoice, a report, a form, a flyer, a label and a receipt that each render and name their example). The front matter names the gem's version, which is what status compares: current, outdated (written for an older version: run install again), missing, or not written by stationery. print writes the same files to stdout as one Markdown document, for an agent that takes one file. See Getting started for the docs over MCP.