Show every diagram as a picture drawn from its Mermaid source, because the GitHub app draws no Mermaid¶
- Status: accepted
- Date: 2026-10-13
Context¶
The documentation of the blueprint and of every repository made from it explains with diagrams: 26 in the blueprint, about 81 in the five repositories. They were Mermaid in a mermaid block of the Markdown, which github.com and the website draw. The GitHub app for iOS and Android doesn't: it shows the source as code, as a screenshot of the README of paperless-unified-search in the iOS app showed on 2026-10-13. Neither do the other places where a README is read: HACS, the Nextcloud App Store, PyPI, the GitHub Marketplace, the notification e-mails and editors without an extension for Mermaid. Every renderer of Markdown shows a picture.
Options¶
- Keep the
mermaidblocks. Nothing to do, and the readers outside github.com go on seeing code. - Pictures drawn by hand, or exported from an editor. They show everywhere, but nothing keeps them in step with what they explain, a second language doubles the work, and a review sees only that a binary changed.
- The Mermaid source in a file of its own, and pictures that a script draws from it with the official mermaid-cli, checked in the CI and committed by a bot.
- A service that draws Mermaid on request, such as mermaid.ink, linked as an image. The pictures follow the source, but every reader asks a service outside GitHub, and the README breaks when it is down.
Decision¶
Option 3. A diagram is a source in docs/diagrams/<name>.mmd, <name>.de.mmd for a German page. scripts/diagrams.sh, which the blueprint keeps current in every repository, draws it in the image of mermaid-cli, pinned by its digest, which Renovate keeps current, as docs/images/diagrams/<name>.svg on a white card and <name>.dark.svg on the background of GitHub's dark theme. The Markdown shows them with a <picture>, with the title and the description of the diagram, accTitle and accDescr, as the text for screen readers.
---
config:
flowchart:
wrappingWidth: 400
---
flowchart TB
accTitle: How a diagram reaches every reader
accDescr: A diagram is a Mermaid source in docs/diagrams/. scripts/diagrams.sh draws it with mermaid-cli in Docker as an SVG picture for the light and one for the dark theme, which the Markdown shows with a picture element, so that the GitHub app, the stores, e-mails and github.com all show it. The website draws the source itself, live. In a pull request that changes a diagram, the check diagrams draws the pictures anew, and the diagram bot commits those that differ.
you(["You"])
source["`**docs/diagrams/NAME.mmd**<br>Mermaid, from top to bottom<br>accTitle · accDescr`"]
draw["scripts/diagrams.sh<br>mermaid-cli in Docker<br>without network"]
pictures["docs/images/diagrams/<br>NAME.svg · NAME.dark.svg"]
readers["README and docs/ with a picture<br>the GitHub app · github.com<br>HACS · App Store · PyPI · e-mails"]
website["The website<br>draws the source live"]
check{"The check diagrams:<br>the same pictures?"}
bot(["Diagram bot<br>commits the pictures"])
you -- "writes" --> source
source --> draw --> pictures --> readers
source -- "the hook of MkDocs" --> website
source -. "a pull request" .-> check
check -- "no, on a branch<br>of the repository" --> bot
bot -.-> pictures
classDef bot fill:#526cfe2e,stroke:#526cfe,stroke-width:2px
classDef person fill:#f59e0b2e,stroke:#f59e0b,stroke-width:2px
classDef done fill:#16a34a2e,stroke:#16a34a,stroke-width:2px
class draw,check,bot bot
class you,source person
class readers,website done
- Pictures that every renderer shows: the labels are SVG text, not HTML in a
foreignObject, which many renderers of pictures leave out. So a label breaks a line with<br>alone, and a label in"`…`"takes**bold**and*italic*. The labels are measured with DejaVu Sans, which is wider than the fonts that readers have before it in the list, so that every label fits its box. The light picture has an opaque card, so that it stays readable where an app shows it on a dark background. - The same pictures every time: the container has no network, the shapes with curves get a fixed seed, and the coordinates are rounded to hundredths, so that drawing again changes nothing and a review sees only the diagrams that changed.
- The website draws the source: the hook in
.github/mkdocs_blueprint.pyputs the live Mermaid of the source in place of each picture, in the colors of the theme that the reader switches to, sharp at every size and with text to search. - Checks:
scripts/check.shchecks without Docker that nomermaidblock is left once a page shows a picture of a diagram, that every source that a page shows has both pictures, that every picture has its source, and, with Python, that thealtof every picture repeats theaccTitleandaccDescrof its source, which--extractwrites. Amermaidblock inside another block of code, such as the example of a guide, or in a comment is no diagram, and one in a quote is. The required check diagrams of the Lint workflow runsscripts/diagrams.sh --extracton the head of a pull request that changes a diagram or adds amermaidblock, and fails when that changes a file; any other pull request passes at once, without the large image. - Fix first, explain second: for a pull request from a branch of the repository, the diagram bot, a job of After the checks, commits what the check changed onto the branch, as the release app, so that its checks run again, and names the pages whose blocks became pictures in one comment. It runs no code of the pull request:
blueprint.pyofmaintakes only sources, SVG pictures and pages of Markdown, by plain paths, from the artifact of the check, deletes only pictures, and commits only onto the commit that the check drew. A pull request from a fork keeps the failing check, whose summary lists the files and the command, and whose run holds them as its artifact. A new version of mermaid-cli from Renovate is drawn on its branch the same way. mainheals itself: after every change ofmainthat touches a page or a diagram, and every week, the Diagrams workflow draws every diagram ofmainwithout secrets; after a change that touches no diagram and not the renderer, it only looks for a newmermaidblock, without Docker, because the check of the pull request drew the rest. When a file changes, such as the blocks of a repository right after the update that brings this, or after a merge that went around the check, a second job keeps one pull request frombot/diagramswith the fix, which merges itself, and closes it whenmainis fixed otherwise. It makes each new commit on a branch of its own and then movesbot/diagramsto it, because GitHub closes a pull request whose head is a commit ofmain. A failed run opens an issue, which the weekly run closes once the bot passes again.- Moving existing diagrams:
bash scripts/diagrams.sh --extractturns everymermaidblock into a source, named after itsaccTitle, or after the diagram at the same place of the English page with.de, and its picture, and then draws them. A diagram withoutaccTitletakes the heading above it for its name, and the heading and the labels of its nodes for the text of its picture, so that a migration that merges itself still says what each picture shows. Amermaidblock is only a warning until a page of a repository shows a picture of a diagram, so that the update of the blueprint passes before its diagrams moved. The checks and the script take only the sources that a page shows and those that have a picture already, also afterwards, because a repository may already draw its own sources indocs/diagrams/in its own way.
Consequences¶
Every reader sees the diagrams, in the app and in every store, and the website keeps its live diagrams. A change of a diagram is a change of its source, which a review reads as text, and the pictures follow by themselves on a branch of the repository. Drawing them needs Docker and pulls an image of about 2.4 GB, so the check draws only in a pull request that changes a diagram, and a contributor without Docker leaves it to the bot. The repositories made from the blueprint move their diagrams without a person: after the update that brings this, the Diagrams workflow opens the pull request that does it, and bash scripts/diagrams.sh --extract does the same by hand. The convention of the colors and of accTitle and accDescr stays as CONTRIBUTING.md describes it. A picture is a path from its page, which github.com and the GitHub app follow; HACS and PyPI show a README outside of the repository and don't, so a README published there needs absolute links to its pictures, which the checks and the hook of the website accept as well.