AI agents can write code. But when you ask one to generate a polished PDF -- with cover pages, tables, badges, dosing schedules, and pixel-matched typography -- most frameworks fight back hard.
We needed to know: which PDF framework produces the best results when the "developer" is an LLM?
So we took a real 4-page clinical protocol document and rebuilt it from scratch in 8 different frameworks, using AI agents (Codex, Claude) to write every generator script. Then we had Codex review each output against the HTML original.
This repo is the result. Every script, every output, every review -- all public.
| Framework | Language | Approach | Script |
|---|---|---|---|
| Typst | Typst | Native markup language | gen_typst.typ (v1-v5) |
| FPDF2 | Python | Procedural API | gen_fpdf2.py |
| ReportLab | Python | Platypus flowables | gen_reportlab.py |
| WeasyPrint | Python | HTML/CSS to PDF | gen_weasyprint.py |
| Playwright | Python | Headless Chromium | gen_playwright.py |
| pdfmake | Node.js | Declarative JSON | gen_pdfmake.js |
| React-PDF | Node.js | React components | react-pdf/gen.mjs |
| LaTeX | LaTeX | TeX typesetting | gen_latex.tex |
Typst wins. After 5 iterations it produced the closest match to the HTML original. Its markup is clean, its output is sharp, and LLMs write good Typst code because the syntax is straightforward.
The short version:
- Typst -- Best overall. Clean syntax, excellent typography, fast compilation. LLM-friendly.
- ReportLab -- Strongest Python option. Verbose but precise pixel control.
- FPDF2 -- Lightweight Python. Good for simpler layouts, struggles with complex grids.
- LaTeX -- Beautiful output but the boilerplate is brutal. LLMs generate too many packages.
- pdfmake -- Decent declarative approach. Badge/circle rendering is limited.
- React-PDF -- Familiar if you know React. Limited layout primitives.
- WeasyPrint -- Great idea (just use CSS!) but CSS-to-PDF edge cases are painful.
- Playwright -- Screenshot-to-PDF. Least control, most dependency headaches.
git clone https://github.com/199-biotechnologies/agent-pdf-cli.git
cd agent-pdf-clipip install fpdf2 reportlab weasyprint playwright
playwright install chromiumcd scripts && npm installbrew install typst # macOS
# or download from https://github.com/typst/typst/releasesEach generator is standalone. Run any of them:
# Python
python scripts/gen_fpdf2.py
python scripts/gen_reportlab.py
# Node.js
node scripts/gen_pdfmake.js
node scripts/react-pdf/gen.mjs
# Typst
typst compile scripts/gen_typst_v5.typ output/typst-v5.pdfAll output lands in output/.
data/protocol-data.json <-- Sample protocol (patient data, peptides, supplements)
|
v
scripts/gen_*.{py,js,typ,tex} <-- 8 framework generators
|
v
output/*.pdf <-- Generated PDFs for comparison
- Same input data -- every generator reads from
protocol-data.jsonor embeds the same content - Same target design -- a 4-page Healtrix clinical protocol with cover, tables, badges, and monitoring grids
- AI-written generators -- each script was written by Claude or Codex, not hand-coded
- Codex reviews -- GPT-5.4 compared each PDF output against the HTML baseline
agent-pdf-cli/
data/
protocol-data.json # v1 sample data
protocol-data-v2.json # v2 sample data (alternate schedule)
scripts/
gen_fpdf2.py # FPDF2 generator
gen_reportlab.py # ReportLab generator
gen_weasyprint.py # WeasyPrint generator
gen_playwright.py # Playwright generator
gen_pdfmake.js # pdfmake generator
gen_latex.tex # LaTeX source
gen_typst.typ # Typst v1
gen_typst_v2.typ # Typst v2 (data-driven)
gen_typst_v3.typ # Typst v3 (Codex fixes)
gen_typst_v4.typ # Typst v4 (full rewrite)
gen_typst_v5.typ # Typst v5 (native design)
react-pdf/gen.mjs # React-PDF generator
output/ # Generated PDFs
fonts/ # Shared fonts
See CONTRIBUTING.md. PRs welcome -- especially new framework generators.