Every diagram that lands in a document follows one shape: a text DSL source beside the document and a committed SVG rendered from it. This skill picks the tool, applies the house palette, and produces both artifacts so the image carries on github.com.
Pick the tool
Reach up the table only when the default cannot carry the domain. The default is the first row.
| Purpose |
Tool |
| Structure, class, relations, small-to-medium flow, state, timeline |
nomnoml (default) |
| Architecture, system, module dependencies, container maps |
D2 |
| Very large dense DAG, hundreds of nodes |
Graphviz DOT |
| Byte, bit, or on-disk layout |
bytefield-svg |
| Quantitative chart, only with sourced real figures |
Vega-Lite |
Author it
Five steps, each with a checkable done condition.
- Choose the shape. A comparison, trade-off, or decision matrix is a Markdown table. For a quantitative comparison whose real numbers cannot be sourced, a table is the required form, not a chart. Done when the choice between table and diagram is made and stated.
- Write the source into
assets/<kebab-slug>.<ext> beside the document that will embed it, opening with the house header below when the tool is nomnoml. Done when the file exists on disk and, for nomnoml, the header is the first block in it.
- Render with the matching command under Render commands. Done when the command exits zero and the SVG exists beside its source.
- Embed as
 followed directly by a one-line > caption carrying the key message. Done when both lines are present, the alt text is a label rather than the word "diagram", and the caption states what the image means rather than restating its title.
- Commit source and SVG together. Done when both paths are staged. Never commit one without the other; the pair is the contract.
House header
Open every nomnoml source with this header verbatim. It sets direction, background, spacing, stroke, and the named styles accent, blue, green, neutral, and ghost.
#direction: right
#background: #fcfcfc
#fill: #ffffff
#stroke: #2b2b2b
#spacing: 36
#padding: 12
#fontSize: 13
#lineWidth: 2
#.accent: fill=#fce9df stroke=#f15d22 title=bold
#.blue: fill=#e6f5f7 stroke=#48b9c7 title=bold
#.green: fill=#e9f5ee stroke=#73c48f title=bold
#.neutral: fill=#f0f0f0 stroke=#808080
#.ghost: fill=#f0f0f0 stroke=#808080 dashed
D2 uses --theme 0; its palette is set by the same hex values in the source where the theme allows it.
Layout
Source and rendered SVG are siblings in assets/ beside the document that embeds them, both kebab-case, both committed. A document at docs/x.md gets docs/assets/<slug>.noml and docs/assets/<slug>.svg, so the relative embed assets/<slug>.svg stays correct. Keep the path relative; an absolute path breaks on github.com.
Example

> A draft needs one reviewer; anything touching billing needs two.
The source that produced it lives at assets/approval-path.noml and is committed with the SVG. Alt text is a label for what the image shows, never the word "diagram".
Render commands
npx -y nomnoml@latest assets/<slug>.noml assets/<slug>.svg
d2 --theme 0 assets/<slug>.d2 assets/<slug>.svg
dot -Tsvg assets/<slug>.dot -o assets/<slug>.svg
A non-zero exit means the source is wrong. Fix the source; an unrendered diagram does not ship. When neither binary is present, say so and name the install command rather than emitting source nobody can see.
Rules
- One focal element per diagram, carrying
accent. Everything else takes blue, green, neutral, or ghost.
- Keep to the palette above and leave red out entirely, red-with-green most of all.
- Encode meaning twice: colour plus shape plus a direct label. Direct labels beat a legend.
- Labels sit inside the nodes, and a diagram that stands alone is left to stand alone rather than paired with prose restating it.
- Ship an explicit light background inside the SVG. A GitHub
<img> does not propagate prefers-color-scheme.
- Meet contrast: non-text at least 3:1, text at least 4.5:1.
- Real figures only. A chart with invented numbers is a table with real ones instead.
- Text DSL and a committed SVG is the shape this contract recognises. Where a surface renders mermaid natively and has no committed asset to link — a GitHub PR body is the one such case — that surface is outside this contract and says so at its own site.
1---2name: diagram-contract3description: Use when a diagram is going into a document: pick the tool, write the text source, render it, and embed it with an accessible caption. Text DSL plus a committed SVG is the shape — nomnoml for structure and flow, D2 for architecture, the house palette on both.4---5
6Every diagram that lands in a document follows one shape: a text DSL source beside the document and a committed SVG rendered from it. This skill picks the tool, applies the house palette, and produces both artifacts so the image carries on github.com.
7
8## Pick the tool
9
10Reach up the table only when the default cannot carry the domain. The default is the first row.
11
12| Purpose | Tool |
13|---|---|
14| Structure, class, relations, small-to-medium flow, state, timeline | **nomnoml** (default) |
15| Architecture, system, module dependencies, container maps | **D2** |
16| Very large dense DAG, hundreds of nodes | Graphviz DOT |
17| Byte, bit, or on-disk layout | bytefield-svg |
18| Quantitative chart, only with sourced real figures | Vega-Lite |
19
20## Author it
21
22Five steps, each with a checkable done condition.
23
241. **Choose the shape.** A comparison, trade-off, or decision matrix is a Markdown table. For a quantitative comparison whose real numbers cannot be sourced, a table is the required form, not a chart. Done when the choice between table and diagram is made and stated.
252. **Write the source** into `assets/<kebab-slug>.<ext>` beside the document that will embed it, opening with the house header below when the tool is nomnoml. Done when the file exists on disk and, for nomnoml, the header is the first block in it.
263. **Render** with the matching command under [Render commands](#render-commands). Done when the command exits zero and the SVG exists beside its source.
274. **Embed** as `` followed directly by a one-line `>` caption carrying the key message. Done when both lines are present, the alt text is a label rather than the word "diagram", and the caption states what the image means rather than restating its title.
285. **Commit source and SVG together.** Done when both paths are staged. Never commit one without the other; the pair is the contract.
29
30## House header
31
32Open every nomnoml source with this header verbatim. It sets direction, background, spacing, stroke, and the named styles `accent`, `blue`, `green`, `neutral`, and `ghost`.
33
34```text
35#direction: right
36#background: #fcfcfc
37#fill: #ffffff
38#stroke: #2b2b2b
39#spacing: 36
40#padding: 12
41#fontSize: 13
42#lineWidth: 2
43#.accent: fill=#fce9df stroke=#f15d22 title=bold
44#.blue: fill=#e6f5f7 stroke=#48b9c7 title=bold
45#.green: fill=#e9f5ee stroke=#73c48f title=bold
46#.neutral: fill=#f0f0f0 stroke=#808080
47#.ghost: fill=#f0f0f0 stroke=#808080 dashed
48```
49
50`D2` uses `--theme 0`; its palette is set by the same hex values in the source where the theme allows it.
51
52## Layout
53
54Source and rendered SVG are siblings in `assets/` beside the document that embeds them, both kebab-case, both committed. A document at `docs/x.md` gets `docs/assets/<slug>.noml` and `docs/assets/<slug>.svg`, so the relative embed `assets/<slug>.svg` stays correct. Keep the path relative; an absolute path breaks on github.com.
55
56## Example
57
58```markdown
59
60
61> A draft needs one reviewer; anything touching billing needs two.
62```
63
64The source that produced it lives at `assets/approval-path.noml` and is committed with the SVG. Alt text is a label for what the image shows, never the word "diagram".
65
66## Render commands
67
68- `npx -y nomnoml@latest assets/<slug>.noml assets/<slug>.svg`
69- `d2 --theme 0 assets/<slug>.d2 assets/<slug>.svg`
70- `dot -Tsvg assets/<slug>.dot -o assets/<slug>.svg`
71
72A non-zero exit means the source is wrong. Fix the source; an unrendered diagram does not ship. When neither binary is present, say so and name the install command rather than emitting source nobody can see.
73
74## Rules
75
76- One focal element per diagram, carrying `accent`. Everything else takes `blue`, `green`, `neutral`, or `ghost`.
77- Keep to the palette above and leave red out entirely, red-with-green most of all.
78- Encode meaning twice: colour plus shape plus a direct label. Direct labels beat a legend.
79- Labels sit inside the nodes, and a diagram that stands alone is left to stand alone rather than paired with prose restating it.
80- Ship an explicit light background inside the SVG. A GitHub `<img>` does not propagate `prefers-color-scheme`.
81- Meet contrast: non-text at least 3:1, text at least 4.5:1.
82- Real figures only. A chart with invented numbers is a table with real ones instead.
83- Text DSL and a committed SVG is the shape this contract recognises. Where a surface renders mermaid natively and has no committed asset to link — a GitHub PR body is the one such case — that surface is outside this contract and says so at its own site.