Implementation Plan

Add PDF Export to HTML Plans

completed
2026-06-06 agentics feature

Add a "Save as PDF" button to every HTML plan so users can download a clean, print-optimized PDF of any plan with a single click -- no external dependencies, no server-side rendering, pure browser-native window.print() with PDF-tuned @media print styles.

File add-pdf-export-to-html-plans.html
Path docs/plans/add-pdf-export-to-html-plans.html
Acceptance criteria 5 / 5 done

Context

HTML plans are self-contained documents that users open in a browser. The existing @media print rules already hide the sidebar, progress bar, and interactive controls, but there is no visible affordance inviting the user to print or save. Users who want a PDF must know to use Ctrl+P / Cmd+P and select "Save as PDF" in the print dialog.

Adding a dedicated button makes the export discoverable, ensures the print stylesheet is invoked correctly, and sets the document title (which browsers use as the default PDF filename) to a clean slug derived from the plan title.

The approach is zero-dependency: window.print() triggers the browser's native print dialog, which on every modern browser (Chrome, Edge, Firefox, Safari) offers a "Save as PDF" destination. No third-party libraries, no server round-trips, no CORS headaches.

Steps

1
done Add a download icon (ic-arrow-down-tray) to the SVG symbol sprite
The button needs a recognizable download icon; adding it to the existing sprite keeps the file self-contained with no external asset requests.
Verify
Search for id="ic-arrow-down-tray" in the HTML; confirm it renders at 1rem in the button.
2
done Add the "Save as PDF" button in the header next to the status badge
Placing it in the header makes it immediately visible without scrolling; co-locating with the status badge keeps the action bar compact.
Verify
Open the plan in a browser; confirm the button appears to the left of the status badge with a download icon and the label "Save as PDF".
3
done Style the button with .save-pdf-btn and hide it in @media print
The button must be visible on screen but absent from the printed/PDF output; a dedicated class makes the print rule explicit and prevents it from appearing in the exported document.
Verify
Open DevTools, toggle print media emulation; confirm the button disappears. Confirm it has hover/focus/active states on screen.
4
done Implement the savePDF() function using window.print()
The browser's native print dialog is the most reliable cross-browser path to PDF; wrapping it in a named function lets the onclick handler remain a clean one-liner.
Verify
Click the button; confirm the print dialog opens. In Chrome/Edge, select "Save as PDF" destination; confirm the downloaded PDF looks correct with no sidebar, no buttons, and clean page breaks.
5
done Enhance @media print styles for PDF-quality output
The existing print rules are minimal; PDF output needs explicit @page margins, break-inside: avoid on cards, preserved background colors for status badges and chips, and suppressed link URL suffixes for internal anchors.
Verify
Generate a PDF from a plan with 6+ steps; confirm no step card is split across pages, the objective card retains its blue accent, and the status badge color is preserved.
6
done Update the markdown-to-html skill template and assets to include the button and styles
The plan-to-html alias delegates immediately to markdown-to-html, which is the active HTML generator with the template, assets, and spec. Updating the alias alone would leave the actual generator unchanged and future plans would still lack the button.
Verify
Run /markdown-to-html on any markdown plan; confirm the generated HTML includes the .save-pdf-btn button and the savePDF() function. Also verify kit/plugins/plan-interview/skills/markdown-to-html/reference/html-spec.md documents the button.

Acceptance Criteria

Verification

Open this plan file in Chrome. Click the "Save as PDF" button. In the print dialog, select "Save as PDF" as the destination and click Save. Open the resulting PDF and confirm:

  1. The sidebar and all buttons are absent.
  2. The objective card has a blue left border.
  3. Step cards are not split across pages.
  4. The status badge retains its gray background.
  5. The document title in the PDF metadata matches the plan title.

Repeat in Firefox and Safari. Firefox uses its own print engine — confirm the layout is acceptable (minor differences in page breaks are tolerable).

Next Steps

Backfill the Save as PDF button into all existing HTML plans

Paste this prompt into Claude to execute this follow-up:

Find all HTML plan files in docs/plans/ that do not contain a .save-pdf-btn button. For each file, add the save-pdf-btn markup in the .plan-header-top div (before the status badge), add the .save-pdf-btn CSS rules, add the ic-arrow-down-tray SVG symbol, add the savePDF() JavaScript function, and update the @media print block to hide the button. Do not change any plan content. Commit with message "feat(docs/plans): backfill Save as PDF button into existing HTML plans".
Add a keyboard shortcut hint tooltip on hover

Paste this prompt into Claude to execute this follow-up:

Add a title attribute to the .save-pdf-btn button with the text "Save as PDF (Ctrl+P / Cmd+P)" so users learn the keyboard shortcut. Also add a CSS tooltip on hover that shows the same hint below the button. Keep it simple — no JS tooltip library, just a ::after pseudo-element positioned absolutely.
Wish List
Client-side PDF generation without print dialog Wish List

Speculative / blue-sky idea -- not on the critical path. Paste into Claude when ready to explore:

Investigate using html2pdf.js (a wrapper around html2canvas + jsPDF) to generate a PDF directly in the browser without opening the print dialog. The button should download the PDF file immediately. Evaluate: (1) bundle size impact if loaded via CDN script tag, (2) rendering fidelity compared to window.print(), (3) whether SVG icons render correctly, (4) cross-browser support. Deliver a written recommendation with pros/cons — do not implement yet.
Unresolved Questions
  • Should the button label say "Save as PDF" or "Download PDF"?
    The Save as PDF button uses window.print() which opens the browser's print dialog — the user must still select "Save as PDF" as the destination. "Download PDF" implies an instant download. Evaluate which label sets the correct expectation and recommend one. Consider: (1) user familiarity with the print-to-PDF flow, (2) whether "Save" or "Download" is more accurate for a print dialog trigger, (3) what Google Docs and Notion use for similar buttons.