Plan HTML Review App Design
Defines a manual workflow that converts canonical markdown specs into clean HTML review pages via an agentic LLM CLI, served by a dedicated Astro app at apps/plans. The generated HTML is a fast-comprehension layer over the source markdown — not a second source of truth.
A manual TypeScript script orchestrates a pluggable agentic CLI (claude, codex, or gemini) to convert markdown specs into light-mode HTML review pages, stored in an Astro content collection and deployed to Cloudflare Pages. The HTML is a fast-comprehension layer over the source markdown — not a second source of truth.
Key Decisions
Generation strategy
LLM-driven via agentic CLI; agent writes JSON + HTML files directly to a temp dir.
Matches how agentic CLIs are designed. Post-hoc validation against Zod is clearer than parsing structured stdout. Delegating visual restructuring to the LLM allows rich, context-aware output that no deterministic transformer could produce. See ADR-0026.
Rejected: stdout JSON parsing (fragile), markdown-to-HTML deterministic transform (loses the enrichment benefit).
Output shape
Metadata JSON + sibling HTML body fragment. Astro shell wraps the fragment with chrome.
Keeps git diffs readable. Lets reviewers open the raw HTML for spot-checking. The layout (hero, TOC, footer) is shared across all specs via a single Astro layout component.
Rejected: single JSON with embedded HTML string (unreadable diffs), MDX (too much tooling for generated content).
Component vocabulary
Closed catalog (COMPONENT_CATALOG.md). body_html may only use declared classes. Undeclared patterns → suggestion entry in JSON, not a lint pass.
Prevents per-spec bespoke CSS from accumulating. Suggestion loop ensures catalog evolves based on real content needs rather than speculation. See ADR-0027.
Rejected: open CSS (drifts uncontrollably), AI-generated inline styles (unscoped, breaks global layout).
Re-run policy
SHA-256 hash skip by default. --force regenerates unconditionally. Atomic writes via temp dir + rename().
Avoids burning tokens on unchanged specs. Atomic writes ensure a failed validation never leaves broken files in the content collection.
Rejected: timestamp-based skip (unreliable), always-regenerate (wasteful).
Generation Pipeline
Non-Goals
- Do not move canonical spec content out of
docs/superpowers/specs. - Do not auto-convert specs during
astro dev/astro build. - Do not use MDX as the generated review format.
- Do not build a CMS or editing interface.
- Do not require AI-generated images for every spec.
- Do not produce HTML deterministically — enrichment is delegated to the LLM (ADR-0026).
Astro App Shape
- Content storage
- Astro Content Collection at
src/content/specs/. Each spec →<slug>.json+<slug>.html. Schema shared with generator via Zod. - Archive page (
/) - Specs newest-first, status badges, tag filters, client-side MiniSearch search bar.
- Detail page (
/specs/<slug>) - Astro layout provides hero, sticky TOC (extracted from
<h2>/<h3>), footer. Body is<Fragment set:html={bodyHtml} />. - Search engine
- MiniSearch over
public/search-index.json. Field-weighted: title ×5, key_decisions ×3, tags ×3, summary ×2, search_text ×1. - Index rebuild triggers
- End of every generate run +
astro:build:doneintegration hook (samebuildSearchIndex()function). - CSS
- Independent of
apps/platform. Own design tokens, Tailwind v4. Light-mode only in v1. No dark mode. - Deployment
- Cloudflare Pages ·
super-app-plans. Static build, no SSR adapter, no auth.noindex+/robots.txt Disallow.
Script & CLI Flags
Path: frontend/astro/apps/plans/scripts/generate-plan-html.ts (TypeScript via tsx)
| Flag | Default | Effect |
|---|---|---|
--with=<cli> | claude | Pluggable CLI: claude | codex | gemini. Env fallback: PLAN_HTML_CLI. |
--model=<id> | claude-sonnet-4-6 | Claude model ID. Only applies to --with=claude (direct Anthropic API). |
--all | — | Iterate all docs/superpowers/specs/*.md. |
--force | false | Regenerate even if source hash matches. |
--diagrams=<mode> | mermaid | mermaid (client-side) | image (requires image-capable CLI). |
--with-images | false | Allow illustrative image generation (requires image-capable CLI). |
--variant=<name> | — | Save as <slug>.v.<name>.json/html. Canonical slot unchanged. Use to compare CLI outputs. |
Variant System
Variants let you keep multiple CLI outputs for the same spec side-by-side without collision.
- Canonical slot
<slug>.json+<slug>.html— drives the archive, search index, and detail page hero.- Variant slot
<slug>.v.<name>.json/html— shown in collapsible<details>sections below the canonical on the detail page.- Archive / search
- Canonical only. Variants are excluded from the index.
- Usage
pnpm generate <path> --with=codex --variant=codexto generate a codex variant alongside the claude canonical.
Output Schema
One Zod schema (src/lib/spec-schema.ts) is shared by the generator script, the Astro content collection, and the prompt's auto-rendered TypeScript type.
| Field | Who sets it | Notes |
|---|---|---|
title | LLM | Spec H1 or inferred |
status | LLM | draft | approved | superseded | implemented |
date | LLM | YYYY-MM-DD from spec or filename prefix |
summary | LLM | 1–3 sentences, plain text. Archive card + meta description. |
tags | LLM | 1–8 lowercase kebab-case tags |
key_decisions | LLM | 1–8 sentence-length locked decisions |
search_text | LLM | ≥50 chars plain text, prioritises headings/decisions/definitions |
suggested_components | LLM | Patterns the catalog doesn't cover. Default []. |
related_adrs / new_adrs | LLM | ADR numbers referenced or introduced by the spec |
slug | Script | Source filename without .md |
source_path | Script | Repo-relative path to markdown |
source_hash | Script | SHA-256 of source markdown bytes (used for skip logic) |
generated_at | Script | ISO timestamp of this run |
generated_by | Script | Model ID (e.g. claude-sonnet-4-6) or CLI name |
diagram_format | Script | mermaid | image — recorded for re-run policy |
Content Preservation Rule
- Long prose may be compressed when meaning is preserved.
- Detailed information may move lower or into
<details>blocks, but must not disappear. - Every generated page links back to the source markdown via a
main-branch GitHub URL. - The source markdown remains the place to audit exact wording.
Diagrams & Images
| Type | Default | Opt-in flag | Requires | Storage |
|---|---|---|---|---|
| Diagrams — Mermaid | ✓ (default) | — | Any CLI | Inline <pre class="mermaid">, rendered client-side |
| Diagrams — image | — | --diagrams=image | Image-capable CLI (codex) | public/spec-images/<slug>/diagram-<n>.png |
| Illustrative images | — | --with-images | Image-capable CLI (codex) | public/spec-images/<slug>/illustration-<n>.png |
Component Catalog (v1 — 20+ classes)
Defined in apps/plans/COMPONENT_CATALOG.md. Enforced by a post-generation lint step in the script. The suggestion loop grows the catalog based on real content needs.
Layout & Structure
spec-section— top-level TOC-anchored sectionspec-lede— executive summary paragraphspec-meta-grid— facet tiles near top of spec
Decisions & Callouts
spec-callout— with modifiers:--decision,--rationale,--risk,--warning,--open-question,--constraintspec-decision-card— structured decision with chosen + reason + alternatives
Comparison & Data
spec-comparison-grid— side-by-side option comparisonspec-table— tabular data with header emphasisspec-kv— key-value definition listspec-rule-list— heuristic/metric rows with accent stripesspec-category-grid— descriptive card grid for roles/modules
Flow & Timeline
spec-flow— linear process steps, grouped in one containerspec-timeline— phased rollout over timespec-diagram— figure wrapper for Mermaid or image diagramsspec-mockup— UI mockup escape hatch (custom CSS allowed inside)
Prompt Template
- Path
frontend/astro/apps/plans/prompts/generate-plan.md- Format
- Plain markdown with
{{VAR}}substitution. One template for all CLIs. - Key variables
SPEC_PATH,OUTPUT_JSON_PATH,OUTPUT_HTML_PATH,SOURCE_MARKDOWN,COMPONENT_CATALOG,JSON_SCHEMA,DIAGRAM_MODE,IMAGES_ENABLED- JSON_SCHEMA
- Auto-rendered from Zod via
renderAgentSchemaAsTypeScript()— schema and prompt stay in sync automatically. - Evolution
- Material changes are commits with rationale. After any change, regenerate ≥1 representative spec with
--forceand PR-review the diff before claiming it works.
Repo-local Skill
- Path
.agents/skills/plan-html/SKILL.md, registered in.claude/skills.yaml- Trigger
- "generate plan HTML", "render this spec", "regenerate spec pages", "publish plan"
- Behavior
- Prompt-then-run: ask before invoking the script. Default command:
pnpm --filter @astro/plans generate <spec-path>. Use--allfor multiple specs. Use--all --forceafter prompt/catalog/CSS changes. - Post-run
- Surface
suggested_componentsto the human. Spot-check the generated page at desktop + mobile widths.
Testing & Verification
- Script run against the full
docs/superpowers/specscorpus — Zod validation passes for every<slug>.json. - Generated HTML inspected for: title, summary, source link, navigation, all important sections (per content preservation rule).
- Search index contains every canonical spec; client search finds at least one result per spec via title and via a key decision.
pnpm --filter @astro/plans buildsucceeds;astro:build:donehook regeneratessearch-index.json.- Browser review at desktop and mobile widths.
--with=codex --diagrams=imageproduces a diagram image with non-empty alt text and an<img>reference in the HTML.- Variant system:
--variant=codexproduces a.v.codex.json/htmlpair; detail page shows it in a collapsible section below canonical.
Locked Implementation Decisions
| # | Decision | Resolution | ADR |
|---|---|---|---|
| 1 | Generation strategy | LLM-driven via agentic CLI; agent writes files directly | ADR-0026 |
| 2 | Output shape | Metadata JSON + sibling HTML fragment; Astro shell wraps it | ADR-0026 |
| 3 | CLI selection | Pluggable via --with= flag, default claude | — |
| 4 | Storage location | Astro Content Collection at src/content/specs/ | — |
| 5 | Re-run policy | SHA-256 hash skip + --force + atomic writes | — |
| 6 | Schema authority | Single Zod schema shared by script + collection + prompt | — |
| 7 | Search engine | MiniSearch over custom search-index.json | — |
| 8 | Deployment | Cloudflare Pages, static, no auth, noindex | — |
| 9 | Source link | Main-branch GitHub URL, no commit pinning | — |
| 10 | Component vocabulary | Closed catalog + suggestion loop; manual adoption | ADR-0027 |
| 11 | Diagrams default | Mermaid; image opt-in requires codex; alt text required | — |
| 12 | Prompt template | Single markdown file, {{VAR}} substitution, all CLIs | — |
| 13 | Schema in prompt | Auto-rendered as TypeScript type from Zod | — |
| 14 | Search index rebuild | Script end-of-run + astro:build:done safety net | — |
| 15 | Skill default behavior | Prompt-then-run before invoking script | — |