diff --git a/CLAUDE.md b/CLAUDE.md index 74f31a7..568b205 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -514,6 +514,43 @@ mirror its content into `src/patterns.ts`'s `PATTERNS` array (with a No DB migration, no schema change, no new endpoint — the existing `/.well-known/patterns/:filename` route picks it up automatically. +**Prescriptive patterns (structure fixed, not a menu).** Most patterns +offer 3–5 layout directions and let the agent pick. `session-explainer` +does not: it mandates one structure, because these pages are only worth +comparing to each other if they share a shape. Two mechanics support that: + +- **A reference skeleton** at `patterns/.template.html`, mirrored + into `src/patterns.ts` as a second string constant and referenced from + the pattern's front matter (`template: .template.html`). Served + by the same route via `getPatternAsset()`, which returns body + + content-type so `.md` goes out as `text/markdown` and `.template.html` + as `text/html`. `buildPatternIndex()` adds `template_url` for any + pattern that declares one, so agents discover it from the index. + The template's CSS is split by a marked comment: a **BRAND TOKENS** + block the agent adapts, and a **STRUCTURE** block it must not touch. +- **`brand_scope: colors-only`** alongside `brand_sensing: true` — adapt + palette and type, leave the structure alone. A prescriptive pattern and + full brand sensing contradict each other; pick one per pattern. + **Why a second key rather than `brand_sensing: colors-only`:** the + CLI's validator (`src/patterns/schema.ts` in the CLI repo) requires + `brand_sensing` to be a boolean and throws otherwise. Since `init` + loops every pattern inside one `try`, a throw drops the whole run into + the offline fallback — an older CLI would silently install 3 patterns + and report `offline: true`. Unknown front-matter keys are ignored, so + `brand_scope` and `template` are forward-compatible with published + CLI versions. Keep new pattern metadata additive for that reason. + +Enforcement tops out there on purpose. The server does **not** validate +published HTML (that would break "HTML uploads exactly as posted"), and +`./.htmlbin/patterns/` still overrides the official catalog. The pattern +carries a conformance checklist for the agent to self-check instead. + +The CLI's offline bundle globs `patterns/*.md` only, so templates are +**not** vendored — an offline `patterns init` gets the pattern's prose +fallback ("build the same structure from the requirements below"). If +that becomes a real gap, teaching `scripts/build-bundled-patterns.mjs` +and the CLI's install path about a second file per pattern is the fix. + **The CLI's `patterns` subcommand** ([utsengar/htmlbin-cli](https://github.com/utsengar/htmlbin-cli)) offers `list / init / add` for managing local installs. The skill's @@ -822,6 +859,8 @@ patterns/ ─ human-browsable canonical pattern markdown — source of pr-explainer.md ─ "explain this PR / summarize this diff" summary-roundup.md ─ discussion summaries, weekly status, incident timelines plan-spec-explainer.md─ plan.md / spec.md publishing + session-explainer.md ─ agent session writeups — problem, approach, dead ends + session-explainer.template.html ─ required skeleton for the above (prescriptive) # Mirrored byte-for-byte into src/patterns.ts (wrangler .md-import gotcha). .github/workflows/ diff --git a/patterns/session-explainer.md b/patterns/session-explainer.md new file mode 100644 index 0000000..21df999 --- /dev/null +++ b/patterns/session-explainer.md @@ -0,0 +1,118 @@ +--- +name: session-explainer +description: Explain an agent session — the problem, the approach, the dead ends, and what the thinking actually was. +triggers: + - publish this session + - share this trace + - share my claude code session + - make a page from this transcript + - publish my agent session + - show my thinking on this +brand_sensing: true +brand_scope: colors-only +template: session-explainer.template.html +--- + +# Session explainer + +## When to use + +When the source is an agent session — a transcript of work with a coding agent. The drop's job is to explain **how the author thought about a problem**, not to replay the conversation. The reader wants the reasoning; the transcript is raw material, not the deliverable. + +**When not to use.** If the audience needs unedited proof that the work happened — a grant or accelerator application, an interview artifact, an audit — this pattern is the wrong tool and so is a drop. Those readers want the original file precisely because nobody curated it, and curation is this pattern's whole point. Say so and hand them the raw transcript instead. + +Sessions worth publishing also tend to be the long ones, and a long transcript does not fit in a drop. Distilling isn't a stylistic preference here; it's the only thing that fits. + +## Start from the template, don't invent a layout + +This pattern is **prescriptive**. Unlike the other official patterns it does not offer layout choices, because the structure is what makes these pages comparable to each other. + + curl -s https://htmlbin.dev/.well-known/patterns/session-explainer.template.html + +Fill every `SLOT_*` placeholder and each `` region. The template's CSS is split by a marked line: adapt the **BRAND TOKENS** block, treat everything under **STRUCTURE** as fixed. + +If you cannot fetch the template, build the same structure from the requirements below. Do not substitute a different one. + +## Required structure + +All five are mandatory. A page missing any of them is not this pattern. + +1. **A sticky left rail** (`.rail`) holding the session's numbers and context. It stays on screen while the content column scrolls, so the reader keeps the session's identity while reading any one part. +2. **Two tabs** — `Highlights` (`#p1`, default) and `Dead ends` (`#p2`). Driven by `:target` and `:has()`, never JavaScript. +3. **A compressed timeline** in Highlights. One line per step. This is the index to the whole session. +4. **One card per dead end** in the second tab, `id="dead-N"`. +5. **Deep links from timeline to cards.** A timeline row that has a card is an `` whose gutter reads `dead-N →`. Clicking it switches tab, scrolls to the card, and rings it. Rows without a card stay a `
` and get a plain gutter label. + +## Numbers must be measured + +Every value in the rail comes from the transcript. Count it; never estimate, never round for effect. **Omit a tile rather than guess** — a wrong number is worse than a missing one. Mark at most one tile `.hot`, and only when it carries the page's central constraint. + +Required in the context block: `agent`, `model`. Add `window`, `repo`, `outcome` when known. + +## Hard limits + +| Thing | Limit | +|---|---| +| Insights | 2–4 items, **150 words total** | +| Timeline rows | 8–16, one line each | +| Dead-end cards | 2–6 | +| Lede | 2 sentences | +| `