Petri Lahdelma / Field Guide 04: Promptable docs template

A resource for design system and docs teams

Promptabledocstemplate.

One page per component, written for readers that cannot ask back.

Rules first. Everything enumerated. Every example compiled.

25writing rules, each checkable
17sections in a fixed order
01page per component

Docs are now read by two audiences at once.

Agents reach your documentation through MCP servers, Storybook manifests, llms.txt files and retrieval indexes. Each of them ends up serving the same thing: a component page, often as a single chunk cut from the middle. A page written for a person who can scroll, infer and ask a colleague fails that reader. The fix is not a second set of docs for machines; it is one page that works for both.

The evidence on formats is still thin and points in different directions. Vercel found that a small always-loaded docs index in AGENTS.md reached 100% on its Next.js evals, where an on-demand skill reached 79% even with explicit instructions [S07]. Atlassian found its MCP server beat a single DESIGN.md file on tokens used and design coverage [S08]. Both are vendor evals of single tasks. What they agree on is that the component page itself has to be excellent retrieval material, with a small index pointing to it.

This guide gives that page a fixed structure and 25 writing rules, and the kit makes them checkable: a template, a frontmatter schema, a linter, a generator that writes the API table from the Field Guide 02 contract, a script that extracts every example for the compiler, an llms.txt and ready-made agent instruction files.

Version 1.0 / Sources checked 24 September 2026
Field Guide 04 of the Design × AI series. The worked example is the same Button as Field Guides 02 (contract) and 03 (tokens); its examples typecheck against the contract's types.

Practical guidance, not a standard: none exists for component doc structure or frontmatter. Prepared with AI assistance and edited by hand.

Start here

Pick your route, then read the labels.

Apply the template to one component end to end before rolling it out. The rules are ordered by where they bite: structure, rules, API, examples, accessibility, delivery.

Writing a new page

Copy component-doc.template.md, fill it top to bottom and run the linter. Generate the API table from the contract rather than typing it.

Converting existing docs

Sections 01 and 02 first: fixed headings and a Rules section do most of the work. Move version history into Old patterns.

Opening docs to agents

Section 06: publish a .md twin, list it in llms.txt, and paste the AGENTS.md snippet into consuming repos.

Proving it works

W25: three agent tasks per component, run without docs and with docs. Keep the ones that fail as regression tests.

LabelMeaning
LINTChecked by lint-component-doc.mjs in the kit.
CIChecked by another kit script or CI job: the API generator, the code extractor, a staleness job.
AGENTExists so an agent retrieves, reads or follows the page correctly.
PRACTICEA working method with a review signal rather than a hard gate.
The page is the interface. MCP tools, Storybook manifests, llms.txt links and retrieval indexes all serve component pages. Improve the page and every channel improves with it.

Section 01

Structure the page for chunked reading.

Retrieval often returns one section, not the page. Every section has to stand on its own and sit where a reader, human or model, expects it.

Suggested owners: Docs owner + design-system lead

  1. Frontmatter carries the machine metadata

    W01LINT

    Identity, package and import, versions the page applies to, lifecycle status, owner, source URLs for the HTML page and its .md twin, and a last-verified stamp. Flat enough to index as metadata filters.

    Evidence: doc-frontmatter.schema.json, validated by the linter.

    Field names from Shopify (source_url), Mintlify, Custom Elements Manifest and Storybook. S10, S12.

  2. The H1 and a one-sentence summary open the page

    W02LINT

    A blockquote summary of 30 words or fewer that names the component and its one job. It is identical to the frontmatter summary, and it is the chunk head every retriever sees first.

    Evidence: Linter: H1 equals title; blockquote equals summary.

    Mirrors the llms.txt H1 and blockquote pattern. S01.

  3. Rules come first

    W03LINT

    ## Rules is the first H2. Constraints before prose, because the Rules chunk has to stand alone when it is the only one retrieved.

    Evidence: Linter: fixed H2 order.

    Recommended structure.

  4. Fixed heading text, fixed order

    W04LINT

    Seventeen H2 sections with the template's exact wording, on every component page. Predictable headings give predictable anchors and chunks.

    Evidence: Linter: H2 list compared with the template.

    Mintlify: skipped or renamed headings hide how sections relate. S11.

  5. Every section names the component

    W05LINTAGENT

    The first sentence of each section says "Button", never "it" or "this component". A chunk read on its own has no antecedent.

    Evidence: Linter warning when a section's first sentence omits the title.

    Mintlify on vague pronouns. S11.

  6. One term per concept

    W06PRACTICE

    Pick tone and never also say variant, kind or appearance for the same thing; pick prop, never option or param. Keep the list in a glossary and lint for banned synonyms.

    Evidence: A glossary with banned synonyms; the Does not exist list.

    Anthropic: use consistent terminology. S05.

  7. Nothing hides in tabs, images or widgets

    W07PRACTICE

    The .md twin contains every variant and every example as plain Markdown, and no rule exists only in an image or video.

    Evidence: Diff the code blocks in the HTML page against the .md twin.

    Mintlify structure guide. S11.

  8. Concise by default

    W08LINT

    Skip what the model already knows about the web or the framework. Keep a page under 500 lines; split larger ones.

    Evidence: Linter warning over 500 lines.

    Anthropic skill guidance, applied by analogy to docs. S05.

Write every section as if it were the only one retrieved, because often it is.

Section 02

Write rules a model can follow and a script can check.

The Rules section is the only text meant to be copied into agent rule files. Keep it short, keep its words exact and give every prohibition a way out.

Suggested owners: Docs owner + accessibility lead

  1. Declare RFC 2119 and 8174 once

    W09PRACTICE

    State once, on the docs index and in llms.txt, that MUST, MUST NOT, SHOULD, SHOULD NOT and MAY carry their BCP 14 meaning only in capitals.

    Evidence: The boilerplate is present in llms.txt (the kit's example has it).

    RFC 8174. S03.

  2. Three to ten rules, each with a keyword

    W10LINT

    Most important first. Each bullet carries exactly one normative keyword in capitals.

    Evidence: Linter: 3 to 10 bullets, each with a keyword.

    Recommended practice.

  3. Every prohibition gives the reason and the replacement

    W11LINTAGENT

    "Button MUST NOT navigate to another page, because screen readers announce it as a button; use Link instead." A bare "don't" leaves the model to guess the alternative.

    Evidence: Linter: every MUST NOT and SHOULD NOT contains "because" and "use".

    Anthropic: give the reason, and say what to do instead. S04.

  4. Capitals only in Rules

    W12LINT

    Outside Rules (and the "You MUST provide" accessibility list) write plain facts. Lowercase "should" and "must" read as advice, so avoid them too.

    Evidence: Linter: RFC keywords outside Rules are errors; lowercase normative words are warnings.

    RFC 8174: lowercase words keep their ordinary meaning. S03.

  5. No shouting

    W13PRACTICE

    No CRITICAL, IMPORTANT! or bold-capital banners. RFC keywords are a vocabulary, not emphasis.

    Evidence: Grep for emphasis banners in review.

    Anthropic notes that newer models can over-trigger on aggressive emphasis. S04. No published eval shows that RFC capitals improve compliance; the case for them is clarity and checkability.

A rule without a replacement is a trap, not a rule.

Section 03

Enumerate the API, and name what does not exist.

Agents invent what the page leaves open. Close every set, generate the table from source and list the guesses you have already seen.

Suggested owners: Design-system lead + engineering lead

  1. Generate the API table from the contract

    W14CI

    Hand-written prop tables drift. The kit writes the table from the Field Guide 02 contract between two marker comments and fails CI when the page differs.

    Evidence: generate-api-table.mjs page.md contract.json --check.

    Storybook recommends docgen for accuracy. S13.

  2. Close every set in words

    W15CIAGENT

    "Valid values: primary, secondary, ghost, destructive. No other values are valid." The generator writes this sentence for every enum.

    Evidence: Generated API table.

    Enumerated sets make invented values provable. S09.

  3. Name the hallucinations

    W16LINTAGENT

    A "Does not exist" list under Do and don't: the props, values and components agents keep guessing (variant, shadow, PrimaryButton), with the real alternative. Feed it from agent-eval failures.

    Evidence: Linter: the section is required.

    Ant Design's export allow-list with named non-existent components. S09.

  4. One default, then the exception

    W17PRACTICE

    "Use Button. For navigation, use Link." Three equal options invite a coin toss.

    Evidence: When to use names exactly one default per task.

    Anthropic: provide a default with an escape hatch. S05.

Anything the page does not close, an agent will open.

Section 04

Examples that compile, and mistakes that teach.

Models copy examples more reliably than they follow prose. That makes every example a specification, so every example has to be correct.

Suggested owners: Docs owner + engineering lead

  1. One complete canonical example first

    W18LINT

    Imports included, no ..., no placeholder props, accessible name present. It is the example an agent copies by default.

    Evidence: Section order in the linter; the extractor compiles it.

    Recommended practice.

  2. Every code block compiles in CI

    W19CI

    Extract the blocks and typecheck them against the version in last_verified. The kit's Button examples compile against the contract's own types, and an invented tone in any of them fails the build.

    Evidence: extract-doc-code.mjs then tsc --noEmit; blocks after "Don't:" are skipped because they are wrong on purpose.

    Kit scripts.

  3. Every fence has a language

    W20LINT

    Fenced blocks with a language tag, never inline code for multi-token snippets.

    Evidence: Linter: untagged fences are errors.

    Mintlify: inline code can split into separate tokens. S11.

  4. Do and don't pairs are symmetric

    W21PRACTICE

    Each Don't block is followed by one sentence of reason and a Do block that fixes the same case.

    Evidence: Review: matching counts of Do and Don't blocks.

    Recommended practice.

An example that does not compile teaches the wrong API with full confidence.

Section 05

Split what the component gives from what you owe.

Most accessibility failures in generated UI are consumer failures: the component was fine, the accessible name was missing.

Suggested owners: Accessibility lead + docs owner

  1. Provides, You MUST provide, Keyboard interaction

    W22LINTAGENT

    Three fixed subsections. Link the APG pattern, keep the keyboard table in APG's shape and state the accessible-name requirement explicitly. Never recommend ARIA that duplicates native semantics.

    Evidence: Linter: all three subsections are required.

    APG pattern pages; APG: no ARIA is better than bad ARIA. S14.

The component can promise a role. Only the consumer can supply a name.

Section 06

Keep it fresh, findable and tested.

A correct page nobody retrieves, or a stale one that everybody does, is worse than no page. Stamp it, publish it where agents look, and measure it.

Suggested owners: Docs owner + platform owner

  1. Version-conditional text lives in Old patterns

    W23LINT

    No "before v4", "as of 3.2" or "recently" in the main sections. Deprecated usage goes in one table: old usage, removed in, replacement.

    Evidence: Linter: version-conditional phrases outside Old patterns are errors.

    Anthropic: avoid time-sensitive information; keep an old-patterns section. S05.

  2. Stamp it, twin it, list it

    W24LINTCI

    A machine-checkable last_verified (date, package version, method) with a staleness job; a .md twin advertised with rel="alternate" type="text/markdown"; and a link from an llms.txt that follows v2.

    Evidence: Linter warns on stamps older than 180 days (a local policy); a HEAD request shows the Link header.

    llms.txt v2 (August 2026). S01, S02.

  3. Evaluate the page with agents

    W25PRACTICE

    Keep at least three agent tasks per component ("build a destructive confirm dialog with Button") with pass criteria. Run them without the docs, then with them, and after every significant edit.

    Evidence: An eval file per component, run in CI or on release.

    Anthropic: build evaluations before writing extensive docs. S05. Atlassian and Vercel publish results from evals of this kind. S07, S08.

Measure the page with the readers it is written for.

Appendix A

The page, section by section.

The fixed order the linter enforces, with the job of each section. Section titles are exact.

SectionJobWritten by
Frontmatter, H1, summaryIdentity and the chunk head every retriever seesAuthor
RulesThe normative contract; the only text copied into agent rule filesAuthor
When to use / When not to useChoose this component, or name the alternativeAuthor
ImportThe exact import lineAuthor
Canonical exampleThe default code an agent copiesAuthor, compiled in CI
APIEvery prop, type, value and default, plus combination rulesGenerated from the contract
VariantsPurpose of each value, when and when notAuthor
StatesHow each state is set, what the component does, what you provideAuthor
CompositionAllowed parents and children, forbidden nestingAuthor
AccessibilityProvides, You MUST provide, keyboard tableAuthor with accessibility lead
Content guidelinesLabel rules as Do and Don't text pairsContent designer
Do and don'tCode-level mistakes with fixes; Does not existAuthor, fed by evals
TokensTokens the component uses (Field Guide 03)Author
RelatedSibling components with a use-instead-when noteAuthor
Old patternsDeprecated usage and replacements, the only versioned textAuthor
VerificationCommands and tools that check output mechanicallyAuthor
Machine-readable sourcesContract, manifest, story IDs, token filesAuthor

examples/button.md (frontmatter and Rules)

---
id: button
title: Button
summary: Button triggers one action in the current view, such as saving or submitting a form.
package: "@acme/ui"
import: "import { Button } from \"@acme/ui\";"
applies_to_versions: ">=4.2 <5"
status: stable
last_verified: { date: 2026-09-24, against_version: "4.6.1", method: ci-doc-tests }
contract: ./button.contract.json
---

# Button

> Button triggers one action in the current view, such as saving or submitting a form.

## Rules

- Button MUST have an accessible name: visible text, or `aria-label` when `iconOnly` is true.
- Button MUST NOT navigate to another page, because screen readers announce it as a button
  and users expect an action; use `Link` instead.

Abbreviated for print: the file uses multi-line YAML and one line per rule. The full page is in the kit and passes the linter with no errors or warnings.

Appendix B

Point agents at the page.

Instruction files are always loaded, so they carry a short router, not the docs. The llms.txt follows the v2 proposal: one H1, a blockquote, plain notes, then H2 sections of link lists.

llms.txt (excerpt)

# Acme Design System

> Acme Design System is the React component library, design tokens and usage guidelines for
> Acme web products. Package: `@acme/ui` 4.x.

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in linked pages are to be interpreted
as described in BCP 14 (RFC 2119, RFC 8174) when, and only when, they appear in all capitals.

- `@acme/ui` does not export `Box`, `Stack`, `Container`, `Heading`, `PrimaryButton` or `IconButton`.

## Components

- [Button](https://design.acme.example/components/button.md): Triggers one in-page action
- [Link](https://design.acme.example/components/link.md): Navigates to another page

## Optional

- [Complete documentation](https://design.acme.example/docs/llms-full.txt): Every page concatenated

llms-full.txt is a platform convention, not part of the spec, so it sits under Optional.

agents/AGENTS.snippet.md

## UI components (Acme Design System)

- Build UI with `@acme/ui` 4.x. Icons come from `@acme/icons`.
- Prefer retrieval over recall: read the component page before using a component.
  Index: https://design.acme.example/docs/llms.txt
- Use only exported components and only the props and values each page lists.
- Style with semantic tokens (`var(--ds-color-*)`). Never use `--ds-core-*` or `--ds-comp-*`.
- Before finishing, run `npm run lint`, `npx tsc --noEmit` and the Storybook tests.

The kit also has the same router as a path-scoped Claude Code rule, a Copilot instructions file and a Cursor rule.

FileRead byScope
AGENTS.mdCodex, Copilot coding agent, Cursor, Claude Code and othersNearest file in the tree
.claude/rules/*.mdClaude Codepaths: globs in frontmatter
.github/instructions/*.instructions.mdGitHub CopilotapplyTo: globs
.cursor/rules/*.mdcCursorglobs, alwaysApply

Verify file names and scoping against the tool versions you run; these conventions still move.

Appendix C

Run the checks.

Three scripts turn the rules into a build step. Output below is from the kit's Button page.

terminal

$ node scripts/generate-api-table.mjs examples/button.md button.contract.json --check
examples/button.md: API section matches the contract.

$ node scripts/lint-component-doc.mjs examples/button.md
1 page(s), 0 error(s)

$ node scripts/extract-doc-code.mjs examples/button.md .doc-tests
Extracted 5 code block(s) into .doc-tests
$ npx tsc --noEmit -p .doc-tests
(no output: every example compiles against the Button contract types)
Linter checkSeverity
Frontmatter against doc-frontmatter.schema.jsonerror
H1 equals title; blockquote equals summaryerror
Seventeen H2 sections, exact text, fixed ordererror
3 to 10 rules, each with an RFC keyword; MUST NOT with because and useerror
RFC keywords outside Rules and You MUST provideerror
Untagged code fences; missing API markerserror
Version-conditional wording outside Old patternserror
Missing Does not exist list or accessibility subsectionserror
Lowercase should or must outside Ruleswarning
Section's first sentence does not name the componentwarning
last_verified older than 180 days; page over 500 lineswarning

Keep with the page

Leave a page review record.

A record for one component page. It shows which checks ran against which package version, and what the agent evals said.

Component / page id
Package version verified against
Linter run (link)
API table check against contract (link)
Extracted examples compiled (link)
Agent eval tasks and results (link)
Does not exist list updated from evals
Accessibility review (name, date)
Owner
Next review date
A green linter is not a good page. The linter proves the page is complete and consistent. Only the agent evals show whether it helps.

Sources / maintenance

Keep the guide current.

Sources checked 24 September 2026. Vendor eval figures are single-task results published by the vendors; treat them as signals, not benchmarks.

S01 / llms.txt proposal (v2, August 2026)File structure, link relations and path scoping.https://llmstxt.org/index.md
S02 / llms.txt changesWhat v2 changed, including the Optional section.https://llmstxt.org/changes.md
S03 / RFC 8174Ambiguity of uppercase and lowercase in RFC 2119 keywords.https://www.rfc-editor.org/rfc/rfc8174.txt
S04 / Anthropic, prompting best practicesGive reasons, say what to do instead, avoid aggressive emphasis.https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices
S05 / Anthropic, Agent Skills best practicesConcise content, consistent terms, defaults, evaluations first, old-patterns sections.https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices
S06 / AGENTS.mdThe shared agent instruction file convention.https://agents.md/
S07 / Vercel, AGENTS.md outperforms skills in our agent evalsAlways-loaded docs index at 100% against a skill at 79% (January 2026).https://vercel.com/blog/agents-md-outperforms-skills-in-our-agent-evals
S08 / Atlassian, testing DESIGN.md in practiceMCP server against DESIGN.md on tokens and design coverage (June 2026).https://www.atlassian.com/blog/how-we-build/atlassians-design-md-is-here-what-we-learned-testing-portable-design-context-in-practice
S09 / Kaelig Deloumeau-Prigent, State of AI in Design SystemsSurvey of 21 systems (July 2026); secondary source for per-system tooling.https://state-of-ai-in-design-systems.netlify.app
S10 / Shopify, Polaris with MCP (markdown twin)Frontmatter with title, description and source_url for html and md.https://shopify.dev/docs/api/polaris/using-mcp.md
S11 / Mintlify, structuring documentation for AI and human readersHeadings, pronouns, tabs and inline code in chunked retrieval.https://www.mintlify.com/blog/structure-documentation-AI-human-readers
S12 / Custom Elements ManifestStructured component metadata that pairs with prose docs.https://github.com/webcomponents/custom-elements-manifest
S13 / Storybook, writing docs for AIDocgen, JSDoc descriptions and one concept per story.https://storybook.js.org/docs/ai/best-practices
S14 / W3C, ARIA Authoring Practices: button patternKeyboard interaction and roles, states and properties.https://www.w3.org/WAI/ARIA/apg/patterns/button/

Maintenance: recheck the llms.txt proposal, the agent instruction file conventions and the Storybook AI pages every quarter; all three moved in 2026. Update the PDF, HTML, Markdown and JSON together.