SKILL NOTE · 2026-05-09

The unreasonable effectiveness of HTML, and the skill that tries not to ruin it

On Thariq's case for HTML-as-artifact, and how composing-html threads the needle he warned about.

Thariq from the Claude Code team published “The Unreasonable Effectiveness of HTML” earlier today. The argument, compressed:

It's a good post. Read it. The piece you're reading now is about a worry Thariq tucks near the end:

THARIQ, NEAR THE END

I'm a little bit afraid that people will read this article and turn it into a /html skill or something. While there might be some value in that, I want to emphasize that you don't need to do much to get Claude to do this. You can just ask it to “make a HTML file” or “make a HTML artifact”.

This page was made with such a skill, composing-html. So it owes Thariq a defense: why does this exist, and why isn't it the thing he was worried about?

The thing he was worried about


The bad version of this skill is easy to picture. It would have 30 templates: weekly_report, pr_review, incident, design_system, flowchart, deck, kanban, concept_explainer, on and on. Each one a JSON dialect — you'd hand it {title, sections: [{heading, body, ...}]} and it would emit HTML.

That skill solves nothing HTML didn't already solve. Worse: it adds a translation step. Now the model has to first know HTML and the template's slot grammar. The slot grammar is the bottleneck because the slots will never match what you actually want this time. Every artifact becomes a contortion act — squeeze the content into a shape someone else picked, or break out of the template entirely and lose the consistency that was the only reason to use it.

This is the “worse Jinja” failure mode. Jinja already exists. It's better at being Jinja.

What composing-html actually is


WHAT IT GIVES

Page chrome. Doctype, head, meta tags, inlined CSS reset, design tokens, type stacks, layout primitives, components, base.js for tabs / drag / live-binding, masthead, colophon. All of it loaded into every artifact.

You don't write <style>. You don't pick fonts. You don't re-derive what a card or a badge or an eyebrow should look like.

WHAT IT DOESN'T DO

Tell you what to put in it. The default workflow, freeform, has exactly one slot: body_html. Whatever HTML you'd write anyway, write it there — using the inventory the chrome already loaded.

That's the thing. The skill is a typography baseline, not a templating engine.

So when Thariq says “you can just ask it to make an HTML file,” freeform agrees. The only thing the skill insists on is that the resulting file look like the other files — same fonts, same color tokens, same heading rhythm, same dark-mode handling, same escape-safe rendering. The thing that's hard to write from scratch every time isn't the HTML; it's the page chrome. The skill gives that back.

The inventory, on display


Everything below is loaded automatically into every artifact. You reference these in body_html by class name. No <style> tags, no token redeclaration.

COLOR TOKENS
  • --ivory, --paper, --slate
  • --clay, --clay-d (brand)
  • --oat, --olive, --rust, --moss
  • --g100--g700
  • Semantic: --ok, --warn, --err, --info
TYPE & GEOMETRY
  • --serif / --sans / --mono
  • --radius-sm, --radius, --radius-lg
  • --border, --border-soft
  • --shadow-card, --shadow-pop
COMPONENTS
  • .eyebrow — clay-led label
  • .badgeok warn err
  • .kbd⌘K
  • .bullets — clay-dotted lists
  • Tabs, drag-to-reorder, live bindings

Templates exist, but earn their slot


The skill ships 21 templates — the bad-skill catalog from earlier. The reframe is they're shortcuts, not the front door. They earn their keep only when the same artifact shape actually repeats:

  1. You're producing the same artifact shape repeatedly — not just twice ever.
  2. The repeat structure is tight enough that a fixed slot map captures it without contortions.
  3. Cross-artifact consistency matters more than per-artifact flexibility.

Status reports week after week qualify. PR reviews across many PRs qualify. Most things you'd ask Claude for once do not. Hence: freeform is the default, and the templates section sits at the back of the SKILL.md with an explicit gate.

This wasn't the skill's original shape. The earlier version led with templates — exactly the skill Thariq warned about — and it took an attempted 22nd template to surface the underlying mistake. Removing the lead-with-templates framing was the most useful change made to the skill.

The three-line workflow


python scripts/build.py describe freeform   # see the body_html slot
# write spec.json with body_html: "<your HTML using the inventory above>"
python scripts/build.py build freeform --spec spec.json --out artifact.html

This page was produced exactly that way. The spec it came from is shorter than the page is.

Where this leaves Thariq's worry


Thariq's caution is correct as written: most /html skills will be the bad version. They'll wrap HTML in JSON, force content through fixed slot maps, and leave the model fighting the harness. People who reach for them will lose the expressiveness that made HTML worth using in the first place.

THE NARROW DEFENSE

A skill is worth keeping if and only if it gives Claude something Claude can't cheaply re-derive on every artifact. Page chrome qualifies. Templates for genuinely-recurring shapes qualify. Templates for one-shots don't — that's the trap.

composing-html exists in the narrow zone where a skill is doing real work: providing typography and layout primitives so Claude can do exactly what Thariq says — just make an HTML file — without re-picking fonts and colors every time.

The same shape, one layer up


This pattern shows up elsewhere. Brian Suh's recent post on agent control flow makes the same observation about agents: if you've resorted to MANDATORY or DO NOT SKIP, you've hit the ceiling of prompting. The dual is reach-for-a-structural-gate, not stronger prose imperatives.

composing-html had the dual at the artifact-format layer: reach for more templates instead of better chrome. In all three cases — Thariq, Suh, this skill — the trap is the same. Adding a textual or declarative layer where the underlying primitive already does the work. The honest formulation is structural vs textual. Pick the layer that enforces, not the layer that asks.

META

This page is a test artifact — written to validate that composing-html can carry its own rationale without help. If anything on it looks wrong, the skill (or the rationale) is the bug, not the post.

Composed with composing-html