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 Workspace** (MCP) — Gmail, Google Chat, Drive, Sheets
|
||||||
- **Google Drive** — the topic's continuity folder (`_topic-state.md` + brief history
|
- **Google Drive** — the topic's continuity folder (`_topic-state.md` + brief history
|
||||||
+ `Meeting Briefs/` + `Meeting Transcripts/`)
|
+ `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
|
- **MPM Technical Reference System** — a Drive-based product/technical knowledge
|
||||||
registry (131 entity files as of 2026-09-22: brand voice, platform/software,
|
registry (131 entity files as of 2026-09-22: brand voice, platform/software,
|
||||||
display technologies, products, engineering, concepts, proof/evidence). Read
|
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,
|
Real, verified content over generic summary — carry forward specific facts (names,
|
||||||
dates, exact technical decisions), not vague paraphrase.
|
dates, exact technical decisions), not vague paraphrase.
|
||||||
|
|
||||||
### 7. Render
|
### 7. Render — HTML and PDF, always both, not HTML alone
|
||||||
Single self-contained HTML file. Include `assets/brief-components.css` inline (don't
|
**PDF is a required parallel output, not an optional extra someone has to remember to
|
||||||
link out to it — the brief must survive as a standalone file). Include: sticky jump-nav,
|
export.** Not everyone can open an HTML file comfortably (attachments, security
|
||||||
a working light/dark toggle (`data-theme` attribute, default light), and the
|
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
|
`@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
|
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 —
|
(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.
|
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
|
**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
|
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) —
|
(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
|
reseller/customer deal in more candid terms than anyone would want forwarded to that
|
||||||
customer.
|
customer.
|
||||||
|
|
||||||
### 8. Archive — the brief, the transcript, and the manifest update
|
### 8. Archive — the brief (HTML + PDF), the transcript, and the manifest update
|
||||||
- Save the generated HTML into the topic folder's `Meeting Briefs/` subfolder
|
- Save both the HTML and the PDF into the topic folder's `Meeting Briefs/` subfolder,
|
||||||
(`YYYY-MM-DD <Meeting> - <Mode> Brief.html`). If a PDF was also generated, save it
|
same base filename (`YYYY-MM-DD <Meeting> - <Mode> Brief.html` /`.pdf`). Both, every
|
||||||
alongside with the matching name.
|
time — not PDF-on-request.
|
||||||
- **Save a plain-text copy of the meeting record into a `Meeting Transcripts/`
|
- **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
|
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
|
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
|
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
|
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.
|
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
|
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.
|
this file said and what turned out to actually be needed, now closed.
|
||||||
|
|||||||
Reference in new issue
Block a user