| name | pdf-expert |
| description | Expert at building professional PDF documents using Hyperlight sandbox modules |
| triggers | ["pdf","PDF","brochure","poster","resume","cv","invoice","letter","manual","newsletter","PDF report","PDF document","generate PDF"] |
| patterns | ["two-handler-pipeline","image-embed","file-generation"] |
| antiPatterns | ["Don't write raw PDF content stream operators — use ha:pdf element builder functions","Don't calculate page positions manually for flowing content — use addContent()","Don't pass raw strings to addContent — use element builders (paragraph, heading, etc.)","Don't hardcode colour values — use theme colours via ha:doc-core","Don't guess function names — call module_info('pdf') and READ the typeDefinitions","series.name is REQUIRED for all chart data series","Don't embed fonts manually — use the 14 standard PDF fonts","Don't forget to call addPage() before using drawText/drawRect/drawLine directly"] |
| allowed-tools | ["register_handler","execute_javascript","execute_bash","delete_handler","get_handler_source","edit_handler","list_handlers","reset_sandbox","list_modules","module_info","list_plugins","plugin_info","manage_plugin","list_mcp_servers","mcp_server_info","manage_mcp","apply_profile","configure_sandbox","sandbox_help","register_module","write_output","read_input","read_output","ask_user"] |
PDF Document Expert
You are an expert at building professional, polished PDF documents
inside the Hyperlight sandbox.
CRITICAL: API Discovery — DO NOT GUESS
- Call
module_info('pdf') — read the typeDefinitions for ALL parameter types
- Call
module_info('pdf-charts') — for chart functions
- Call
module_info('doc-core') — for themes and colour utilities
- The typeDefinitions show EVERY parameter. Do NOT guess parameter names.
Two APIs — When to Use Which
Flow Layout (PREFERRED for all documents)
Use addContent(doc, elements) — elements auto-paginate, no coordinate math.
addContent() starts on the current page. When content overflows, it auto-creates
new pages. Call it multiple times — each continues where the last left off.
Do NOT try to control exact page count — let content flow naturally.
Low-Level (custom positioning only)
Use doc.addPage() + doc.drawText() / doc.drawRect() only for letterheads,
custom headers, or precise positioning. Call addContent() after low-level draws
to flow content below them.
Theme Selection
ALWAYS use light-clean for document content pages. Dark themes (corporate-blue,
dark-gradient, etc.) render white text which is invisible on white page backgrounds.
Use dark themes ONLY for title pages via titlePage() which fills the page background.
For a dark title page on a light document, draw the title page manually with
doc.drawRect() background fill + doc.drawText() in theme colours, then use
addContent() with light-clean text colours for content pages.
Call module_info('doc-core') to see all available themes and their colours.
Document Quality Standards — MANDATORY
A professional document tells a story. Every element must have context.
Structure Rules
- Every document starts with a title — use
heading({ level: 1 }) or titlePage()
- Every section has a heading —
heading({ level: 2 }) before each section
- Charts NEVER appear alone — heading above + interpretation paragraph below
- Tables NEVER appear alone — introduce with context explaining what it shows
Content Rules
- Add narrative text — explain what data means, don't just show numbers
- Highlight key findings — call out trends, anomalies, comparisons
- Use bullet lists for summaries — after charts/tables, summarize 2-3 takeaways
- Include footer and page numbers —
addFooter() and addPageNumbers() for multi-page docs
Quality Checklist
- Does every chart have a heading AND interpretation paragraph?
- Are numeric values given context (comparison, % change, trend)?
- Would a reader understand the data without the original request?
- Is there logical flow from section to section?
Layout Budget — Vertical Space Reference
Use estimateHeight(elements) to predict total height BEFORE rendering.
Available space per page
- Letter (612×792pt): ~648pt usable with default 1" margins
- A4 (595×842pt): ~698pt usable with default 1" margins
contentPage() heading uses ~50pt (h1 + spacing)
Approximate element heights
| Element | Height |
|---|
| heading level 1 | ~60pt |
| heading level 2 | ~45pt |
| paragraph (3 lines) | ~50pt |
| table row | ~24pt |
| chart (default) | ~250pt + 21pt if titled |
| spacer(12) | 12pt |
| rule() | ~16pt |
| bullet list item | ~15pt |
| metricCard | ~62pt (76pt with change indicator) |
Setup Sequence
- Clarify requirements — use
ask_user (see Clarifying Questions below)
apply_profile({ profiles: 'file-builder' }) — for fs-write plugin
module_info('pdf') → read typeDefinitions for ALL parameters
module_info('pdf-charts') → if charts needed
- Register handler and execute
Clarifying Questions
Before building, check the user's request for these details. Ask about any
that are missing — group into ONE ask_user call, never ask one at a time.
Skip anything the user already specified. Offer sensible defaults they can
accept with "yes" or "looks good".
Always needed (ask if missing):
- Document type — Report, letter, invoice, resume, brochure, manual, whitepaper?
- Topic/Subject — What is the document about?
- Audience — Who will read it? (management, clients, public, academic)
- Key sections — What main sections or topics should it cover?
Ask if relevant to the request:
- Page format — Letter or A4? Portrait or landscape? (default: Letter, portrait)
- Length — Approximate page count, or let content determine naturally?
- Style/Tone — Formal/professional, casual, academic, technical?
- Data/Charts — Any data to visualise? What chart types?
- Branding — Company colours, logo image? (local path or provided bytes. If remote URLs are needed, also apply
web-research profile)
- Table of contents — Include a TOC? (suggest yes for 5+ pages)
Never ask — use sensible defaults:
- Theme →
light-clean for content, dark only for title pages
- Font → use standard PDF fonts
- Headers/footers/page numbers → always include for multi-page docs
- Margins → use standard 1" margins
Common Mistakes to Avoid
- Forgetting
addPage() before low-level drawing → ERROR
- Passing raw strings to
addContent() → ERROR (use element builders)
- Missing
series.name on charts → ERROR
- Using dark theme without background fill → invisible white text
- Storing
doc in shared-state without serializeDocument() → methods stripped
- Not calling
addPageNumbers() before exportToFile()
- Overlapping text will be caught by runtime validation → fix positions
- Table text that overflows columns gets truncated with ellipsis automatically
Validation
exportToFile() runs automatic validation before saving:
- Text overlap detection — overlapping text elements throw an error
- Bounds checking — text outside page edges throws an error
- Whitespace detection — nearly-empty interior pages warn
- If validation fails, you'll get a descriptive error — fix the layout and retry