Generate professional PDFs from code, markdown, or HTML in the current repository. Supports cover pages, tables of contents, watermarks, custom margins, and page sizes.
Scanned 9/3/2026
Install to Claude Code
npx -y skills add timurgaleev/vibestack --skill make-pdf --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Make Pdf?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/timurgaleev-make-pdf)More formats (shields.io, HTML) on the badges page.
---
name: make-pdf
description: |
Generate professional PDFs from code, markdown, or HTML in the current repository. Supports cover pages, tables of contents, watermarks, custom margins, and page sizes.
triggers:
- make pdf
- generate pdf
- create pdf
- export pdf
- pdf preview
allowed-tools:
- Bash
- Read
- Write
- Glob
- Grep
- AskUserQuestion
---
## When to invoke
Use when asked to "make pdf", "generate pdf", "export to pdf", "create pdf report", or "pdf preview".
## Preamble
```bash
eval "$(~/.vibestack/bin/vibe-slug 2>/dev/null)" 2>/dev/null || SLUG="unknown"
_LEARN_FILE="${VIBESTACK_HOME:-$HOME/.vibestack}/projects/${SLUG:-unknown}/learnings.jsonl"
if [ -f "$_LEARN_FILE" ]; then
_LEARN_COUNT=$(wc -l < "$_LEARN_FILE" 2>/dev/null | tr -d ' ')
echo "LEARNINGS: $_LEARN_COUNT entries loaded"
if [ "$_LEARN_COUNT" -gt 5 ] 2>/dev/null; then
~/.vibestack/bin/vibe-learnings-search --limit 5 2>/dev/null || true
fi
else
echo "LEARNINGS: none yet"
fi
```
{{include lib/snippets/session-host.md}}
{{include lib/snippets/decision-brief.md}}
{{include lib/snippets/working-protocols.md}}
{{include lib/snippets/state-protocols.md}}
## Step 0: Find the make-pdf renderer
```bash
# Env override first, then the launcher installed with this skill (resolves
# the repo's compiled binary or runs the CLI on bun).
P="${MAKE_PDF_BIN:-${CLAUDE_SKILL_DIR:-$HOME/.claude/skills/make-pdf}/bin/vibe-make-pdf}"
[ -x "$P" ] && "$P" version >/dev/null 2>&1 && echo "FOUND: $P" || echo "NOT_FOUND"
```
If `NOT_FOUND`, stop and tell the user:
> make-pdf renderer not found. It ships with the vibestack repo.
> Run: `cd ~/data/vibestack && bun install && bun run build:make-pdf && ./install`
> Or set `$MAKE_PDF_BIN` to the path of an existing `make-pdf` binary.
>
> After building, re-run `/make-pdf`.
---
## Step 1: Detect intent
Parse the user's input to determine what to do:
1. `/make-pdf` with no args — **Auto-detect**: look for markdown files or ask what to convert
2. `/make-pdf preview <file>` — **Preview mode**: generate and open a PDF preview
3. `/make-pdf setup` — **Setup mode**: run `$P setup` to configure defaults
4. `/make-pdf <file or description>` — **Generate mode**: produce a PDF from the specified input
---
## Step 2A: Generate mode
1. Identify the source file(s). If the user provided a path, use it. If not, ask:
```
What should I turn into a PDF?
A) A specific file (provide path)
B) All markdown files in this directory
C) A generated report (I'll describe what to include)
D) Something else
```
2. Determine output filename. Default: `<source-basename>.pdf` in the same directory.
3. Run the generator:
```bash
"$P" generate "<source>" --output "<output.pdf>" [flags]
```
Common flags:
- `--cover` — add a cover page (uses repo name + date)
- `--toc` — add a table of contents
- `--watermark "<text>"` — overlay watermark text (e.g., "DRAFT", "CONFIDENTIAL")
- `--margins <dim>` — one dimension for all four margins (default: `1in`; also `72pt`, `2.54cm`, `25mm`)
- `--page-size <size>` — A4 (default), Letter, Legal
- `--title "<title>"` — override document title
- `--author "<name>"` — set author metadata
- `--to pdf|html|docx` — output format (default: `pdf`)
- `--no-confidential` — suppress the CONFIDENTIAL footer stamped by default
- `--strict` — missing or remote images fail the run instead of warning
4. Report the result:
```
PDF GENERATED
═══════════════════════════════════════════
Output: <output.pdf>
Size: <file size>
Pages: <page count>
═══════════════════════════════════════════
```
---
## Step 2B: Preview mode
Generate the PDF and open it:
```bash
"$P" preview "<source>" [flags]
```
This generates a temporary PDF and opens it in the system PDF viewer. Report the path if the user wants to save it.
---
## Step 2C: Setup mode
Verify the render toolchain — browse binary, Chromium launch, `pdftotext` (optional) — then
generate and open a smoke-test PDF:
```bash
"$P" setup
```
It writes no config file. Report which checks passed and, if Chromium or the browse binary
failed, relay the fix it printed before attempting any other mode.
---
## Core patterns
### 80% case — memo/letter
One command, no flags. Gets a clean PDF with running header, page numbers, and a
CONFIDENTIAL right-footer.
```bash
"$P" generate letter.md # writes /tmp/letter.pdf
"$P" generate letter.md letter.pdf # explicit output path
```
### Brand-free — no CONFIDENTIAL footer
The footer is on by default, so anything meant to leave the building needs it turned off:
```bash
"$P" generate --no-confidential memo.md memo.pdf
```
### Publication mode — cover + TOC + chapter breaks
```bash
"$P" generate --cover --toc --title "On Horizons" essay.md essay.pdf
```
Each top-level H1 starts a new page. Disable with `--no-chapter-breaks` for memos that happen to have multiple H1s.
### Draft-stage watermark
```bash
"$P" generate --watermark DRAFT memo.md draft.pdf
```
Diagonal DRAFT across every page. Drop the flag when final.
### Diagrams — mermaid and excalidraw fences render as pictures
A column-0 ```` ```mermaid ```` or ```` ```excalidraw ```` fence renders as a vector diagram,
offline. Indented fences are left alone, so a fence quoted inside a list stays a code block.
Info-string options on the opening fence:
- `title="Auth flow"` — accessible label for the rendered figure
- `render=false` — leave this fence as a plain code block (the escape hatch when the source
is what the reader needs to see)
- `page=landscape` / `page=portrait` — force or veto a landscape page for this diagram
A fence whose source fails to parse becomes a visible red diagnostic block carrying the error
and an excerpt — never a silently missing figure. When that shows up, fix the diagram source
rather than dropping the fence.
### Images — scaled right, never truncated
A directive suffix on a markdown image tunes its placement:
```markdown
{width=full}
{width=50%}
{page=landscape}
{page=portrait}
```
`width` takes `full`, a percentage, or an absolute dimension (`in`, `cm`, `mm`, `pt`, `px`).
By default an image renders at its intrinsic size, capped at the content box and never
upscaled.
Wide, small-text images auto-promote to their own landscape page. The heuristic is deliberately
conservative — aspect ratio at least 1.8, intrinsic width over roughly 2.5x the content box,
*and* either diagram provenance or a diagram-ish word in the alt text — so it misses more often
than it fires. `{page=landscape}` forces promotion; `{page=portrait}` vetoes it.
Local images are inlined as data URIs and rasters wider than print resolution are downscaled.
An image that is missing, not a regular file, or over 64MB degrades to a visible placeholder
with a warning; one resolving outside the markdown's own directory is inlined but warned about,
because an agent rendering untrusted markdown should not quietly embed a file from elsewhere on
the machine into a shareable document.
### Other formats — single-file HTML and Word
```bash
"$P" generate readme.md out.html --to html # one self-contained file, no network refs
"$P" generate readme.md out.docx --to docx # content fidelity; diagrams become PNG
```
`--to` is the output format. `--format` is something else entirely — an alias for
`--page-size` — so `--format html` asks for a page size named "html", not HTML output.
### CI mode — fail loud on missing assets
```bash
"$P" generate docs.md --strict
```
Missing, unreadable, oversized, out-of-tree, and remote images become hard failures instead of
warnings, so a broken asset path fails the build rather than shipping a placeholder.
### Fast iteration via preview
```bash
"$P" preview essay.md
```
Renders with print CSS and opens in browser. Skip the PDF round trip until you're ready.
---
## Common flags
```
Output format:
--to pdf|html|docx What to produce (default: pdf)
Page layout:
--margins <dim> 1in (default) | 72pt | 2.54cm | 25mm
--page-size letter|a4|legal (alias --format — page SIZE, not --to)
Structure:
--cover Cover page (title, author, date)
--toc Clickable TOC with page numbers
--no-chapter-breaks Don't start a new page at every H1
Branding:
--watermark <text> Diagonal watermark ("DRAFT", "CONFIDENTIAL")
--header-template <html> Custom running header
--footer-template <html> Custom footer (mutex with --page-numbers)
--no-confidential Suppress the CONFIDENTIAL right-footer (on by default)
Output:
--page-numbers "N of M" footer (default on)
--tagged Accessible PDF (default on)
--outline PDF bookmarks from headings (default on)
--quiet Suppress progress on stderr
--verbose Per-stage timings
Images:
--strict Missing/remote images fail the run (CI mode)
Network:
--allow-network Fetch external images. Off by default
(blocks tracking pixels).
Metadata:
--title "..." Document title (defaults to first H1)
--author "..." Author for cover + PDF metadata
--date "..." Date for cover (defaults to today)
```
---
## When to run it
Watch for markdown-to-PDF intent. Any of these → run `"$P" generate`:
- "Can you make this markdown a PDF"
- "Export it as a PDF"
- "Turn this into a PDF"
- "I need a PDF of this"
- "Print this as a PDF for me"
If the user has a `.md` file open and says "make it look nice", propose `"$P" generate --cover --toc` and ask before running.
---
## Output contract
```
stdout: /tmp/letter.pdf ← just the path, one line
stderr: Rendering HTML... ← progress (unless --quiet)
Generating PDF...
Done in 1.5s. 43 words · 22KB · /tmp/letter.pdf
exit code: 0 success / 1 bad args / 2 render error / 3 Paged.js timeout / 4 binary unavailable
```
Capture the path: `PDF=$("$P" generate letter.md)` — then use `$PDF`.
---
## Debugging
- **Blank output** → check binary is executable: `ls -la "$P"`
- **Fragmented text on copy-paste** → remove fenced code blocks and regenerate
- **Timeout** → no headings in the markdown, drop `--toc`
- **External image missing** → the binary fetches external images only when `--allow-network` is set
- **Wrong text metrics or ▯ boxes where emoji should be (Linux, containers)** → the print CSS
falls back to Liberation Sans and a system color-emoji font; install `fonts-liberation` and a
Noto color-emoji package, neither of which the vibestack installer provides
---
## Capture Learnings
If you discovered a non-obvious make-pdf behavior, flag pattern, or conversion quirk
during this session, log it for future sessions:
```bash
~/.vibestack/bin/vibe-learnings-log '{"skill":"make-pdf","type":"TYPE","key":"SHORT_KEY","insight":"DESCRIPTION","confidence":N,"source":"SOURCE","files":["path/to/relevant/file"]}'
```
**Types:** `pattern` (reusable approach), `pitfall` (what NOT to do), `tool`
(binary behavior), `operational` (env/path/dependency quirk).
**Only log genuine discoveries.** A good test: would this save time in a future session?
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!