On Runtime, Markdown written by a model becomes a PDF or a Word file on a
machine that can read nothing but that Markdown. Each sandbox is a
Firecracker microVM with its own kernel and disk. Pandoc's own --sandbox flag
narrows access further, to the files named on the command line. Runtime bills
the CPU a render uses, not the CPU the sandbox holds. A 2 vCPU, 4 GiB sandbox
costs $0.03125 an hour between documents, and $0.08 an hour with both
CPUs busy (pricing).
Which pandoc
| Source | Version on 25 October 2026 | Install |
|---|---|---|
Ubuntu 24.04 package pandoc |
3.1.3 | sudo apt-get install -y pandoc |
| pandoc's GitHub release, 8 October 2026 | 3.12.1 | pandoc-3.12.1-1-amd64.deb, then sudo dpkg -i |
pandoc's install page offers the release .deb for the latest version on Linux.
It downloads from GitHub over HTTPS, which a sandbox without credit can reach.
Choose the PDF engine
pandoc makes a PDF through another program. Its manual names pdflatex as the
default. It also lists lualatex, xelatex, latexmk, tectonic,
wkhtmltopdf, weasyprint, pagedjs-cli, prince, context, groff,
pdfroff and typst. The table below shows the ones that Ubuntu 24.04 packages:
| Engine | Ubuntu package(s) | Good for |
|---|---|---|
pdflatex |
texlive-latex-recommended, texlive-fonts-recommended, lmodern |
Papers, maths, the classic LaTeX look |
xelatex |
texlive-xetex |
System fonts and non-Latin scripts |
weasyprint |
weasyprint (61.1) |
Styling a PDF with CSS, a small install |
wkhtmltopdf |
wkhtmltopdf (0.12.6) |
HTML-first layouts |
The TeX Live packages in noble are 2023.20240207. Ubuntu's archive for 24.04 does not include Typst.
Markdown to PDF and DOCX
TypeScriptimport { writeFile } from "node:fs/promises";import { Sandbox } from "withruntime";const markdown = "# Quarterly report\n\nRevenue rose **12%**.\n\n| Region | Sales |\n|---|---|\n| West | 120 |\n";await using sbx = await Sandbox.create({ diskMiB: 6144, timeoutSeconds: 900 });await sbx.exec( "curl -fsSLO https://github.com/jgm/pandoc/releases/download/3.12.1/pandoc-3.12.1-1-amd64.deb" + " && sudo dpkg -i pandoc-3.12.1-1-amd64.deb" + " && sudo apt-get update -qq && sudo apt-get install -y -qq weasyprint", { check: true, timeoutMs: 600_000 },);await sbx.files.write("/workspace/report.md", markdown);await sbx.files.upload("./report.css", "/workspace/report.css");await sbx.exec( "pandoc --sandbox report.md -s --css report.css --pdf-engine=weasyprint -o report.pdf", { check: true, timeoutMs: 120_000 },);await sbx.exec("pandoc --sandbox report.md -o report.docx", { check: true });await writeFile("report.pdf", await sbx.files.read("/workspace/report.pdf"));await writeFile("report.docx", await sbx.files.read("/workspace/report.docx"));Pythonfrom withruntime import Sandboxmarkdown = "# Quarterly report\n\nRevenue rose **12%**.\n"with Sandbox.create(disk_mib=6144, timeout_seconds=900) as sbx: sbx.exec("curl -fsSLO https://github.com/jgm/pandoc/releases/download/3.12.1/pandoc-3.12.1-1-amd64.deb" " && sudo dpkg -i pandoc-3.12.1-1-amd64.deb" " && sudo apt-get update -qq && sudo apt-get install -y -qq weasyprint", check=True, timeout_ms=600_000) sbx.files.write("/workspace/report.md", markdown) sbx.files.upload("report.css", "/workspace/report.css") sbx.exec("pandoc --sandbox report.md -s --css report.css --pdf-engine=weasyprint -o report.pdf", check=True, timeout_ms=120_000) sbx.exec("pandoc --sandbox report.md -o report.docx", check=True) sbx.files.download("/workspace/report.pdf", "report.pdf") sbx.files.download("/workspace/report.docx", "report.docx")Pandoc picks the output format from the file extension. The .docx format needs
no extra program.
Why --sandbox
Markdown can pull in other files through an image path or an include. When the
text comes from a model or a user, that lets it read files it should not. The
pandoc manual describes --sandbox as limiting input and output in readers and
writers "to reading the files specified on the command line". It offers this
"security against, for example, disclosure of files through the use of include
directives".
In a Runtime sandbox, the two layers work together. Pandoc reads only the files you named, and the machine holds only the files you uploaded. Turn the internet off after the install as well. Then nothing a document references can be fetched (turn off sandbox internet).
House style for Word output
--reference-doc takes a .docx file. According to the pandoc manual, pandoc
copies its styles, margins, page size, header and footer into the output. Its
contents are ignored. Start from a file that pandoc wrote, edit the styles in
Word, and upload it:
TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create({ image: "pandoc" });await sbx.files.upload("./house-style.docx", "/workspace/house-style.docx");await sbx.files.upload("./memo.md", "/workspace/memo.md");await sbx.exec("pandoc --sandbox memo.md --reference-doc=house-style.docx -o memo.docx", { check: true,});await sbx.files.download("/workspace/memo.docx", "./memo.docx");To make the starting file, run pandoc -o custom-reference.docx --print-default-data-file reference.docx.
Start every sandbox with pandoc installed
This is the pandoc image that the last sample uses, as a custom image.
Recipe commands run as root, so they need no sudo:
TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.images.build({ name: "pandoc", recipe: { apt: ["weasyprint"], commands: [ "curl -fsSLO https://github.com/jgm/pandoc/releases/download/3.12.1/pandoc-3.12.1-1-amd64.deb", "dpkg -i pandoc-3.12.1-1-amd64.deb && rm pandoc-3.12.1-1-amd64.deb", ], },});Pythonfrom withruntime import RuntimeRuntime().images.build(name="pandoc", recipe={ "apt": ["weasyprint"], "commands": [ "curl -fsSLO https://github.com/jgm/pandoc/releases/download/3.12.1/pandoc-3.12.1-1-amd64.deb", "dpkg -i pandoc-3.12.1-1-amd64.deb && rm pandoc-3.12.1-1-amd64.deb", ],})For LaTeX output, add the TeX Live packages from the engine table to apt. Also
raise the build machine's scratch disk with build: { diskMiB: 8192 }. The
scratch disk takes 4 GiB to 32 GiB. Building is free. An
account without credit can store three images free.
Limits that apply
- Disk. The default 4 GiB disk had about 2.5 GiB free on 24 September 2026.
WeasyPrint fits. TeX Live needs
diskMiB: 8192, which is within the 10 GiB allowed without credit. - Output in the result. Output from
pandoc -t plainor-t htmlto stdout is kept up to 64 KiB in the command result. Write longer output to a file. - Fonts. A PDF uses the fonts installed in the sandbox. Add the font packages that your CSS or LaTeX template names.
To convert Word, Excel or PowerPoint files to PDF, see LibreOffice in a sandbox. For a chat product that returns generated files, see a code interpreter for chatbots.
Sources
- pandoc manual, https://pandoc.org/MANUAL.html, read 25 October 2026
- Installing pandoc, https://pandoc.org/installing.html, read 25 October 2026
- pandoc 3.12.1 release assets, https://github.com/jgm/pandoc/releases/tag/3.12.1, read 25 October 2026
- Ubuntu 24.04 packages (pandoc, weasyprint, wkhtmltopdf, texlive-*), from the noble package index at http://archive.ubuntu.com/ubuntu/dists/noble/universe/binary-amd64/, read 25 October 2026
Facts on this page were checked on 25 October 2026.