agentleFS
eisbaweisbaw/mped-skills/skills/drawio-figure-reviewer/SKILL.md

drawio-figure-reviewer

Skill11 starsChanged 3 months agoMITView on GitHub

Review or author a draw.io / diagrams.net .drawio file. Catches the silent failure modes the GUI doesn't tell you about - reserved cell IDs, double-escape requirements for `<` and `>`, scroll-offset traps that make the file look empty, edges that cross through intermediate nodes. Use when authoring a new diagram, debugging "my drawio file is empty / won't export", or reviewing one for clarity.

The file

We split this skill into the rules it gives an agent

6 rules. About 0 are common, 5 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈5

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Run the symptom-to-rule lookup:

    line 136
  2. Distinctive:

    When the bisect points at one or two cells, inspect their IDs against the reserved-name list.

    line 158
  3. Distinctive:

    Use separate files when:

    line 233
  4. Very specific:

    If splitting into separate files: keep filename prefix consistent (dataflow-scan.drawio, dataflow-locate.drawio, ...) so they sort together …

    line 238
  5. Distinctive:

    When reviewing, be specific and concrete: point at the cell ID, the line number, the exact rule.

    line 242
  6. Distinctive:

    When pushing back on a request ("split this monolith"), explain *why* the current is crowded (count nodes/edges, identify the dense region) …

    line 244

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

drawio Figure Reviewer

drawio files are XML, easy to author programmatically — and full of silent failure modes the GUI does not flag. CLI export and the GUI app disagree on what's a fatal problem; some bugs only manifest in one of the two. This skill captures the known traps.

The five hard-won rules

  1. dx="0" dy="0" on mxGraphModel when authoring programmatically.
  2. Never use reserved SVG/HTML element names as cell IDs (filter, mask, defs, style, script, g, path, clipPath, linearGradient, radialGradient, ...).
  3. Double-escape < and > in cell values and edge labels: &amp;lt; / &amp;gt; (not &lt; / &gt;).
  4. Don't park a node on the straight line between two other nodes that have a direct edge — the edge will pass through it visually.
  5. Verify via CLI export AND by opening in the GUI app. They mask different bugs.

When to use

  • User asks to "make a drawio diagram of X" or to author one programmatically.
  • User says "the drawio file is empty / won't open / won't export" — these symptoms map to specific rules above.
  • Reviewing an existing .drawio for clarity and correctness.
  • Splitting a crowded monolithic diagram into per-aspect tabs/files.

The pitfalls, in detail

Rule 1 — dx/dy are scroll offsets, not metadata

<mxGraphModel dx="0" dy="0" ...>

dx/dy are the saved scroll position of the viewport. When drawio opens the file, it scrolls to that position. If you wrote a programmatically-large value (e.g. dx="1700" dy="1100") and your content sits at small coordinates, the GUI shows a blank canvas — the content is fine, the viewport is parked off it.

Symptoms: file opens, canvas appears empty, but drawio -x -f png -o out.png file.drawio still produces a non-empty PNG.

Fix: set dx="0" dy="0" for hand-authored / scripted files. When the user saves from the GUI, drawio writes whatever scroll position they last had — that's fine because they were viewing real content.

Rule 2 — reserved IDs silently break CLI export

Symptoms: drawio -x -f svg -o out.svg file.drawio produces no output and prints Error: Export failed: file.drawio. GUI may still render the file fine.

Cause: drawio's export pipeline emits SVG, and cell IDs become element IDs. Collisions with SVG/HTML reserved element names break the export. Confirmed-bad IDs include:

filter   mask   defs   style   script   g   path   clipPath
linearGradient   radialGradient   text   image   use   symbol

Probably others (full list is the SVG element registry; safest assumption is "avoid any name that's also an HTML or SVG tag").

Fix: rename to a non-reserved synonym (e.g. filter → filt, mask → mask1, path → path_box). The cell's value (what's displayed) can stay as the human name — only the id="..." attribute matters.

To audit a file:

grep -oP 'id="[a-zA-Z][a-zA-Z0-9_-]*"' file.drawio | sort -u

Cross-reference against the SVG element registry: https://developer.mozilla.org/en-US/docs/Web/SVG/Element.

Rule 3 — <T> in cell text gets eaten

Symptoms: a cell or edge label written as Vec<ScannedAp> renders as just Vec. The angle-bracketed part is gone.

Cause: drawio cell styles include html=1 by default (rounded boxes, all standard shapes). The value= attribute is rendered as HTML. <ScannedAp> is parsed as an unknown HTML tag and silently dropped.

Fix: in the XML, write the angle brackets as &amp;lt; and &amp;gt;. After XML parse → &lt; &gt;. After HTML render → literal < >. Example:

<mxCell id="scanner" value="scanner.rs&#xa;parse → Vec&amp;lt;ScannedAp&amp;gt;" ...>

Same trap applies to edge labels (mxCell with edge="1"'s value).

Rule 4 — edges respect geometry, not topology

If node A is at (60, 200), node C is at (800, 200), and you have an edge A→C, the edge is drawn as a straight line through y=200 between x=60 and x=800. If you also place node B at (400, 200), the edge passes through B. drawio does not auto-route around obstacles unless you tell it to.

Fix options:

  • Move B off the straight line (e.g. to y=120, above the edge).
  • Give the edge explicit waypoints (<Array as="points"><mxPoint .../></Array> inside the edge's mxGeometry).

Rule 5 — verify both ways

Bug classCaught by CLI export?Caught by GUI app?
Reserved IDYES (fails)NO (renders)
Bad <> escapeNO (silently strips)NO (silently strips) — visible in render
Bad dx/dyNO (renders fine)YES (canvas blank)
Edge through a nodeNO (renders)NO (renders) — visible to humans
Reserved schema attributeYES (fails)sometimes

So the verification protocol is:

# 1. CLI export to PNG — proves the file is structurally exportable.
rm -f ~/.config/drawio/Singleton*
drawio -x -f png -o /tmp/probe.png file.drawio
[ -s /tmp/probe.png ] || echo "FAIL: CLI export produced nothing"

# 2. Open in the GUI — proves content is on-screen at viewport open.
drawio file.drawio &
# ask the human: "do you see content, or a blank canvas?"

Procedure

When authoring a new drawio file

  1. Start from a known-good template — copy an existing working file (e.g. user's architecture.drawio if available) and edit, rather than building from scratch. Avoids forgetting a wrapper element.
  2. Use these in the header:
    <mxfile host="Electron" agent="<short-identifier>" version="29.0.3">
      <diagram name="<Human Name>" id="<safe_id>">
        <mxGraphModel dx="0" dy="0" grid="1" gridSize="10" ...>
          <root>
            <mxCell id="0" />
            <mxCell id="1" parent="0" />
            ...
  3. Pick cell IDs from a safe namespace: prefix all IDs (n_ for nodes, e_ for edges, el_ for edge labels — e.g. n_filter, e_parse_emit, el_parse_emit) so collisions with SVG element names are impossible.
  4. Escape angle brackets the moment you write them: &amp;lt; &amp;gt;.
  5. Layout sanity-check before adding edges: list every (id, x, y, w, h). For every pair of nodes A, B that have an edge A→B, check whether any third node C has its bounding box on the straight-line segment from A's edge-exit point to B's edge-entry point. If so, move C or add waypoints.
  6. Validate: CLI export → non-empty PNG; open in GUI → content visible.

When debugging "the drawio file is empty / broken"

Run the symptom-to-rule lookup:

SymptomLikely rule
Error: Export failed: file.drawioRule 2 (reserved ID)
CLI export OK but GUI canvas blankRule 1 (bad dx/dy)
Vec / <X> rendered without its angle-bracketed partRule 3 (double-escape)
Edge visibly crosses through a boxRule 4 (geometry vs. topology)
GUI renders fine, CLI failsRule 2 (almost always)

Then bisect:

# If a file fails to export, bisect by stripping cells:
python3 - <<'PYEOF'
import xml.etree.ElementTree as ET
t = ET.parse('file.drawio')
gm = t.getroot().find('.//mxGraphModel/root')
# Remove half the data cells, test export, narrow down.
PYEOF

When the bisect points at one or two cells, inspect their IDs against the reserved-name list.

When reviewing a finished drawio for clarity

Run through:

CheckHow to spot
dx/dy non-zero in a hand-authored fileHeader dx="N" dy="M" with N,M > 0 — but skip this check if drawio app last saved the file
Reserved IDgrep -oP 'id="[a-z]+"' and cross-reference SVG element names
Unescaped <T> in value=grep '<[A-Z]' file.drawio looks for un-escaped pointy generics
Edge crosses a nodeOpen in GUI, visually inspect; or compute geometrically (intermediate-node bounding-box vs. edge straight-line segment)
Crowded diagram (too many edges in one view)>25 nodes or >40 edges → suggest splitting into per-aspect files/tabs
Inconsistent edge stylingSame logical edge type (data / trigger / read) using different style="..." patterns across cells
Page boundsAll nodes within pageWidth × pageHeight? grep -oP 'x="[0-9]+" y="[0-9]+" width="[0-9]+" height="[0-9]+"' and check

Programmatic structural check (Python, runs against any .drawio):

import xml.etree.ElementTree as ET, sys
t = ET.parse(sys.argv[1])
gm = t.getroot().find('.//mxGraphModel')
page_w = int(gm.get('pageWidth')); page_h = int(gm.get('pageHeight'))
nodes, edges = {}, []
for c in gm.findall('.//mxCell'):
    cid = c.get('id')
    if c.get('vertex') == '1':
        g = c.find('mxGeometry')
        if g is not None and g.get('width'):
            nodes[cid] = tuple(float(g.get(k, 0)) for k in ('x','y','width','height'))
    elif c.get('edge') == '1':
        edges.append((cid, c.get('source'), c.get('target')))

# Reserved IDs
RESERVED = {'filter','mask','defs','style','script','g','path','clipPath',
            'linearGradient','radialGradient','text','image','use','symbol'}
bad_ids = [n for n in nodes if n in RESERVED]
if bad_ids: print(f"BAD: reserved IDs: {bad_ids}")

# Edge endpoints resolve
for eid, s, t_ in edges:
    if s and s not in nodes and s not in ('0','1'):
        print(f"BAD: edge {eid} source={s} not a node")
    if t_ and t_ not in nodes and t_ not in ('0','1'):
        print(f"BAD: edge {eid} target={t_} not a node")

# Overlap
keys = list(nodes); over = []
for i in range(len(keys)):
    for j in range(i+1, len(keys)):
        ax,ay,aw,ah = nodes[keys[i]]; bx,by,bw,bh = nodes[keys[j]]
        if ax < bx+bw and ax+aw > bx and ay < by+bh and ay+ah > by:
            over.append((keys[i], keys[j]))
if over: print(f"OVERLAP: {over[:5]}")

# Page bounds
oob = [n for n,v in nodes.items() if v[0]<0 or v[1]<0 or v[0]+v[2]>page_w or v[1]+v[3]>page_h]
if oob: print(f"OUT OF BOUNDS: {oob}")

Anti-patterns (push back on these)

  • Monolithic diagrams with 30+ nodes — splits into per-aspect files (or per-aspect tabs in a multi-<diagram> file) are almost always more readable. Propose the split before refining a crowded layout.
  • Hand-tuning every edge waypoint to avoid overlaps — usually means the layout itself is wrong. Reposition nodes first.
  • Reproducing the entire SQLite schema / object model in the diagram — drawio is for flow / topology, not ER. If the user wants ER, propose dbdiagram.io or PlantUML ER.
  • Lane backgrounds via huge fillColor=#fafafa rectangles — these read fine in CLI export but can become "click-traps" in the GUI when the user wants to click an underlying node. Use them sparingly; consider pointerEvents=0 on the background to make it click-through.
  • Custom agent strings — pretty (agent="my-cool-diagram") but drawio prefers to overwrite with the real Mozilla UA on save. Don't fight it; let drawio write what it wants.

Multi-diagram files (tabs vs. separate files)

drawio supports multiple <diagram> elements inside one <mxfile> — they show as tabs at the bottom of the canvas. Use this when:

  • The diagrams are aspects of one system (good: Scan, Locate, History, Persist for a daemon's dataflow).
  • A reader benefits from quickly switching between views.

Use separate files when:

  • The diagrams are independent (a network topology and a deployment topology don't belong as tabs of one file).
  • You want to reference them individually from a README (per-file SVG export is one-to-one).

If splitting into separate files: keep filename prefix consistent (dataflow-scan.drawio, dataflow-locate.drawio, ...) so they sort together in ls.

Tone

When reviewing, be specific and concrete: point at the cell ID, the line number, the exact rule. Don't hand-wave "diagram could be cleaner" — say "node n_parse overlaps node n_emit at (590, 1090)" or "edge e_parse_emit passes through node n_buffer between x=300 and x=600".

When pushing back on a request ("split this monolith"), explain why the current is crowded (count nodes/edges, identify the dense region) and propose the specific split.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.