Skip to content

Put the explanation in the README, and keep it from rotting #199

Description

@abernier

Part of the distilled-docs spec (parent issue). Needs the schema PR and the skill.

Why

The one-line description is what the index can afford. It is not what a reader wants once they have opened the example.

What

The explainer lives in the example's own README.md, under the badges. That file already exists in all 170 examples — badges, degit line, thumbnail, nothing else. GitHub renders it, degit carries it into whatever the reader scaffolds, and it is where a human lands. Writing under the badges is additive: no new file, no new convention.

render-llms.mjs inlines it into <name>.md, under the facts block. This is what finally puts an explanation into the document agents are served. llms.txt is untouched — it keeps its single line. One line to choose, the full explainer once chosen.

Structure is fixed, length is not — the problem, the technique, the pitfalls. A fixed structure resists drift better than a word ceiling, and a demo that needs 200 words should not be padded to 400.

The glossary goes to examples/<demo>/CONTEXT.md, which the multi-context layout in docs/agents/domain.md already provides for.

Where the content comes from

describe-example --explain, which runs /mattpocock-skills:teach in sub-agents (see the skill issue). The teach workspace — MISSION.md, learning-records/, lessons/ — is one person's learning state and stays outside the repo. Only the reference distillation and the glossary come back.

Keeping it from rotting

Prose that explains code goes stale on its own. It gets a mechanism, chosen from how this repository actually changes.

How examples actually change. Seven commits in twenty-four months touched any example's src/:

Commit Files Examples
abdf0770 migrate demos → examples 1159 161
3f913a0d pre-commit prettier hook 593 161
d05ff3b6 convert the examples to TS 550 158
the other four 2–51 1 to 9

Nobody edits aquarium on its own. Change here is either a mechanical sweep across the whole gallery, or a targeted fix on a handful.

So the obvious mechanism is out. A hash of the example's source stored next to its explainer, failing the lint when the source moves, would have fired 161 times on a formatting commit. The only rational response would be to re-stamp 161 hashes without reading a word — training precisely the reflex that makes a tripwire worthless.

What works instead: every identifier the prose names in backticks must still appear somewhere in the example's src/. A concatenation and a search — no import parsing, no package resolution. useMask disappears in a drei migration → the lint breaks on precisely the explainers that named it, and on no others. A prettier sweep never wakes it.

It reaches further than renames: in a declarative r3f scene the technique is the set of components used, so an explainer saying "the spheres are instanced" names Instances, and the day instancing goes the identifier goes with it.

The check is deliberately looser than the one on apis, because it guards prose rather than a data field:

Field Checked against Why
apis the example's imports a list of library APIs — an entry that is not imported has no business there
README.md, CONTEXT.md anywhere in the example's src/ prose may name the demo's own components (Aquarium, Turtle) and its props (stencil in gl={{ stencil: true }})

What it gives up is small: an identifier deleted from the code but surviving in a comment still passes.

Second, free: the writing contract. The explainer names the technique and its APIs; it never walks the code, cites no line numbers, no variable names, no "the file X does Y".

Also in this PR

docs/agents/domain.md gains two rules:

  • teach is a legitimate producer of CONTEXT.md, alongside /domain-modeling
  • no demo gets a CONTEXT.md that merely restates its README

Absence is the normal state. teach is multi-session and interactive; realistically this happens for a handful of examples driven by curiosity, not as a programme across 170. An example with an explainer is better; one without is fine.

Done when

--explain produces an explainer for at least one example, <name>.md carries it, and the backticked-identifier check fails on a deliberately stale identifier.


How to implement

Start from a cleared session — this issue is written to be self-sufficient, and a session carrying the design discussion also carries the options that were rejected.

Branch off main once #194 and #196 have merged — it needs the renderer and the skill.

git checkout -b readme-explainer
/mattpocock-skills:implement #199

implement commits to the current branch, so the branch has to exist first — otherwise this lands on main.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions