with one click
documents-pdf-skill
Use when generating PDF documents. Uses the marble_pdf API.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Use when generating PDF documents. Uses the marble_pdf API.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
Use when researching competitor ad creatives: find competitors, brand IDs, evergreen winners, breakout winners, pattern analysis.
Use when generating Word documents (.docx). Uses the marble_docx API.
Use when generating PowerPoint presentations (.pptx). Uses the marble_pptx API.
Use when generating Excel workbooks (.xlsx). Pandas + openpyxl patterns for multiple sheets, number formats, freeze panes, formulas.
Use for any GA4 query whose result will be reported back to the user. Covers conversions ≠ transactions distinction, channel-subset-sum trap with sessionDefaultChannelGroup, intraday partial-data discipline, Paid Social aggregation rules, API-vs-UI attribution mismatch.
Use when creating a Google Ads ad group. Loaded after the create master skill.
| name | documents-pdf-skill |
| description | Use when generating PDF documents. Uses the marble_pdf API. |
Use the marble_pdf helper library. It builds HTML internally and converts to PDF via WeasyPrint — giving you full CSS styling with a simple Python API.
IMPORTANT: Always use the library helpers below. Never manually define CSS, color constants, or helper functions — the library handles all of this.
This skill is the complete API reference — all palettes, font pairs, and methods are documented below.
from marble_pdf import PDF
pdf = PDF(f'{WORKSPACE}/report.pdf', palette='ocean', fonts='modern')
# palette: midnight, forest, coral, terracotta, ocean, charcoal, teal, berry, sage, cherry
# fonts: classic, modern, bold, elegant, clean
# Or: PDF(path) for default light theme
| Method | Purpose |
|---|---|
PDF(path, theme, pagesize, margins, palette, fonts) | Create PDF. palette for named colors, fonts for font pair |
pdf.cover_page(title, subtitle, author, date) | Professional cover page with accent lines. Auto page break after |
pdf.title(text) | Title (28px, centered, primary) |
pdf.subtitle(text) | Subtitle (17px, centered, secondary). Use after title() |
pdf.heading(text, level) | Heading (level 1=18px, 2=14px). Use pdf.hr() after headings |
pdf.body(text) | Body paragraph (11px). Supports <b>, <i>, <font>, <sub>, <sup> |
pdf.caption(text) | Caption (9px, secondary) |
pdf.bullet(text) | Bullet list item. Supports HTML markup. Consecutive bullets auto-wrapped in <ul> |
pdf.spacer(height) | Vertical space (default 12px) |
pdf.hr(color) | Horizontal rule (default: primary) |
pdf.table(headers, rows, col_widths, first_col_align, header_bg, header_fg) | Themed table with alternating rows |
pdf.two_column(left_items, right_items, col_widths) | Side-by-side content layout |
pdf.image(path, width, align, max_height) | Insert image (auto-embedded as base64, height auto-scales) |
pdf.page_break() | Page break |
pdf.build(page_numbers=True) | Build final PDF. Call last |
When you need custom layouts beyond the builder API:
from marble_pdf import html_to_pdf, theme_css
css = theme_css('ocean', fonts='modern')
html = f"""<html>
<head><style>{css}</style></head>
<body>
<h2>Custom Report</h2><hr>
<p>Full <b>CSS control</b> — use any HTML elements, flexbox, grid, etc.</p>
<table>
<tr><th>Metric</th><th>Value</th></tr>
<tr><td>Revenue</td><td>$1.2M</td></tr>
</table>
<div class="page-break"></div>
<h2>Page 2</h2>
<p>Content continues...</p>
</body>
</html>"""
html_to_pdf(html, f'{WORKSPACE}/report.pdf')
Available CSS classes from theme_css(): .caption, .subtitle, .cover-page, .cover-author, .cover-date, .two-col + .col, .chart, .bullets, .page-break, .spacer, .spacer-sm, .spacer-lg, .spacer-xl.
Choose a palette that matches the content's mood — not the default blue:
| Palette | Primary | Best for |
|---|---|---|
midnight | Deep navy | Finance, enterprise, formal |
forest | Rich green | Sustainability, health, growth |
coral | Warm pink-red | Marketing, creative, consumer |
terracotta | Earthy brown | Luxury, real estate, hospitality |
ocean | Deep blue | Tech, analytics, professional |
charcoal | Dark gray | Minimal, corporate, neutral |
teal | Vibrant teal | Modern, SaaS, healthcare |
berry | Deep plum | Premium, beauty, fashion |
sage | Muted green-blue | Consulting, calm, wellness |
cherry | Bold red | Bold reports, urgency, food |
| Name | Heading / Body |
|---|---|
classic | Georgia / Calibri |
modern | Calibri / Calibri Light |
bold | Arial Black / Arial |
elegant | Cambria / Calibri |
clean | Trebuchet MS / Calibri |
For reports and long documents:
pdf.cover_page() (includes auto page break)pdf.hr() after section headingspdf.heading('1. Executive Summary')
pdf.hr()
pdf.body('Key findings...')
Use standard HTML tags in pdf.body() and pdf.bullet():
<b>bold</b>, <i>italic</i><font color="#34a853">colored text</font><sub>subscript</sub>, <sup>superscript</sup>| Scenario | figsize |
|---|---|
| Single chart per page | figsize=(7, 3) |
| Two charts per page | figsize=(7, 2.5) |
| Wide chart | figsize=(7, 2) |
| Maximum height | figsize height ≤ 4 (taller overflows) |
width — height auto-scales. Never pass explicit height.max_height param to constrain tall images (default 3.5").When the PDF needs real images returned by previous tool calls (ad thumbnails from facebook_analyze_ad_creative_by_id_or_url, competitor ad images from the ad library, video stills, etc.), pass each image URL as an attachment_url data source on the SAME advanced_analysis call. The runtime downloads them before your code runs — pdf.image() takes the local path:
# Tool call payload:
# dataSources: [
# {type: 'attachment_url', identifier: 'https://cdn.fbcdn.net/.../thumb_a.jpg', alias: 'creative_1'},
# {type: 'attachment_url', identifier: 'https://cdn.fbcdn.net/.../thumb_b.png', alias: 'creative_2'},
# ]
# In code:
from marble_pdf import PDF
pdf = PDF(f'{WORKSPACE}/report.pdf', palette='ocean')
pdf.heading('Top Performers')
pdf.hr()
pdf.image(f'{WORKSPACE}/creative_1.jpg', width=5)
pdf.caption('Figure 1: Outdoor Adventure (Video) — CTR 2.46%')
pdf.image(f'{WORKSPACE}/creative_2.png', width=5)
pdf.caption('Figure 2: Forest Boots — CTR 1.92%')
pdf.build()
Do NOT import requests/urllib from inside your code — network is blocked and the call will fail with DNS errors. The attachment_url mechanism is the supported path. Extensions (.jpg/.png/.webp/.gif etc.) are auto-detected.
pdf.build() — it must be called last to finalize the PDF.pdf.hr() after headings — gives visual structure.height to images — only width. Height auto-scales.\n for spacing — use separate pdf.body() calls or pdf.spacer().pypdf — it is NOT available. Use marble_pdf only. There is no PDF reading/editing library — regenerate from data instead.from marble_pdf import PDF
pdf = PDF(f'{WORKSPACE}/report.pdf', palette='ocean', fonts='modern')
# — Cover page (auto page break) —
pdf.cover_page(
'B&M Advertising Account',
subtitle='Spend & ROAS Performance Report',
author='GoMarble AI',
date='February 17 – February 23, 2026',
)
# — Executive Summary —
pdf.heading('1. Executive Summary')
pdf.hr()
pdf.body('This report covers Meta Ads performance for B&M Advertising over the past 7 days.')
pdf.body('Total spend was <b>$793.95</b> with a blended ROAS of <b>0.70x</b>.')
# — Key Metrics (two-column) —
pdf.heading('2. Key Metrics')
pdf.hr()
pdf.two_column(
['<b>Total Spend:</b> $793.95', '<b>Active Campaigns:</b> 4'],
['<b>Blended ROAS:</b> 0.70x', '<b>Top ROAS:</b> 2.83x (Test)'],
)
pdf.spacer(12)
# — Campaign Breakdown —
pdf.heading('3. Campaign Performance')
pdf.hr()
pdf.table(
headers=['Campaign', 'Spend', 'ROAS', 'Status'],
rows=[
['Prospecting', '$320', '0.55x', 'Active'],
['ASC', '$200', '0.38x', 'Active'],
['BOF', '$137', '1.55x', 'Active'],
['Test', '$136', '2.83x', 'Active'],
],
header_bg='primary', header_fg='text_on_primary',
)
pdf.spacer(8)
# — Chart —
pdf.image(f'{WORKSPACE}/roas_chart.png', width=5.8)
pdf.caption('Figure 1: ROAS by Campaign')
# — Recommendations —
pdf.page_break()
pdf.heading('4. Recommendations')
pdf.hr()
pdf.bullet('<b>Pause Prospecting</b> — 0.55x ROAS, reallocate budget to BOF.')
pdf.bullet('<b>Scale BOF</b> — 1.55x ROAS with $137 spend, room to grow.')
pdf.bullet('<b>Expand Testing</b> — 2.83x ROAS is the highest performer.')
pdf.bullet('<b>Review ASC targeting</b> — 0.38x ROAS suggests audience/creative issues.')
pdf.spacer(20)
pdf.caption('Data Source: Meta Ads Graph API | Report generated by GoMarble AI')
pdf.build()
result = {"title": "B&M Performance Report", "description": "Multi-page PDF with cover and recommendations."}
build() saves an HTML file alongside the PDF (e.g., report.pdf.html). To edit, load the HTML, modify it, and re-convert — no need to rewrite the full generation code.
from marble_pdf import html_to_pdf
# Load the saved HTML
with open(f'{WORKSPACE}/report.pdf.html', 'r') as f:
html = f.read()
# Make targeted edits
html = html.replace('Total spend was <b>$793.95</b>', 'Total spend was <b>$850.00</b>')
html = html.replace('0.70x', '0.75x')
# Re-convert to PDF
html_to_pdf(html, f'{WORKSPACE}/report.pdf')
result = {"title": "Updated Report", "description": "Fixed spend and ROAS figures"}
PDF() builder from data filesSave to WORKSPACE. Path is set at construction, call pdf.build() to finalize:
pdf = PDF(f'{WORKSPACE}/filename.pdf')
# ... add content ...
pdf.build()