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.
This commit is contained in:
1 parent
2209a19eb7
commit
93c99c04d2
1 file changed
+54
-8
@@ -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('<brief>.html'))
|
||||
page.emulate_media(media='print') # forces the @media print rules
|
||||
page.pdf(
|
||||
path='<brief>.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 <Meeting> - <Mode> 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 <Meeting> - <Mode> 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 <source name> - 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.
|
||||
|
||||
Reference in new issue
Block a user