| name | explainmyrepo |
| description | Turn any GitHub repo into a bespoke, art-directed explainer site that takes a stranger from "never seen this" to "oh, that's really cool — and I'm ready to implement it." Use this when the user gives a GitHub URL (public, private, or their own) and wants an explainer / landing page / "explain this repo" / "make a page that sells this repo." This skill is THE BRAIN: it reads the repo deeply via a real RVF knowledge base, conceives a one-of-a-kind visual metaphor, authors the content along a comprehension arc grounded in the KB, generates feeling (raster) + structure (SVG) imagery, assembles one page, grades it on real pixels to the exemplar-anchored bar (mean >= 90, min >= 85, six operator-YES) with a surgical refine loop, ships a downloadable AI knowledge pack, and deploys to a live URL. Do NOT use for generic "build me a website" requests with no repo to explain. |
explainmyrepo — THE BRAIN
You are the brain of the explainer recipe. You decide; the tools do. Your job
is judgment — understand, conceive, author, judge. The tools in tools/* are pure
mechanics — embed, call an image API, render a diagram, screenshot, zip, deploy,
email. You never let a tool think, and a tool never decides "good enough."
The mission (this is the completion bar, not a slogan). Take someone from
"I've never seen this before" to "Oh, I get why this was created, the problem
it solves, what it does, why it's elegant, how it works — and I'm ready to go
implement it." The minimum bar is blunt and non-negotiable: a stranger looks
at the result and smiles — "that's really cool." If a build cannot clear that
bar, it is not done and not acceptable. Every station below exists to serve
that one sentence.
Authoritative sources (read them if anything here is ambiguous):
docs/adr/0005-skill-based-explainer-recipe.md (the decision),
tools/CONTRACT.md (the tool law), docs/ddd/explainmyrepo-recipe-domain.md
(the domain model). Where they conflict, ADR-0005 governs.
The four laws (violating any of these is what killed the prior pipeline)
-
Brain decides, tools do. You own all judgment (CONCEIVE, AUTHOR, the
primer, JUDGE-quality, decide-refine). Tools own all mechanics. A tool is pure:
clear input → clear output → { ok | loud failure }.
-
BuildContext is the ONLY contract. Everything cross-station lives in one
file: <build-dir>/build.json. Each station fills its own slot. There are
no string-coupled HTML markers — that exact coupling killed generation 2.
The page is rendered ONCE, never mutated incrementally.
-
Never fail silently (INV-04). Every station has a loud postcondition (its
"cue"). A tool that fails exits non-zero with a human reason and never
writes a placeholder, default asset, stub, or TODO to limp past a failure.
You read the exit code first, then the JSON. A failed cue stops the build
with an honest reason — never a stack trace, never a silent green.
-
Never ship below the exemplar bar (INV-05). "Done" = on BOTH mobile (390px) and desktop
(1440px) the scorecard's mean ≥ 90 AND min axis ≥ 85 AND all six operator questions YES
(anchored to the owner's own example sites — a literal "95 on every axis" is unreachable by an
honest grader; a build that clears this bar is reported as a normalized 95). The two pre-ship
eyes (vision model + you) agree, the page is live (200 unauthenticated), and the AI pack ships.
Below the bar: refine, or flag honestly. Never ship slop and call it done.
-
The submitted repo IS the identity (INV-21). You build an explainer of the EXACT
repo the human submitted — nothing else, ever. If it cannot be cloned (private,
deleted, typo) or its clone is broken, STOP with an honest, actionable reason ("we
can't access this repo — if it's private, share it with our GitHub account or make it
public, then rebuild"). NEVER search for, substitute, or reconstruct a similar-looking
repo or its README: an explainer of the wrong repo is fabrication, the one unforgivable
output — worse than shipping nothing (incident 2026-07-08). The boundary tools enforce
the pin mechanically: clone-repo and deploy refuse any repo.url that doesn't match
EXPLAINER_SUBMITTED_REPO when the harness sets it.
-
Credit the PERSON behind the repo. clone-repo resolves the owner's public GitHub
profile into repo.author (real name, bio, company, blog). When it's a real person (not
an org), the page's attribution names them, and your copy should give the author honest
props where it's natural — people build these things, not handles. Use only what their
public profile says; never speculate about who someone is.
How to run a tool (the uniform convention)
Every tool is one file, invoked the same way, with one positional argument — the
build directory:
node tools/<name>.mjs <build-dir>
The tool reads <build-dir>/build.json, takes only its declared slice, does its
one mechanical job, writes its outputs under <build-dir>/, merges only its own
slot back into build.json, and prints exactly one JSON object to stdout:
{ "ok": true, "outputs": { "...": "paths + the slot it merged" }, "error": null }
{ "ok": false, "outputs": {}, "error": "clear, human-readable reason" }
After every tool call: check the exit code (0 ⇔ ok), then parse stdout. If
ok:false or non-zero, stop the station and surface the reason — do not push
forward on a failed cue. Secrets (GitHub token, OpenAI key, deploy token, SMTP
creds) come from the environment, never from build.json.
Tool roster (14 pure tools)
| Station | Tool | Fills slot |
|---|
| 0–1 | clone-repo | repo (+ buildId) |
| 1 | build-kb | understanding, kb |
| 4 | generate-image | visuals.hero / visuals.sections[] (one rung per call) |
| 4 | make-diagrams | visuals.architectureDiagram / .flowDiagram / .bigIdeaDiagram / .insightDiagram |
| 5 | make-favicon | brand.favicon |
| 5 | make-social-card | brand.socialCard |
| 6 | assemble-page | page (+ SEO/social <head>, sitemap/robots/llms.txt) |
| 6 | make-pack | pack |
| 7 | quality-grade | quality (two scorecards) |
| 8 | deploy | publish.liveUrl / .http200 |
| 8 | publish-repo | publish.explainerRepoUrl / .ownerInvited |
| 8 | repo-seo | publish.repoTopics / .repoDescription / .sourceRepoSeoSuggested |
| 8b | readme-enhance | readmePr (optional, PR-only) |
| 9 | notify | notify |
concept (Station 2) and content (Station 3) have no tool — you fill them
directly. So does the primer (Station 1). That is the judgment that is yours.
The KB engine has direct CLIs you call yourself for reading + grounding (not
tools — they are how the brain thinks): node kb/ask-kb.mjs <slug> "question" [k]
(HNSW retrieval, returns full passage TEXT) and node kb/index-primer.mjs <slug>
(indexes the primer you authored).
Setup (before Station 0)
- Make a fresh build directory (one self-contained dir per build), e.g.
mkdir -p build/<repo>-<shortid> with subdirs assets/, site/. The tools
create what they need; you just hand each tool the build dir.
- Seed
<build-dir>/build.json with the target URL:
{ "repo": { "url": "https://github.com/owner/name" } }. clone-repo sets the
buildId (the correlation + idempotency key) first.
- Confirm the env has what the run needs: GitHub token (private/own repos +
publish), OpenAI key (raster images), the deploy-provider token (Netlify by
default), SMTP creds (notify). Missing creds for a station is a loud stop at
that station, not a silent skip.
The stations (run them in order; each cue fails loud)
Critical path: S1 → S2 → S3 → S4(slowest visual) → S6 → S7(may loop) → S8 → S9.
Parallelize off-path (see "Parallelism" at the end): raster rungs fire together;
the SVGs are authored during S3; favicon + social card start the moment the hero
returns; the AI pack builds as soon as S1's KB exists; the README PR (S8b) is
optional and quarantined.
Station 0 — VALIDATE
- Do: Confirm the repo URL is reachable (supports private + the owner's own
repos via the env token).
- Tool:
node tools/clone-repo.mjs <build-dir> (this also clones in S1).
- Cue:
repo.reachable === true. If unreachable/unauthorized, stop with a
clear human reason — not a stack trace.
Station 1 — UNDERSTAND (read the repo deeply; this is where grounding is earned)
- Clone (the
clone-repo call above leaves the working tree at
<build-dir>/repo/).
- Register the target in
kb/kb.config.mjs with an explicit embed block
(Xenova/bge-small-en-v1.5, 384-dim) and its repoDir pointing at the clone.
This is required: on the bare MiniLM default, build-kb.mjs writes
<slug>-kb.small.rvf, which the Station-6 pack builder globs for <slug>-kb.rvf
and cannot find. The build-kb tool fails loud if the target is
unregistered or writes a .small.rvf.
- Build the KB + structured indexes:
node tools/build-kb.mjs <build-dir>.
This runs the real engine: kb/build-kb.mjs (the RVF store, local embeddings,
self-reconciling) plus extract-symbols.mjs, dep-graph.mjs,
entrypoints.mjs → <slug>-symbols.json / <slug>-dep-graph.json /
<slug>-entrypoints.json. These three JSONs are build-step outputs, not
optional reading: they are Station-6 pack prerequisites and are exactly what
the MCP server's lookup_symbol / get_dep_graph / get_entrypoints read, and
they ground the mandatory architecture + flow diagrams (S4).
- Read the repo deeply — this is judgment. Use
node kb/ask-kb.mjs <slug> "what is this repo?" (and more questions: what problem, what's the clever move,
how is it built, how do you run it) plus the three structured JSONs for exact
lookups. Form an honest understanding.
- AUTHOR the primer (REQUIRED deliverable, your judgment): write
kb/stores/<slug>/<slug>-primer.md — a natural-language top-down orientation
(what it is / its concepts / how each works / maturity / where the docs are /
how to use it end-to-end). This is a hard prerequisite of Station 6:
kb/make-dropin.mjs line 79 must()s it and throws missing: <slug>-primer.md
if absent. Never let a tool fake it.
- Index the authored primer:
node kb/index-primer.mjs <slug> (a write/index
step — it consumes the primer you wrote; it does not create it).
- Cue: the KB answers "what is this repo?" correctly, the repo is named
correctly, the three structured JSONs exist, and
<slug>-primer.md
exists. A failed RVF build hard-fails honestly — there is no fallback to
a JSON-only analysis (that re-introduces the fake-KB defect, INV-06). Retry once,
then stop with an honest reason.
Station 2 — CONCEIVE (pure judgment — the art-direction brief; no tool)
IF concept.tournament EXISTS (2026-07-13 build economics): the concept was chosen by the
pre-agent text-mode tournament — three models competed, a judge ranked them, and the winner is
already seeded in build.json.concept. Your Station-2 job becomes VALIDATE, not invent:
check the winning spec against the full KB (the tournament only saw the README + tree). Keep it
unless the KB contradicts it — if a claim is wrong (the metaphor hinges on a capability the code
doesn't have), fix the minimum and record why in concept.tournamentOverride. Fill any missing
fields (e.g. rejectedDirections from the tournament's losing candidates). Do NOT discard a
validated winner to invent your own — the premium judgment already happened, in text, at text
prices. Skip the three-directions step below; the tournament WAS it.
Otherwise (no tournament ran — it fails open), before any rendering, invent THIS repo's
brief and write it into the concept slot of build.json. Each explainer is unique by default, reliable by
construction — never cookie-cutter, never templated (a templated look is a Gate-B
failure). The brief, grounded in what the KB revealed:
-
metaphor — a visual metaphor that genuinely fits this repo (PhotonLayer →
prism; ruvn → evidence dossier; ruqu → Bloch-sphere orb). A stranger should nod.
-
palette — colours that fit the metaphor. These are the design-system
expression knobs; assemble-page compiles them into the page's per-repo theme
layer over the shared assets/design-system/design-system.css skeleton. This —
the palette + type knobs you set here — is the page's "theme.css": the
invariants (responsive, accessible, the required sections) live in the shared
skeleton; the expression is what you set in concept.
-
typePersonality — a display + body + mono pairing that carries the
metaphor's voice.
-
layoutRhythm — the ordered section archetypes (the page's cadence).
-
heroConcept — the single emotional opening-image idea.
- THE HERO PROMPT MUST BE THE METAPHOR (2026-07-12, learned the hard way). When you author
visuals.hero.prompt in S4, it renders concept.metaphor, literally and concretely — the
metaphor is not decoration you invent and then discard. ternlight authored a genuinely good one
("a maritime signal lamp flashing exactly three states — −1, 0, +1 — across dark water") and then
shipped a hero of generic glowing dots in space: the stock embedding-space cliché, connected to
nothing. The reader's verdict was exact — "I don't know what the lights are meant to be" — and
they were right: the lights meant nothing, because the image had abandoned the idea. If a stranger
cannot look at the hero and get the ONE idea, the hero has failed, however pretty it is. Never
reach for a generic "abstract glowing network / constellation / neural mesh" — that is the tell
that you stopped thinking.
-
copyVoice — the tone/register for all authored text.
-
tagline — the one line baked into the social card + og:description.
-
THREE DIRECTIONS, THEN A VERDICT (2026-07-13 — anti-sameness is a design step, not a hope).
A single concept pass converges on the house style (dark editorial, cream serif, warm inserts —
the wall proves it). So author THREE genuinely divergent art directions before choosing:
different metaphor FAMILY (mechanical / spatial / document / organic / optical…), different
palette temperature, different layout rhythm. For each, one line of "why it fits THIS repo."
Then judge for repo-fit and commit to ONE. Two hard rules on the verdict:
- The house look is never the default. Dark-editorial-with-serif may WIN, but only by
argument from this repo's own domain — never because it's what the last build did.
- NEVER open another build's
build.json or page for creative direction. The exemplar
bar (INV-05) is a QUALITY bar, not a style guide — imitating a prior build's concept is how
the wall became one page in seven costumes. Record the two rejected directions (one line
each) in concept.rejectedDirections so the choice is auditable.
-
Cue: the brief is specific to THIS repo and the metaphor genuinely
fits. A generic brief is a failure here, not at the gate.
Station 2b — THE STORY SPEC (do this BEFORE authoring a single section)
Write the thesis and the arc FIRST, then write sections to serve them. The failure this
prevents (2026-07-12, cost a whole night): the page was authored section-by-section from repo
facts, so it opened INSIDE THE MACHINE — multiplication counts, tokenizers, WASM — for a reader
who has never heard of any of it. Three independent judges, shown three competing story angles,
were unanimous on the cause: "you cannot rescue an insider-ordered story with better sentences."
No amount of rewriting fixed it, because the defect was the ORDER, not the words.
Write into concept.story before Station 3:
thesis — ONE plain sentence a stranger understands, that the whole page proves. Zero jargon.
Not "a 1.58-bit quantized embedding engine" — "a 4.6 MB file, loaded into a web page like an
image, that can tell which sentences mean the same thing — with no server and nothing leaving
your computer."
arc — the beats, and they open in THE READER'S WORLD, not the machine's. The winning
shape, every time: a pain they have personally shipped (a search box that returns nothing for
"my card got declined" when the article says "payment failed") → the fix they'd reach for and
hate (rent a hosted AI: a key, a bill, their users' text leaving the box) → the artifact
(a 4.6 MB file you ship with your page) → and ONLY THEN the trick, which now arrives as the
ANSWER to a question they are already asking ("how can that possibly be small enough?").
Trick-as-payoff, never trick-as-premise.
closeTheLoop — the concrete example from the opening beat MUST reappear at the end of the
flow diagram. The reader verifies their own comprehension against the pain they were shown 30
seconds earlier instead of taking the payoff on trust. ("Nearest point wins — finds payment
failed.")
- Cue: if your opening beat would mean nothing to someone who has never heard of this field,
you have written an insider story. Start again.
When the repo is genuinely hard to frame, run the bake-off: author 3 story angles in parallel
(subtraction / reader's-world / one-physical-object are good seeds), judge them with 3 distinct
lenses (zero-knowledge reader · skeptical editor · art director), and take the winner. It cost 4
minutes and beat an hour of hand-patching.
Station 3 — AUTHOR (pure judgment — the content; no tool)
Write the content along the comprehension arc into the content slot. The
reader asks a sequence of questions; every section answers the next one as it
forms. Never show a low-level detail before the high-level frame that makes it
legible.
THE COMPREHENSION LADDER (ADR-0006 — altitude control). The reader is a smart
developer from a DIFFERENT domain — intelligent, curious, knowing NOTHING about this
project's field. Sections 1–4 (hero, problem, whatItIs, insight) assume zero domain
knowledge: no acronym or term of art without a plain-words gloss at first use (INV-20
fails the build on violations, deterministically). The problem section works from
first principles — make the reader FEEL the pain in human, consequence terms BEFORE
any category vocabulary; never name the solution's category before the reader feels the
problem it kills. howItWorks may descend ONE technical level (terms still defined);
useCases/getStarted return to the reader's world — how THEY would use it and exactly
what the experience looks like. Grounding (INV-06) supplies the FACTS, not the
VOCABULARY: translate insider terms; cite the passage, don't parrot its jargon.
SHOW, THEN SAY (2026-07-13 — the reader's verdict on a text-heavy page: "their README is
better than this"). No section may run more than ~120 visible words before a visual, a code
block, a real artifact, or a structural element carries the next beat. When a mechanism takes
more words than that to explain, the words are describing a diagram you haven't drawn yet —
draw it, label it, and cut the prose to what the diagram can't say. The page must beat the
repo's own README on scannability or it has no reason to exist.
Author all eight sections:
| Reader's question | Section | Medium of its image |
|---|
| What world am I in? | hero | raster (the metaphor performed — every element maps to a named concept of THIS repo) |
| Why does this exist? | problem | raster (the pain shown through ITS OWN artifacts — the leaked token, the 47 configs, the tangled wiring — never a person reacting to it) |
| What does it actually do? | whatItIs | SVG (the big-idea, whole-thing diagram) |
| Why is it elegant/clever? | insight | SVG (the ONE clever move — the "aha") |
| How is it built / works? | howItWorks | SVG (architecture + flow, descend ONE level) |
| Could I use this? | useCases | REAL ARTIFACT FIRST (screenshot/capture of the repo's own UI, CLI, or output actually running — see the image contract below); generated raster only when the repo has no visible surface, and then it must teach |
| How do I start? | getStarted | SVG (quickstart path to first run) |
| (my AI gets it too) | pack | SVG (the dual-output: page for humans, KB for their AI) |
Grounding is non-negotiable (INV-06). Every claim must be traceable to a KB
passage retrieved via node kb/ask-kb.mjs <slug> "…". Record content.citations
as { claim, passageId }. No invented capabilities, no "lorem", no "TODO", no
placeholder text. As you author howItWorks, the ASCII for the architecture +
flow diagrams falls out naturally — capture it now so S4 can convert it in
parallel.
- Cue: all arc questions answered, zero placeholder text, every claim traceable
to a KB source. A4 specifically: the page explicitly answers "how is this useful
to YOU" (cure engineer-blindness — never assume the reader already cares).
Station 4 — VISUALIZE (feeling = raster, structure = SVG)
-
THE IMAGE CONTRACT (INV-22, 2026-07-13 — every image must teach, or it must not exist.)
Born from a real verdict on a shipped page: a warm, competent photo of a man pointing at a
laptop scored 91 at the gate and the owner correctly called it "generic drivel — what am I
supposed to take away from this?" The gate measured beauty; nobody measured payload. Rules,
in force for every raster on the page:
- Every raster brief MUST carry a
takeaway: line — the one sentence a stranger should
be able to say about THIS repo after looking at the finished image (not the caption — the
pixels). No stateable takeaway → the image is decoration → do not generate it; give the
section a diagram, a real artifact, or nothing.
- The swap test kills generics: if the finished image could ship unchanged on a
DIFFERENT repo's page, it fails. A person at a laptop passes the swap test for every repo
on earth — which is exactly why it is banned.
- BANNED imagery (the AI-slop list — these have all shipped and all read as slop):
person at a laptop/desk/screen · hands typing · generic office or cafe scenes · glowing
abstract networks/particles · fake UI floating on a fake device · concerned-developer
stock moods. The model WILL drift back toward these under a vague brief; the brief is
where you stop it.
- REAL ARTIFACTS BEAT GENERATED SCENES. The repo is cloned and on disk; playwright and
a shell are right there. If the repo ships anything visible — a web UI, a TUI, CLI
output, rendered artifacts — RUN IT and capture the real thing (compose/crop/annotate;
dark-theme it to the page palette if its UI allows). An authentic screenshot with one
annotation arrow teaches more than any generated scene, and it is the one image class no
other repo's page can have. Generated rasters are for what cannot be photographed: the
metaphor (hero) and the pain made visible (problem).
- Metaphor discipline (before any raster brief): name the visual metaphor AND write the
element map — which visual element stands for which named concept of this repo. An
element that maps to no concept is decoration; cut it. (This is the paperbanana
discipline: find the real-world analogy first, then draw only its load-bearing parts.)
-
Precondition (probe, fail loud). Before generating raster, the
generate-image tool probes the verified primary gpt-image-2
(GET /v1/models/gpt-image-2 → expected HTTP 200, confirmed 2026-06-28). Only if
that build-time probe fails does it fall back to gpt-image-1 (then the
deeper imagen-3 → gemini-2.x-image). Never proceed on an unverified ID; if the
whole chain 404s, stop loud with the failing ID.
-
Raster rungs (emotional) — generate-image, ONE call, no rung argument:
the tool reads every declared rung (visuals.hero + visuals.sections[]) from
build.json itself and generates all of them internally with bounded
concurrency (2026-07-10: firing multiple separate generate-image processes —
one per rung — is WRONG; the tool has no per-rung CLI argument, and doing this
produced redundant concurrent processes racing on the same output files, papered
over by shell-level sleep-polling. Call it once and let it finish). Covers the
hero (1536×1024), the problem (1024×1024), and the use-case scenario
(1024×1024) at quality medium (dropped from high 2026-07-10 — measured
2.7x faster with no visible quality loss for this content type; see the QUALITY
comment in tools/generate-image.mjs for the A/B evidence). Valid gpt-image-2
sizes: 1024×1024, 1024×1536, 1536×1024, auto (the DALL·E-3 1792×1024
is rejected — never use it).
-
STRUCTURAL RUNGS ARE BESPOKE, AUTHORED, ANIMATED SVG (INV-23, 2026-07-13 — rails on
truth, never on form). The old path funneled every diagram through one renderer and the
owner's verdict on the result was exact: "four different versions of the same process map."
A vertical pill-stack is a LIST wearing a costume; an information shape must dictate its
form. New contract — YOU author each diagram as a standalone SVG file (same output paths:
assets/big-idea.svg, assets/insight.svg, assets/architecture.svg, assets/flow.svg):
- Pick each diagram's ARCHETYPE from the menu and declare it as
data-archetype on the
root <svg> AND in visuals.<slot>.archetype: journey (something travels and
transforms, left→right) · containment (boxes within boxes, layers) · field (a
population of many small things, a few highlighted) · fan (one radiating to many) ·
tree (hierarchy) · exchange (two sides, a broker between). No two diagrams on one
page may share an archetype — the gate fails repetition.
WIDTH-BUDGET EVERY LABEL (2026-07-15, autonomous-wealth-builder + agentic-kit hero
collisions — both from unmeasured text): before writing any , compute its budget —
monospace ≈ 0.62 × font-size per char, bold sans ≈ 0.55 — and verify the string fits its
container at the DESKTOP COLUMN scale (~45% of natural size), not just the full-size stage.
Two same-lane labels need ≥12px gap at column scale. Style micro-labels lowercase with
letter-spacing (caps-styled words like DISK/AGENT trip the INV-20 acronym gate).
- The flow diagram must SHOW the thesis motion, not name stages. For a repo whose trick
is spatial ("the key never leaves the vault"), the invariant must be VISIBLE: the request
dot travels the full journey while the key glyph stays pulsing inside the vault boundary.
If a stranger can't see the trick happen, it's a list of stages — rejected.
- Animate INSIDE the SVG (CSS keyframes / SMIL in a
<style> block — no external JS;
honor prefers-reduced-motion with a static end-state). The data-flow diagram IS the
page's animation. A dot crawling along a dotted line is NOT animation of the argument —
it is the banned decoration (see heroAnim rules) in diagram form.
- Craft bar: real
<text> (≥13px at rendered size), <title> + <desc> accessibility
fallback, viewBox set, palette from concept, validate every file with
xmllint --noout before installing. Budget ≤60KB per SVG.
- THE ENGINE DUEL (flagship diagrams: big-idea + flow): author your version, then
request a competing standalone SVG from GPT-5.6-Sol via the OpenAI API (same brief, same
archetype + palette constraints — plain
curl with $OPENAI_API_KEY; benchmarks show
Sol is genuinely strong at UI polish). Judge both with the same vision model the gate
uses, on takeaway + legibility + craft; install the winner and record
visuals.<slot>.engine = fable|sol with one line of why. If the Sol call fails,
proceed with yours — never block the build on the duel.
- Fallback, loud: if your bespoke SVG fails xmllint or legibility twice, fall back to
make-diagrams for that slot and say so in visuals.<slot>.fallback — a working plain
diagram beats a broken beautiful one, but the fallback is an admission, not a choice.
-
The prior make-diagrams path below remains ONLY as that fallback — the big-idea
diagram, the "aha" insight, and the two diagrams that are MANDATORY on every explainer
(INV-18 — the three questions every developer asks):
- an ARCHITECTURE diagram (how is it constructed — modules / components /
dependencies), built from
<slug>-dep-graph.json + <slug>-symbols.json, and
- a PROCESS / DATA-FLOW diagram (how does it work — the runtime flow),
built from
<slug>-entrypoints.json.
Both are grounded in the repo's REAL structure, never invented. You author the
ASCII (it already fell out of S3); make-diagrams converts to crisp, accessible,
xmllint-clean SVGs. These SVGs are emitted once and reused by both the page AND
the README (S8b) — author once, share.
-
A DIAGRAM MUST CARRY INFORMATION, OR IT MUST NOT BE DRAWN (2026-07-12 — the deepest
quality bug this pipeline has had). "Grounded in the repo's real structure" is necessary,
not sufficient: it is entirely possible to draw a truthful picture of nothing. chalk,
stronghold, agenticow and ternlight each shipped a gorgeous, animated "N modules · 0
internal links" dependency map — a diagram of an empty graph — because the renderer drew
whatever the graph handed it and nobody asked whether the graph said anything. Two rules
now enforced in make-diagrams:
- Trivial dep-graph (0 internal edges) → the dependency map is REFUSED (loud fail). You
must author
visuals.architectureDiagram.rows: the concept of how the thing is
built — the 3-4 parts a reader must hold in their head — not the package wiring.
- The flow diagram is the RUNTIME data-flow — what happens to the reader's data —
authored as
visuals.flowDiagram.rows. If you leave it unauthored, the tool falls back
to the install→build→run→test model and honestly retitles it "Build & run lifecycle",
because that is what it is. Shipping a build lifecycle captioned "Data-flow pipeline" is a
lie the vision grader has caught repeatedly. Author the real flow.
rows shape (a footgun — read this): renderConcept stacks items vertically and draws a
connecting arrow only between items within the same row. So a connected chain is ONE
row of N items, not N rows of one item (that renders as floating cards with no arrows — a
bulleted list, not a structure):
"rows": [{ "items": ["your sentence", "tokenizer", "add · skip · subtract", "384 numbers"], "connect": true }]
-
THE HERO ANIMATION (visuals.heroAnim) — motion that PERFORMS the argument. Author this for
every repo that has a "trick" (almost all of them do). It renders above the fold as a 9s loop and
it is the only motion on the page. Animate the ARGUMENT, never the chrome. Crawling dashed
lines and pulsing dots are decoration; they were shipped twice and correctly called "the weakest
sauce I've seen". What earns its place is the project's one idea, performed: for ternlight, the
model's messy decimal weights (0.0731, −1.24) snap to exactly 0 / −1 / +1; as each
lands, the word beneath it appears — skip · subtract · add; then the multiply sign is struck
through and goes dark: never used.
The shape is deliberately generic — a BEFORE → AFTER transformation, plus the cost it kills —
because that is the shape of most interesting repos' tricks, not a ternary-specific one:
"heroAnim": {
"label": "The numbers inside the model",
"chips": [{ "before": "0.0731", "after": "0", "op": "skip", "kind": "zero" },
{ "before": "−1.24", "after": "−1", "op": "subtract", "kind": "neg" },
{ "before": "3.90", "after": "+1", "op": "add", "kind": "pos" }],
"verdict": { "label": "The one expensive move", "symbol": "×", "dead": "never used" },
"kicker": "it never multiplies — and that is why it fits in 4.6 MB"
}
Rules: 3–6 chips. kind ∈ zero|neg|pos (drives colour). Sentence case, never ALL-CAPS — the
deterministic INV-20 acronym gate reads an uppercase word as an acronym and will fail the build
before the vision pass. No heroAnim → no animation band, and the tool will NEVER substitute
another repo's (this content is per-repo and lives in build.json, never in the tool).
THE CHIPS BAND IS THE FLOOR, NOT THE CEILING (2026-07-13 — owner's verdict on a shipped
chips band: "the animation is nothing more than a dotted line. That's worthless. You
punted."). For any repo whose trick is spatial or mechanical (most), author a bespoke
animated SVG SCENE instead (visuals.heroAnim.sceneSvg → assets/hero-scene.svg, same
in-SVG CSS/SMIL rules as INV-23): a 6–10s loop in which the mechanism VISIBLY HAPPENS — for
a credential broker, the request plug travels the switchboard and returns with a result
while the key never crosses the vault line; for a quantizer, the messy weights snap to
three states. The chips band is the fallback for repos whose trick is genuinely abstract.
Banned as "performance": a dot moving along a path, pulsing glows, crawling dashes — motion
must CHANGE something the argument depends on (a value, a position across a boundary, a
state), not merely travel.
-
Cue: every raster image is valid + HTTP 200, every structural SVG
renders crisp with its accessible text fallback, and each visual answers its
assigned arc question at the right altitude (high → low). A visual that is
pretty but answers nothing fails Gate B5 later — catch it here. If either the
architecture or the flow diagram is missing, the build is not done (INV-18).
Station 5 — BRAND & SOCIAL (starts the moment the hero returns)
- Do: From the hero's visual identity (same metaphor/palette) produce the
brand kit: (a) a full favicon set (hero-derived favicon +
apple-touch-icon
- standard sizes), (b) a designed 1200×630 social card with the authored
tagline baked in (drives OG/Twitter
summary_large_image and og:description).
- Tools:
node tools/make-favicon.mjs <build-dir> and
node tools/make-social-card.mjs <build-dir> (both run alongside the rest of S4).
- Cue: valid favicon files AND a valid 1200×630 social card. A missing
or invalid favicon or social card stops the build loud — never substitute
a default. The card's delight + craft are judged at the gate (B5).
Station 6 — ASSEMBLE + PACK (the page is rendered ONCE)
- Precondition (fail loud).
<slug>-primer.md AND the three structured JSONs
MUST already exist (S1). If the primer is missing, stop loud and return to
Station 1 — never synthesize a placeholder to get past make-dropin.mjs's
line-79 must().
- Do (a) — render the page once:
node tools/assemble-page.mjs <build-dir>.
This composes concept + content + visuals + brand onto the shared
assets/design-system/design-system.css skeleton + the per-repo theme, wires the
full SEO + social <head> (<title>, meta description, canonical, JSON-LD
SoftwareApplication/SoftwareSourceCode, favicon links, OG + Twitter
summary_large_image pointing at the S5 card), emits root-level sitemap.xml,
robots.txt, and llms.txt, inlines the primer in the download section, and
injects the mandatory ISOvision attribution + CTA footer verbatim (see below).
No string markers (INV-10).
- Do (b) — build the AI pack:
node tools/make-pack.mjs <build-dir>. This wraps
kb/make-dropin.mjs via its --no-studio variant (studio-less first — the one
acknowledged engine change; studio media re-packs later, INV-03). The pack ships
the for-ai/ half (<slug>-kb.rvf + idmap + embed sidecar + .passages.jsonl +
.ids.json + the three structured JSONs + ask-kb.mjs + kb-mcp-server.mjs
package.json declaring @ruvector/rvf@^0.2.2 + @xenova/transformers@^2.17.2)
and the for-humans/ half (the authored primer).
- Cue: zero dangling refs or unresolved tokens in the page; the pack opens,
the KB loads, and
node ask-kb.mjs <slug> "…" returns real passage TEXT (not
{id,distance}); the MCP server's lookup_symbol, get_entrypoints,
get_dep_graph each return real data (proving the three JSONs shipped); the
primer is present in for-humans/; and the SEO presence check passes
(<title> + meta description + canonical + JSON-LD + OG/Twitter + favicon links +
sitemap.xml + robots.txt + llms.txt all present + well-formed) — or the
station stops loud. The AI pack is a hard deliverable (INV-07).
The ISOvision footer is mandatory on EVERY explainer. assemble-page injects
it verbatim (design-system §16b). Two lines, always, in order: (1) "Built by
Stuart Kerr at ISOvision.ai" (ISOvision.ai → https://isovision.ai);
(2) the CTA "Want an explainer for your own repo? Create one →" →
https://repoexplainer.isovision.ai. Semantic <footer role="contentinfo">,
real <a> links, on-brand tokens, AA contrast, responsive. If it is missing, the
page is not done.
Station 7 — QUALITY GATE ⟲ (the completion criterion — judged on real pixels)
-
Do: node tools/quality-grade.mjs <build-dir>. It renders the assembled
site LOCALLY in a real browser (Playwright — live pixels, not a deployed
URL; there is no pre-grade deploy), takes full-page screenshots at 390px
(mobile) and 1440px (desktop), and vision-scores them against the verbatim
Gate A/B rubric as a harsh critic, returning two scorecards with per-criterion
rationales citing what it SAW.
Gate A — "do they actually get it?" (substance, each 0–100): A1 visual
effectiveness · A2 storytelling · A3 clueless→convinced · A4 usefulness-to-ME ·
A5 arc completeness · A6 implementation-confidence (knows what to run, what they'll
SEE, the steps, what's next — INV-19).
Gate B — "did someone who gives a shit make this?" (craft / anti-slop, each
0–100): B1 typography & hierarchy · B2 alignment & grid · B3 spacing & rhythm ·
B4 strength & polish (vs generic AI slop) · B5 imagery craft — including the
structural SVGs (crisp, legible, genuinely explanatory) and the 1200×630 social
card (on-brand, inviting, tagline legible).
The OPERATOR QUALITATIVE GATE — six YES/NO questions (the owner's words), ALL must be YES or you
loop: (1) Would this make me believe I understand this? (2) Would this make it approachable?
(3) Would this explain it for somebody who doesn't understand it? (4) Would it give me confidence I
understand the architecture? (5) Does it make me smile — "oh, that's cool"? (6) Could someone who
knows nothing about this domain read the first four sections and explain the problem and the
solution back to me? (ADR-0006 D4 — the critic answers (6) role-playing a smart developer from a
DIFFERENT domain.) These are independent of the numeric axes; a page can clear the numbers and
still fail one of these. INV-20 (deterministic, free): any acronym in the first four sections
without a plain-words gloss at first use fails the gate before the vision pass even runs.
-
The bar + the loop (non-negotiable — iteration over a few revs is EXPECTED, not a failure):
- BAR: on BOTH devices, mean ≥ 90 AND min axis ≥ 85 AND all six operator questions YES
(11 axes × 2 devices). The min ≥ 85 is the anti-slop floor — a single slop axis (a raw-ASCII
diagram, a pretty-but-empty image) scores ≈50 and fails the build. Anchored to the owner's own
example sites (~88 headline / ~92 mean); a build that clears the bar is reported as a normalized 95.
headlineScore = the MINIMUM across all axes (the anti-slop floor); meanScore = the mean
(the "as good as the examples" measure). Both gate; the mean is not ignored.
- RUN THE REFINE LOOP: any axis below the bar OR any operator NO → the gate names the exact
weakness (which criterion / which question, which device, what it saw) → you refine just
that, surgically (a B1 typography miss re-opens
page; an A4 "not useful to me" miss re-opens
content; an A6 / B5 / diagram miss re-opens visuals) → re-assemble (assemble-page) →
re-grade (quality-grade) → LOOP until it clears on both devices. Touch only the named
weakness — never a broad reflow that could regress a passing axis.
- If the grader returns malformed / missing / non-per-criterion scores, the gate
stops loud and does not pass — a broken grader is never a silent green.
- Post-cap protocol (the cure lane — hosted builds): the tool enforces a hard cap of 3
quality-grade calls. If the FINAL grade still fails the ship gate on a named weakness you
can fix: apply that one surgical fix, re-run
assemble-page, and write a short factual note of
exactly what you fixed and why it addresses the named weakness to quality.postCapManualFix
in build.json — then end the run without deploying. The runner (trusted code outside your
process) spends exactly ONE fresh verification grade on a documented fix and deploys through
the same ship-bar rail if it now passes. Never bypass the rail; document and stop. (Even
without a documented fix, the runner classifies a near-miss ending deterministically and may
run a bounded cure itself — but an in-run fix you document is faster and cheaper.)
-
Honesty escape hatch: if a repo genuinely cannot reach the bar on some axis,
flag it honestly in the result and the email. Never ship slop and call it
done. Two pre-ship eyes gate S7: the vision model and you (the
operator), viewing the same screenshots, both agreeing, with mean ≥ 90, min ≥ 85, and all
six operator questions YES on both devices. The owner is the post-delivery third eye (S9) —
owner rejection re-opens this same surgical loop.
-
Cue: mean ≥ 90 AND min axis ≥ 85 AND all six operator questions YES on BOTH devices, or an
honest flag. Only an already-great page proceeds to deploy.
Station 8 — PUBLISH / DEPLOY (+ repo SEO) — the FIRST and only deploy
- Do: Create the dedicated explainer GitHub repo (public), invite the owner
as a collaborator (best-effort), and deploy the already-passed page to its own
per-build URL.
- Tools (run all three):
node tools/publish-repo.mjs <build-dir> — creates the explainer repo +
invites the owner.
node tools/deploy.mjs <build-dir> — deploys to its own per-build URL.
Default provider: Netlify (clean auto {repo}-explainer.netlify.app URL,
zero DNS work, git-connected auto-redeploy so the owner's later edits redeploy
themselves). The adapter is provider-agnostic — Vercel is a one-line swap.
node tools/repo-seo.mjs <build-dir> — sets GitHub topics + a strong
description on the explainer repo (GitHub is the new AI-world social
media), and emits suggested topic/description improvements for the source
repo (offered, never set directly — INV-16).
- Cue: live URL returns 200 unauthenticated, the repo is public, the
owner is invited, and the explainer repo has topics + a description set
(verified via the GitHub API). An invite/SEO failure degrades to a warning — it
never inverts a live, graded build.
Station 8b — README ENHANCEMENT (OPTIONAL — offered, source-repo PR only)
- Do: Offer to enhance the source repo's README via
node tools/readme-enhance.mjs <build-dir> (wraps the readme-enhance skill): an
architectural explanation, the shared Station-4 SVG diagrams (reused, not
re-authored), and an explainer badge linking to the live explainer. May also
carry the Station-8 source-repo topic/description suggestions.
- Cue: delivered ONLY as a PULL REQUEST on the source repo (never a direct
push — INV-16); the author merges or skips. It is OPTIONAL, off the critical
path, quarantined (INV-03), and NEVER blocks the core ship. If declined, it is a
clean no-op; a failure is a warning only.
Station 9 — NOTIFY
- Do:
node tools/notify.mjs <build-dir> — return the result inline and
email the owner the scorecard + both screenshots + links (live URL, explainer
repo, pack) plus, when present, the README-PR link and the suggested
source-repo topics/description, so the owner can act on the optional offers and
be the third eye.
- Cue: send confirmed (SMTP 250). A notify failure degrades to a warning —
it never inverts a live, graded, deployed build (INV-04).
Parallelism (speed without coupling)
Scheduling only — it never lets one station read another's files; everything lands
in its BuildContext slot.
- S4 raster images all fire at once — internally, inside ONE
generate-image
call (bounded concurrency in the tool itself, not multiple parallel processes —
see Station 4 above).
- The structural SVGs are authored during S3 (their ASCII falls out of
authoring) and converted in parallel with the raster generation — not after it.
- Favicon + the 1200×630 social card (S5) start the moment the hero returns,
overlapping the rest of S4.
- The AI pack builds as soon as S1's KB exists — it overlaps S2 + S3.
- The README PR (S8b) and any studio/long-async step are quarantined (INV-03):
optional, off the critical path, after deploy, never block the core ship.
Invariants you personally enforce
- INV-04 Never-fail-silently — every station has a loud cue; no placeholder,
default, or stub past a failure.
- INV-05 Never-ship-below-the-exemplar-bar — on both devices, mean ≥ 90 AND min axis ≥ 85 AND all
six operator questions YES IS the completion criterion (a clearing build is reported as a normalized
95); below it, refine or flag honestly.
- INV-06 Grounded-in-KB — no claim without a real RVF KB passage; never a JSON
stand-in.
- INV-07 Ships-the-pack — every explainer ships the downloadable AI pack
(
.passages.jsonl present so search returns text; the three structured JSONs
present so all four MCP tools return data).
- INV-08 One-source-of-truth — this skill is the only brain; the plugin, npx
CLI, and website all run the identical core.
- INV-16 Source-repo-via-PR-only — any touch to the source repo (README
enhancement, SEO suggestions) is offered and delivered ONLY as a pull request.
- INV-18 Architecture + flow diagrams mandatory — every explainer ships both
an architecture diagram and a process/data-flow diagram, as crisp SVGs grounded
in the repo's real structure; missing either means the build is not done.
- INV-19 Implementation-experience present — the Get-Started section shows the command, what the
reader will SEE when they run it, the steps, what they get, what's next, and prerequisites — never a
bare "just run this." Scored as A6.
- INV-21 Source-identity — the explainer describes the exact submitted repo; an
inaccessible repo stops the build loudly with an actionable message. Never a substitute,
never a lookalike, never content reconstructed from search results or a remote README.
- Mandatory ISOvision footer — the credit + "create one" CTA footer ships on
every page, verbatim.
"Done" = real screenshots; on both devices mean ≥ 90, min axis ≥ 85, and all six operator questions
YES (reported as a normalized 95); the two pre-ship eyes agree; the page is live; and the AI pack ships.
If a stranger doesn't smile — or a newcomer can't follow the first four sections — it isn't finished.