Cover photo

Markdown In, HTML Out

Transforming Markdown Insights into Readable HTML Artifacts

Why your specs are unread and what to do about it

A few weeks ago Thariq Shihipar from the Claude Code team gave a talk that named something I had been doing badly. The thesis fits in one sentence:

Markdown is the right format for instructing an LLM. It is the wrong format for whatever the LLM produces for you to read.

CLAUDE.md, AGENTS.md, SKILL.md are markdown for a reason. Terse. Easy to grep. Easy to keep token-cheap. The model reads them well.

But the output you ask the model for, a plan, a PRD, an architecture writeup, a status doc, is read by a human, not a model. And past a hundred lines, nobody reads markdown. It is a wall of text. There are no anchors, no visual hierarchy beyond ATX headings, no way to collapse a section, no embedded mockup, no working example, no diagram, no diff highlight. Open one of your 1k-line specs and ask honestly when you last scrolled past line 200.

The fix is to have the model emit HTML instead.

On the open-model side, nano-gpt is the cheapest way to try GLM, Qwen, Kimi, and MiniMax through one API key before committing to any of them. Pay per token, no monthly minimum. Check it out!

What HTML buys you

A single self-contained .html file rendered offline gives you:

  • visual hierarchy that scales past 100 lines

  • inline SVG diagrams that diff in git

  • collapsibles, tabs, copy buttons where they help

  • working examples instead of fenced code blocks

  • a shareable URL the moment you push to a static host

  • a real design surface that signals you cared enough to make it readable

The same artifact serves you (the author), your team (review), your stakeholders (sales, regulators, investors), and your future agent (next session context). One file, four audiences.

The pattern

project/
├── src/                   # code
├── dist/                  # generated HTML artifacts
│   ├── index.html         # landing, links, summary
│   ├── plan.html          # scope, milestones, risks
│   ├── architecture.html  # components, data flow, threats
│   ├── design.html        # tokens, type, components
│   └── status.html        # blockers, next steps
├── AGENTS.md              # token-compressed agent directives
└── html.prompt            # paste-ready agent spec for the artifact set

Markdown for the instructions. HTML for the outputs. The agent does the translation.

html.prompt

I packaged this as a paste-ready file you can drop in any project. It tells the agent what artifacts to build, how to constrain them, and what triggers regeneration.

curl -O https://gitworkshop.dev/ngmi@zaps.lol/relay.ngit.dev/dotprompt/html.prompt

claude "read html.prompt, generate dist/ artifact set for this project"
# or
opencode "read html.prompt, generate dist/ artifact set for this project"

Constraints baked in:

  • single .html per artifact, no shared assets, no build step

  • embedded CSS, no CDN, no webfont, no analytics, no telemetry

  • renders offline, deploys as static site anywhere

  • <!-- manual:keep --> blocks preserved across regens

  • gaps marked <mark>TODO</mark>, never fabricated

  • inline SVG only for diagrams, no raster, no third-party logos

  • WCAG AA contrast, semantic HTML, dark default with light toggle

Repo: https://gitworkshop.dev/ngmi@zaps.lol/relay.ngit.dev/dotprompt. MIT. One file. Fork and adapt.

Where this lands

The dist/ directory becomes the canonical spec of the project. It commits with the code. It deploys as a static site to GitHub Pages, Cloudflare, IPFS, or tangled.org. It is what you link to when someone asks for the PRD.

For me this replaced three patterns at once:

  1. Long markdown PRDs nobody reads past the TOC

  2. Stale Notion pages that drift from the code

  3. Figma mockups that exist outside the agent's context

A single html.prompt plus a dist/ is lighter than all three and lives in the repo where the code does.

A note on which agent

This works with any agent that reads files and writes files. Claude Code produces the cleanest HTML out of the box. Open models via OpenCode (GLM-4.6, Qwen3, Kimi) produce passable HTML if you point them at the embedded skeleton in html.prompt as a reference. For client-facing artifacts the quality delta matters and I route those through Claude. For internal status docs and architecture writeups any of them is fine.

The prompt is the source. Edit it. Add artifacts. Tighten privacy rules. Shift the regen triggers. It is one file.

Why this matters past the productivity angle

Specs as living HTML artifacts collapse the gap between code, documentation, and presentation. The same artifact a developer reads in dist/plan.html is the one a regulator reads at yourproject.org/plan. The same artifact the agent loads as context next session is the one a potential customer sees in a pitch. You stop maintaining three derivatives of the same information.

For anyone shipping AI-adjacent infrastructure, where compliance posture, threat model, and audit trail are part of the product, this is not a productivity hack. It is a way to make the spec the deliverable.


Credit where it belongs. Thariq Shihipar's talk is the source of the thesis. html.prompt is the operationalization I now use across every project.

If you fork it or build something on top, drop me a line.

— metaend