From 93c99c04d24555ed7eba4bc8ab98fd4a14814ad2 Mon Sep 17 00:00:00 2001 From: "Bryan Gilliom (via Claude)" Date: Tue, 22 Sep 2026 21:36:58 +0000 Subject: [PATCH] Make PDF a required parallel output, generated via headless Chromium Bryan: PDF needs to happen automatically, not be a manual export -- not everyone can open the HTML comfortably. This was designed back in CW-027's Delivery Architecture discussion but never actually built into this skill; step 7 only produced HTML. Fixed: step 7 now generates the PDF immediately after the HTML, via Playwright + headless Chromium (confirmed available at /opt/pw-browsers), using page.emulate_media('print') so the PDF gets exactly the same print CSS this skill already ships -- no separate print logic to maintain, no relying on someone hitting Ctrl+P themselves. Verified end-to-end before writing this into the spec: patched a real brief with the current print CSS, rendered to PDF, confirmed correct Letter pagination (5 pages, no blank-page artifacts) and correct rendering of the modern CSS (color-mix, gradients, custom properties) that simpler non-browser PDF converters often get wrong. Step 8 (archive) updated: both HTML and PDF save to Meeting Briefs/ every time, not PDF-on-request. --- skills/internal-meeting-brief/SKILL.md | 62 ++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/skills/internal-meeting-brief/SKILL.md b/skills/internal-meeting-brief/SKILL.md index 1dc9576..a836bbb 100644 --- a/skills/internal-meeting-brief/SKILL.md +++ b/skills/internal-meeting-brief/SKILL.md @@ -53,6 +53,10 @@ Other tools this skill uses: - **Google Workspace** (MCP) — Gmail, Google Chat, Drive, Sheets - **Google Drive** — the topic's continuity folder (`_topic-state.md` + brief history + `Meeting Briefs/` + `Meeting Transcripts/`) +- **Playwright (Python, headless Chromium)** — for PDF generation from the rendered + HTML (step 7). Confirmed available in this environment at `/opt/pw-browsers`; if a + future environment lacks it, that's a real gap to flag, not something to silently + skip — HTML-only output is a regression from what this skill is supposed to do. - **MPM Technical Reference System** — a Drive-based product/technical knowledge registry (131 entity files as of 2026-09-22: brand voice, platform/software, display technologies, products, engineering, concepts, proof/evidence). Read @@ -184,15 +188,51 @@ sections only where the meeting's actual content has a structure that calls for Real, verified content over generic summary — carry forward specific facts (names, dates, exact technical decisions), not vague paraphrase. -### 7. Render -Single self-contained HTML file. Include `assets/brief-components.css` inline (don't -link out to it — the brief must survive as a standalone file). Include: sticky jump-nav, -a working light/dark toggle (`data-theme` attribute, default light), and the +### 7. Render — HTML and PDF, always both, not HTML alone +**PDF is a required parallel output, not an optional extra someone has to remember to +export.** Not everyone can open an HTML file comfortably (attachments, security +posture, unfamiliarity) — the PDF is what makes a brief actually shareable outside a +browser. + +**HTML first:** +Single self-contained file. Include `assets/brief-components.css` inline (don't link +out to it — the brief must survive as a standalone file). Include: sticky jump-nav, a +working light/dark toggle (`data-theme` attribute, default light), and the `@media print` rules from the shared CSS (forces light, hides nav/toggle, avoids awkward page breaks). Small brief-specific CSS additions beyond the shared stylesheet (e.g. a status-source badge, a role subtitle under an attendee's name) are fine — append them, don't fork the canonical rules to get the same effect. +**Then PDF, from that same HTML file, via a real browser — not a simplified +HTML-to-PDF library.** This stylesheet uses modern CSS (`color-mix()`, custom +properties, conic-gradient) that non-browser renderers often get wrong. Use headless +Chromium via Playwright, which is confirmed available in this environment +(`/opt/pw-browsers`): + +```python +from playwright.sync_api import sync_playwright +import os + +with sync_playwright() as p: + browser = p.chromium.launch() + page = browser.new_page() + page.goto('file://' + os.path.abspath('.html')) + page.emulate_media(media='print') # forces the @media print rules + page.pdf( + path='.pdf', + format='Letter', + print_background=True, # keep header gradient, card fills, etc. + margin={'top':'0.4in','bottom':'0.4in','left':'0.3in','right':'0.3in'} + ) + browser.close() +``` + +`emulate_media(media='print')` is what makes this reliable — it forces the exact CSS +this skill already ships for print (light theme, hidden nav/toggle, row-level +break-avoid), so the PDF matches what someone would get from Ctrl+P in a real browser, +without relying on them to do that themselves. Verified 2026-09-22: correct Letter +pagination, no blank-page artifacts, gradient/color-mix rendering intact. + **Footer confidentiality note — standard for this brief type.** internal-meeting-brief is, by definition, internal content. End the footer with an explicit statement of that (e.g. "Internal. Do not forward to [named external party]." when the topic has one) — @@ -200,10 +240,10 @@ validated in the Oshkosh brief, where this genuinely matters: the brief discusse reseller/customer deal in more candid terms than anyone would want forwarded to that customer. -### 8. Archive — the brief, the transcript, and the manifest update -- Save the generated HTML into the topic folder's `Meeting Briefs/` subfolder - (`YYYY-MM-DD - Brief.html`). If a PDF was also generated, save it - alongside with the matching name. +### 8. Archive — the brief (HTML + PDF), the transcript, and the manifest update +- Save both the HTML and the PDF into the topic folder's `Meeting Briefs/` subfolder, + same base filename (`YYYY-MM-DD - Brief.html` /`.pdf`). Both, every + time — not PDF-on-request. - **Save a plain-text copy of the meeting record into a `Meeting Transcripts/` subfolder** (`YYYY-MM-DD - Transcript.txt`) — a standing step, not something to be asked for. This matters beyond convenience: it makes the topic @@ -270,6 +310,12 @@ Real, valuable findings, each fixed in this revision: 6. **Meeting transcript wasn't being archived — now a standing step.** The raw transcript needed to be saved alongside the brief so future runs don't depend on the source connector still being reachable. Now explicit in step 8. +7. **PDF was manual, bolt-on, and done by hand — now a required parallel output.** + The skill only produced HTML; getting a PDF meant the person exporting it + themselves (and hitting the print-CSS bug in the process — see above). Fixed: + step 7 now generates the PDF automatically via headless Chromium (Playwright), + using the exact same print CSS this skill already ships, immediately after the + HTML — not something anyone has to remember to do. None of these were failures of judgment in the moment — they're gaps between what this file said and what turned out to actually be needed, now closed.