# Markdown → HTML — Domain Guide
This file provides domain-specific guidance for skills in `markdown-html/`.
## Purpose
The markdown-html domain converts long markdown files (the actual artifacts produced inside a Claude project — specs, reports, RFCs, PR writeups, slide outlines) into world-class, single-file, lightly-interactive HTML. Inspired by Thariq Shihipar's argument (Medium, 2026): markdown collapses past ~100 lines because it lacks visual machinery for density and lateral navigation; HTML restores both.
It is **not** an interactive prompt-tuning playground (`/playground` plugin owns that lane), **not** a landing-page generator (`marketing/landing/`), **not** a session-handoff brief generator (`engineering/handoff/` + `productivity/handoff/`), and **not** a static-site generator (single-file artifacts, not site indices).
## Skills (v2.10.3 — domain complete)
| Skill | Purpose | `context: fork`? | Status |
|---|---|---|---|
| `markdown-html-orchestrator` | Domain orchestrator — classifies doctype, gates on threshold + onboarding, routes to converter | YES | ✓ live |
| `design-system` | One-time onboarding wizard + WCAG-AA-validated brand palette (12 CSS custom properties) + shared config | NO | ✓ live |
| `md-document` | Long-form converter: sticky TOC, collapsibles, search, code-copy, scrollspy | NO | ✓ live |
| `md-review` | Code-review converter: 2-col diff + severity-tagged margin annotations + jump-nav | NO | ✓ live |
| `md-slides` | Slide-deck converter: arrow-key nav + presenter mode + print-to-PDF | NO | ✓ live |
All three converters are shipped. Routing always targets the converter skill's scripts — never hand-render HTML inline.
## Hard rules (domain-specific)
1. **Refuses input < 100 lines.** Markdown still wins below the threshold (Shihipar). Every converter (and the orchestrator) prints the line count and a "keep as markdown" recommendation.
2. **Refuses without design-system onboarding.** The orchestrator's `route_explainer.py` checks `config_loader.setup_completed()`. If false, refuse and surface onboarding (`python3 markdown-html/skills/design-system/scripts/onboard.py`).
3. **WCAG AA enforced.** `brand_palette_validator.py` rejects color combinations whose body-text contrast falls below 4.5:1 on bg. Link contrast is iteratively walked to 4.5:1 by adjusting luminance.
4. **Single-file HTML output.** All CSS and JS inline. The only permitted external CDN entries are Google Fonts CSS and Prism.js. No bundler, no build step, no JS framework runtimes (vanilla JS + IntersectionObserver only).
5. **Never silently chain converters.** "Convert this markdown AND make slides from it AND a code review" is three operations. Pick one, finish, ask before chaining.
6. **Stdlib-only Python.** Deterministic logic, no LLM calls in scripts.
7. **Customization in use, not decoration.** Every converter MUST render differently when the user changes `design_style`, `brand.primary`, `code_theme`, or `toc.behavior`. If a token doesn't change behavior, it doesn't belong in the schema.
8. **Onboarding-first.** The orchestrator surfaces onboarding the moment it detects a missing `setup_completed_at`. Don't render with placeholder defaults silently.
## Build pattern
Path-B contract per skill: SKILL.md + 3 stdlib scripts + 3 references (each citing 5-7 sources) + (optional) 1 asset template. The orchestrator skill ships `context: fork` in its frontmatter. The `design-system` skill is the shared brand owner — every converter imports its `config_loader.py` via `sys.path.insert(0, .../design-system/scripts)`.
Each SKILL.md ships a "Forcing-question library" section (cited-canon grilling, one question at a time) — same discipline as `research-ops`, `commercial`, and `business-operations`.
## Agent + command pattern
- `cs-markdown-html-orchestrator` — density-first markdown-to-HTML converter. Voice: "What decision does this HTML drive — is the reader skimming, deciding, or presenting?"
- `/cs:markdown-html .md` — top-level router (classifier + route + recommend)
- `/cs:grill-markdown-html .md` — Matt-Pocock-style 5-question grill before conversion
- `/cs:design-system` — surface the onboarding wizard
Per-sub-skill commands (all live):
- `/cs:md-document`, `/cs:md-review`, `/cs:md-slides`
## Anti-patterns (domain-level)
- ❌ Converting markdown < 100 lines — markdown still wins. Refuse + cite Shihipar.
- ❌ Skipping onboarding because "the user wants it done now." Surface onboarding — it's 60 seconds.
- ❌ Multi-file output (separate CSS / JS / image folders). Single file or nothing.
- ❌ External JS framework runtimes (React, Vue, Svelte, Alpine). Vanilla JS + IntersectionObserver only.
- ❌ Silently overwriting existing output files. `output_path_resolver.py` suffixes `-2`, `-3`, … by default.
- ❌ Setting `MARKDOWN_HTML_NO_CONFIG=1` silently for an interactive user.
- ❌ Decorative tokens — every token must change at least one converter's output.
- ❌ Inventing brand colors when the user hasn't onboarded.
- ❌ A skill that overlaps Anthropic's official Playground plugin (sliders/knobs/prompt-copy-back).
- ❌ A skill that overlaps `marketing/landing/` (landing-page generation from scratch).
## Customization pipeline
1. User runs `python3 markdown-html/skills/design-system/scripts/onboard.py`.
2. Wizard validates brand colors via `brand_palette_validator.py`, derives 12-token palette.
3. Result written to `~/.config/markdown-html/design-system.json` (or `./.markdown-html/design-system.json` with `--scope project`).
4. Every converter sub-skill imports `config_loader.py` and calls `load_config()` to read project > global > defaults.
5. Each converter's renderer emits a single `