| name | html-report |
|---|---|
| description | Take all documentation, discoveries, and structured knowledge gathered in the current conversation and produce a self-contained HTML report (plus its Markdown source). Use when the user says "/html-report", asks to "generate a report", "write this up as a report", "save this session as a report", or wants a shareable artifact summarizing what was figured out in the session. |
Produce a report pair — Markdown first (canonical source), then HTML rendered from it (self-contained, single file, no external assets). Files are written side-by-side into the user's configured output directory.
Check for ~/.claude/html-report-config.json
.
If it exists, readoutput_dir
from it and use that for the rest of this run. Do not prompt. - If it does NOT exist, ask the user ONCE, in one short sentence:"First run — where should reports be written? (default:
./reports/
in your current directory)"Accept their answer. Acceptable forms:
- Empty / "default" → use literal string
./reports
(resolved against cwd at write time, so reports land next to whatever project you're in) - Absolute path (e.g.
/Users/x/Documents/reports
) → use as-is ~
-prefixed (e.g.~/reports
) → expand~
to$HOME
Save the answer:
mkdir -p ~/.claude
printf '{"output_dir": "%s"}\n' "$CHOSEN" > ~/.claude/html-report-config.json
Confirm in one sentence: "Saved. Reports will go to
<path>
. Re-run to change:rm ~/.claude/html-report-config.json
." - Empty / "default" → use literal string
Then proceed to Step 1. Create the resolved output dir with mkdir -p
if it doesn't exist.
Base: <YYYY-MM-DD>-<kebab-topic>
where:
- Date is today (system date).
<kebab-topic>
comes from$ARGUMENTS
if provided, else inferred from the dominant topic of the session in 1–4 kebab words (e.g.auth-migration-research
,db-migration-tutorial
,vendor-eval
).
If the resulting <base>.md
already exists in the output dir, append -2
, -3
, etc. until unique.
Final paths:
MD="$OUTPUT_DIR/<base>.md"
HTML="$OUTPUT_DIR/<base>.html"
Write $MD
. Required structure:
Frontmatter:
---
title: <Human-readable title>
date: <YYYY-MM-DD today>
type: report
tags: [report, <other-relevant-tags>]
---
Body: all session content in rich Markdown. Use:
- Headings (
#
,##
,###
) —##
defines top-level sections used by Step 3. - Tables for schemas, configs, comparisons.
- Fenced code blocks with language tags ( ```` go`
,```` python`
,```` bash`
). - Callouts using GitHub/Obsidian syntax:
> [!note]
,> [!warning]
,> [!tip]
,> [!info]
,> [!danger]
,> [!success]
. - Task lists:
- [ ]
/- [x]
for open questions or follow-ups. - Mermaid diagrams in ```` mermaid`
fences. - Inline emphasis (
**bold**
,*italic*
,code
).
No raw HTML inside the Markdown unless absolutely needed.
Why this is the way it is:the most common failure mode is the agent stalling on a single hugeWrite
. Writing the full HTML at once exceeds the output token cap (~20K tokens) and hangs. Fix: write a small skeleton once, then fill sections incrementally with ONEEdit
per turn.If you catch yourself "designing" the layout, picking colors from a menu, or batching Edits "for speed" — STOP. That's the stuck-state path.
State your two choices in one plain sentence and move on. Examples:
- "Using teal palette, single-column layout."
- "Using amber palette, sidebar layout (16 sections)."
Palette (pick exactly one keyword): teal
(research/data) · amber
(RFC/decision) · red-amber
(audit) · green
(tutorial) · neutral
(reference).
Layout (pick exactly one keyword):
single-column
— default. Max-width 900px, no sidebar, no scroll-spy.sidebar
— ONLY if section countN ≥ 12
. Static sidebar TOC, no scroll-spy JS.
Do not invent additional palettes, layouts, or "decorations" (back-to-top buttons, scroll-spy, SVG charts, etc.). Content is the product, not styling.
N=$(grep -c '^## ' "$MD")
echo "N=$N"
If N > 25
, tell the user once: "Report has $N sections — HTML fill will take ~$N turns. Continuing." Then proceed without waiting.
The skeleton must be a complete valid HTML file with these — and ONLY these — pieces:
<!DOCTYPE html>
,<html>
,<head>
with one inline<style>
block. CSS budget: ~2 KB. Include only:- Body font, base typography, max-width container (or sidebar grid if
layout=sidebar
). h1
/h2
/h3
styling.table
(striped + padding),pre
/code
styling,pre.mermaid-source
styling.- 5 callout classes —
.callout-note
(blue),.callout-tip
(green),.callout-warning
(amber),.callout-danger
(red),.callout-info
(purple). Each: colored left border + tinted background. .tasks li::before
for task-list checkboxes.
- Body font, base typography, max-width container (or sidebar grid if
- Hero header: title (from frontmatter) and date as plain text.
- Main container. Exactly N placeholder lines, in order:
<!-- SECTION-0 --><!-- /SECTION-0 -->
<!-- SECTION-1 --><!-- /SECTION-1 -->
...
- Closing tags.
FORBIDDEN in the skeleton: <script>
tags of any kind, IntersectionObserver / scroll-spy code, back-to-top buttons, sidebar TOC pre-populated with section titles, fancy responsive grids, @media
queries beyond a single max-width fallback, any external CSS/JS link.
If your skeleton draft exceeds 8 KB, delete CSS rules until it fits.
HARD RULES — do not violate:
ONE Sequential is the whole point. If you're tempted to batch 2-3 Edits "to save time," that IS the stuck state — stop and send one.Edit
per response. Never two. Never parallel.Cap per Edit If a section's rendered HTML would exceed 3 KB, render only the first H3 subsection and append an inner placeholdernew_string
: 3 KB.<!-- SECTION-i.1 --><!-- /SECTION-i.1 -->
to fill next turn.After every Edit, run the checkpoint(3.4.1) BEFORE doing anything else. Do not chain into the next section in the same turn.** Keep text output to ≤ 1 short sentence per turn**("Filled section 3."). No narration, no re-explaining the plan, no progress tables.
grep -c '<!-- SECTION-' "$HTML"
The number must decrement by exactly 1 after each successful Edit. If it does not, stop and inspect — do NOT keep sending Edits.
For each i
from 0
to N-1
, in its OWN turn:
- Locate the
i
-th##
heading in the markdown; capture everything until the next##
or EOF. - Render to HTML following 3.5 (compact reference).
- ONE
Edit
:old_string
:<!-- SECTION-i --><!-- /SECTION-i -->
(literal, substitutei
)new_string
:<section id="sec-i"><h2>Heading text</h2>…rendered…</section>
(≤ 3 KB)
- Run 3.4.1 checkpoint.
- End the turn.
Tables→<table>
(CSS already handles striping + padding).Code blocks→<pre><code class="lang-X">…</code></pre>
.MUST escape<
>
&
to<
>
&
. NO syntax-highlighting library, NO regex tokenizer — CSS-only styling.Callouts> [!type]
→<div class="callout callout-type">…</div>
. Map: note→note, tip→tip, info→info, warning→warning, danger→danger, success→tip.Mermaid```` mermaid`
→<pre class="mermaid-source">📊 Mermaid — paste into mermaid.live to render\n\n<ESCAPED source>\n</pre>
. Never try to render visually.Task lists- [ ]
/- [x]
→<ul class="tasks"><li class="task-open">…</li><li class="task-done">…</li></ul>
.- No raw Markdown (
**bold**
,###
, etc.) in the HTML output — render everything.
Don't restart. Run:
grep -nE '<!-- SECTION-[0-9]+ -->' "$HTML"
Resume from the lowest remaining i
using 3.4.2. The skeleton is already correct.
remaining=$(grep -c '<!-- SECTION-' "$HTML")
size=$(wc -c < "$HTML")
echo "remaining=$remaining size=$size"
remaining
MUST be 0
. size
should land in 20 000–200 000 bytes. If non-zero, return to 3.4.2 — do NOT rewrite the skeleton.
Output to the user (concise):
- Markdown path
- HTML path
- One-line
open <html-path>
command they can paste
Do not include any other commentary unless the user asked questions.