diagram
The facts
Its description
Turn an English description (or mermaid source) into a diagram triplet: the source, an editable .excalidraw file you can open on excalidraw.com, and rendered SVG + PNG. (gstack) Triggers: make a diagram; draw a diagram; create a flowchart; diagram this; visualize this flow; architecture diagram
The description the agent reads to decide when to use it. Phrases the author says should start it.
When it starts
The agent picks this skill when someone asks for a diagram, flowchart, or architecture picture, or asks to visualize a flow, and wants an editable scene plus rendered SVG/PNG rather than a one-off image. The description promises a triplet (mermaid source, editable .excalidraw, SVG + PNG) from an English description or mermaid source.
Things a person might say (the model's guesses)
- “draw a diagram of our auth flow”
- “make an architecture diagram for the new service”
- “can you visualize this flow as a flowchart?”
A model's summary of when it is used.
Tools it may use, or may not
allowed-tools: Bash, Read, Write, AskUserQuestion
Tools it may use while it runs without asking you first.
Runs scripts
bin/gstack-skill-start, bin/gstack-learnings-log, bin/gstack-skill-end, bin/gstack-render.ts
Scripts the text names. Found by matching words, so treat them as pointers.
Stops for a person
3 lines stop to ask a person
Lines that stop and wait for a person before going on. Found by matching words, so treat them as pointers.
What leads to it
- browse is an alternative to this for rendering local HTML into a PNG or PDF browse, line 451
Other skills that hand off to this one, call it, require it or offer it instead, as a model read them.
Licence
MIT, from LICENSE
The terms its author shares it under, which let it be shown here.
The text
Most marks come from matching words in the file, so treat them as pointers.
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly --> <!-- Regenerate: bun run gen:skill-docs -->
Raw lines 1 to 21Boilerplate, lines 22 to 145. The same text appears in 26 other files here. Close
Plan Status Footer
Skills that run plan reviews (/plan-*-review, /codex review) include the EXIT PLAN MODE GATE blocking checklist at the end of the skill, which verifies the plan file ends with ## GSTACK REVIEW REPORT before ExitPlanMode is called. Skills that don't run plan reviews (operational skills like /ship, /qa, /review) typically don't operate in plan mode and have no review report to verify; this footer is a no-op for them. Writing the plan file is the one edit allowed in plan mode.
/diagram — English in, editable diagram out
Every run emits a triplet, never a dead pixel dump:
| Artifact | What it's for |
|---|---|
<slug>.mmd | the mermaid source — the LLM-friendly interchange format |
<slug>.excalidraw | editable scene — open it at excalidraw.com, move a box, keep working |
<slug>.svg + <slug>.png | crisp vector for docs + raster for chat/issues/READMEs |
Rendering is fully offline: the diagram-render bundle (lib/diagram-render/dist/diagram-render.html) is one self-contained page, and gstack-render opens it from a loopback server on this machine — in the Aside browser when Aside is running, otherwise in gstack's own headless browser. Its first output line says which (ENGINE=aside or ENGINE=browse); the triplet is identical either way. No CDN, no network.
Step 1 — Author the diagram
Write mermaid for the user's request. Rules:
- **Flowcharts (
graph LR/graph TD) and sequence diagrams** convert to a fully editable excalidraw scene (real boxes, arrows, and text). Prefergraph LRfor pipelines/flows,graph TDfor hierarchies. - State, class, gantt, and the other mermaid types render to SVG/PNG fine and still get an
.excalidraw, but the converter exports them as ONE image element: it opens at excalidraw.com and can be moved and annotated, not edited box by box. Tell the user that when you deliver one. - Keep node labels short; put detail in edge labels. 5-15 nodes is the readable range. If the user's ask needs more, split into multiple diagrams and say why.
Decide the output directory: ./diagrams/ when the cwd is a git repo (artifacts the user can commit), else /tmp/gstack-diagrams/. Derive <slug> from the diagram's subject (kebab-case, ≤40 chars).
Step 2 — Stage the render bundle (once per session)
gstack-render serves the bundle's directory on 127.0.0.1 for each render (Aside refuses file://, and both engines get the same origin). Stage the bundle under gstack's own render staging directory, ${TMPDIR:-/tmp}/gstack-render (yours alone: if that name is a symlink or another user's directory, a private mktemp -d is used instead), content-addressed by bundle sha: the served directory holds nothing but gstack bundles, and concurrent sessions or mixed gstack versions never clobber each other.
BUNDLE=""
for c in "$HOME/.claude/skills/gstack/lib/diagram-render/dist/diagram-render.html" \
"$(git rev-parse --show-toplevel 2>/dev/null)/lib/diagram-render/dist/diagram-render.html"; do
[ -f "$c" ] && BUNDLE="$c" && break
done
[ -z "$BUNDLE" ] && echo "BUNDLE_MISSING — run: cd ~/.claude/skills/gstack && bun run build:diagram-render" && exit 1
RD="${TMPDIR:-/tmp}/gstack-render"
if [ -e "$RD" ] && { [ -L "$RD" ] || [ ! -O "$RD" ]; }; then RD=$(mktemp -d "${TMPDIR:-/tmp}/gstack-render.XXXXXX"); else mkdir -p -m 700 "$RD"; fi
SHA=$(shasum -a 256 "$BUNDLE" | cut -c1-16)
STAGED="$RD/gstack-diagram-render-$SHA.html"
[ -f "$STAGED" ] && shasum -a 256 "$STAGED" | grep -q "^$SHA" || { cp "$BUNDLE" "$STAGED.$$" && mv "$STAGED.$$" "$STAGED"; }
echo "STAGED: $STAGED"Remember the STAGED: path — every render below opens it (it stands in for <staged>). If BUNDLE_MISSING: stop and show the user the build command. Do not improvise a CDN fallback — offline is the contract.
Step 3 — Render the triplet
Write the mermaid source to <outdir>/<slug>.mmd first (Write tool). ONE gstack-render call renders the whole triplet: it opens the staged bundle in the browser, waits for the page to finish loading (#done), runs the --eval expressions in order inside that page, and writes each result to the --out path that follows it. The page cannot read files itself, so ship the source in via base64 — never splice file contents into a JS template literal (backticks, ${, and backslashes in the source would be interpreted and corrupt it):
SRC=$(base64 < <outdir>/<slug>.mmd | tr -d '\n')
bun --no-env-file --config=/dev/null run ~/.claude/skills/gstack/bin/gstack-render.ts "<staged>" --wait-selector '#done' \
--eval "window.__renderMermaid('diagram-1', atob('$SRC')).then(s => (window.__svg = s))" --out <outdir>/<slug>.svg \
--eval "window.__rasterize(window.__svg, 1950)" --out <outdir>/<slug>.png \
--eval "window.__mermaidToExcalidraw(atob('$SRC')).then(j => (window.__scene = j))" --out <outdir>/<slug>.excalidrawAlways run all three --eval/--out pairs, whatever the diagram type. The PNG is 1950px wide (300dpi of a 6.5in placement). Success prints one OK <path> line per artifact. Read the output for two other lines:
- A hard
ERROR:line (e.g.ERROR: render script did not finish: Error: Parse error on line 4: ...) is a mermaid parse error. Nothing was copied out. Show the error to the user, fix the.mmd, and retry — do not hand the user a broken source file. - A
PAGE_ERRORS=[...]entry containingError processing Mermaid diagrammeans the excalidraw converter fell back to a single image element (Step 1's state/class/gantt case). The triplet is complete and correct; deliver the.excalidrawanyway with the note that it is not element-editable. Any OTHERPAGE_ERRORStext: read it before trusting the output.
Note: atob() yields Latin-1; for sources with non-ASCII labels use decodeURIComponent(escape(atob('…'))) to recover UTF-8 exactly.
gstack-render picks the browser itself: Aside when it is running, otherwise gstack's own headless browser. Only when it prints NEEDS_ASIDE or ASIDE_NOT_RUNNING followed by ERROR: no browser available is there nothing to render with — Aside (macOS 15+, aside.com) is not open and gstack's browser is not built. Tell the user to open Aside, or to run ./setup in the gstack repo to build the fallback, and stop. Never install Aside for them, and never substitute a CDN or another renderer.
Step 4 — Show and deliver
- Read the PNG with the Read tool so the user sees the diagram inline.
- List the triplet paths.
- One-line editability note: "The
.excalidrawfile opens at excalidraw.com (File → Open) — edit it there and I can re-render from the edited scene." - If the user wants changes, edit the
.mmdsource and re-run Step 3 — the source is the single source of truth.
Re-rendering an EDITED .excalidraw (user round-trip): load the scene file and export without touching the mermaid — base64 transport again, since scene JSON is full of quotes and backslashes:
SCENE=$(base64 < <outdir>/<slug>.excalidraw | tr -d '\n')
bun --no-env-file --config=/dev/null run ~/.claude/skills/gstack/bin/gstack-render.ts "<staged>" --wait-selector '#done' \
--eval "window.__excalidrawToSvg(atob('$SCENE')).then(s => (window.__svg = s))" --out <outdir>/<slug>.svg \
--eval "window.__rasterize(window.__svg, 1950)" --out <outdir>/<slug>.pngThis path prints one benign PAGE_ERRORS entry — excalidraw's font subsetter falls back from a worker to the main thread inside the single-file bundle (WorkerInTheMainChunkError). The SVG/PNG are correct; ignore that one.
Rules
- Never ship the triplet without rendering it. A
.mmdfile alone is not a diagram. If rendering is impossible (bundle missing, no browser available), say so and stop. - For diagrams destined for a PDF: remind the user that
make-pdfrenders`mermaidfences natively — embedding the.mmdin their markdown is better than embedding the PNG.
Completion status
- DONE — triplet delivered and shown (with the image-only note for non-flowchart, non-sequence types).
- BLOCKED — bundle missing or no browser available; the build command, "open Aside", or "run ./setup" surfaced.
From garrytan/gstack at 3f79d81, 2026-11-01. Skills read by DeepSeek V4.1 Flash on 2026-11-04. Summary and techniques by Claude Opus 5.5 on 2026-11-06.