# Mermaid Diagrams

> Comprehensive toolkit for creating consistent, cognitively-optimized Mermaid diagrams following the Mermaid Diagram Guidelines (MDG) v1.0 standard. Use for creating flowcharts, system architectures, process flows, sequence diagrams, ERDs, state diagrams, Gantt charts, mindmaps, class diagrams, and conceptual maps. Supports both Diagram Mode (human visual consumption) and RAG Mode (knowledge-graph extraction). Always use when users request Mermaid diagrams or when visualizing systems, processes, or relationships.

- Skill: `highdesertwizard/mermaid-diagrams` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add highdesertwizard/mermaid-diagrams`
- Raw SKILL.md: https://api.skillmd.com/api/skills/highdesertwizard/mermaid-diagrams/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: HighDesertWizard (https://skillmd.com/u/highdesertwizard)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/highdesertwizard/mermaid-diagrams

---


# Mermaid Diagram Guidelines (MDG v1.0)

This skill enables creation of MDG-compliant Mermaid diagrams with consistent styling, cognitive optimization, and support for both visual presentation and knowledge-graph extraction.

## Quick Start

### Emergency Rules (Always Apply)
1. Use only `<br>` to indicate line breaks inside nodes, but only insert line breaks when absolutely needed for some known reason
2. **CRITICAL for flowchart: Always include `color:#000000` in every classDef** — Without this, text is invisible in dark-mode rendering environments. (Flowchart only — classDiagram does NOT support `classDef`; use `themeVariables` instead.)
3. **CRITICAL for flowchart: Apply styles to INDIVIDUAL NODES, not subgraphs** — Subgraph styling does not propagate to node text. Use `class NodeA,NodeB myStyle` for nodes. Use `style SubgraphID ...` for subgraph containers.
4. **CRITICAL: Subgraph identifiers MUST NOT contain spaces** — use CamelCase or underscores
5. **CRITICAL: Subgraph titles need darker styling** — Use `style` directive to ensure subgraph labels are visible against colored backgrounds
6. **CRITICAL: Every diagram MUST have a title** — Use the appropriate title mechanism for each diagram type (see Title Requirements below)
7. First non-blank line **must** be an MDG header tag (e.g., `%%mdg:DGM:1.0%%`)
8. If metadata unknown, ask user once, then fill in available information
9. **Mobile limitation**: Mermaid artifacts render in artifact panel on desktop but may not work on mobile
10. **CRITICAL for flowchart: Default to targeting subgraphs, not leaf nodes, when crossing container boundaries.** Targeting leaf nodes inside a container that uses `direction` for arrangement (a "directional container") often overrides the container's internal layout. If semantic accuracy requires targeting a specific interior node, do so — but expect possible layout instability and test carefully. (See Principle 3 Critical Warning below) **Corollary: When all child subgraphs inside a container are targets, use a single edge to the parent container** (e.g., `Present --> Futures`) instead of separate edges to each child (e.g., `Present --> PathA`, `Present --> PathB`, `Present --> PathC`). Multiple edges into a container's children break the container's internal arrangement.
11. **CRITICAL for flowchart: Every subgraph MUST have an explicit `direction` that alternates with its children.** The cross-grain chain must be unbroken at every nesting level. If the flowchart is TB, a title-wrapper subgraph must be `direction TB`, and its child subgraphs must be `direction LR`. Omitting `direction` on any intermediate subgraph breaks the layout. (See Principle 1.)
12. **CRITICAL for flowchart: Max 4 nodes in any single horizontal chain.** A `direction LR` subgraph with 5+ nodes in a single `-->` chain produces an extremely wide, thin diagram that won't fit any medium. Break long chains into multiple stacked rows (each row a subgraph with `direction LR` containing ≤ 4 nodes). Similarly, hub-and-spoke layouts (`flowchart LR`) with >3 spokes must wrap spokes into row containers.
13. **CRITICAL: Aspect ratio must stay between 2:1 and 1:2.** If a diagram would be wider than 2× its height (or taller than 2× its width), restructure before publishing. Common fixes: break horizontal chains into rows, wrap hub spokes into row containers, or split into multiple diagrams.
14. **CRITICAL for flowchart: Sibling subgraphs MUST have `~~~` invisible links between them.** When a parent subgraph contains two or more child subgraphs at the same level, always add `~~~` links between them (e.g., `ChildA ~~~ ChildB ~~~ ChildC`). Do NOT rely on `direction`, external edges, or declaration order alone — renderers handle these inconsistently. The `~~~` link is the only reliable way to enforce sibling subgraph arrangement. **Exception for leaf nodes:** Do NOT add `~~~` between leaf nodes inside a subgraph when the parent subgraphs are already rank-constrained by `-->` edges — in that case, `direction LR` is sufficient and adding `~~~` can break the layout by forcing an overly wide horizontal row.
15. **CRITICAL: Do not create a Legend Object or Subgraph.**

### Quick Reference: Flowchart Layout Techniques

| Layout Goal | Technique | Key Constraint |
|-------------|-----------|----------------|
| Floating header/title | T1 | `style` wrapper transparent; use `~~~` not `-->` to connect |
| Side-by-side (from common source) | T2 | External node → child **subgraphs** (not leaf nodes) |
| Stacked vertically | T3 | Sequential edges between child subgraphs |
| Side-by-side (aspect ratio) | T4 | `direction TB` on children makes them narrow |
| Grid (N×M) | T5 | `direction LR` rows + `direction TB` children + `~~~` ordering |
| Hub-and-spoke | T6 | Central node at top level; subgraph-level edges to spokes |
| **NEVER** | — | External edges to **leaf nodes** inside directional containers |

### Flowchart Layout Decision Tree

1. **Simple stepwise pipeline** → subgraph-to-subgraph sequential flow (T3)
2. **Peer paths from a common source** → external common-source edges to child subgraphs (T2 + T4)
3. **Peer subgraphs side by side (no common source)** → `direction TB` on children for aspect ratio; combine with `~~~` if ordering matters (T4)
4. **Grid or quadrant (2×2, N×M)** → row containers with `direction LR` + child `direction TB` + `~~~` ordering (T5)
5. **Hub-and-spoke / radial** → central node with subgraph-level edges to spoke containers (T6)
6. **Asymmetric composite** → stacked row containers; each row may have 1, 2, or 3 children (T5 variant)
7. **Would your design require a cross-boundary edge to a leaf node inside a directional container?** → redesign to target the containing subgraph instead, or split diagrams

### Rule Priority (when rules conflict)

1. Syntax validity (character safety, no spaces in IDs)
2. Emergency Rules 1–10
3. Text visibility / accessibility (`color:#000000`, contrast)
4. Layout stability (Principles 1–3)
5. Aesthetic preferences (palettes, legends, shapes)

### Title Requirements

Every diagram must include a title. The mechanism varies by diagram type:

| Diagram Type | Title Mechanism | Example |
|-------------|----------------|---------|
| `flowchart` | Top-level subgraph with title text, or a prominent styled node at top | `subgraph Title["My Diagram Title"]` wrapping all content |
| `sequenceDiagram` | `title` directive | `title API Authentication Flow` |
| `erDiagram` | `title` directive | `title Customer Order Model` |
| `stateDiagram-v2` | `title` directive | `title Order Lifecycle` |
| `classDiagram` | `title` directive | `title Domain Model` |
| `gantt` | `title` directive | `title Project Timeline` |
| `mindmap` | Root node serves as title | Root node text is the title |
| `pie` | `title` directive | `title Budget Allocation` |

For flowcharts, the recommended approach is a top-level container subgraph whose label serves as the diagram title, styled with prominent font weight and color.

### Operating Modes

**Diagram Mode** (default): For human visual consumption
- Prioritize: color palettes, node limits, legends, aesthetics
- Target: presentations, documentation, slides

**RAG Mode**: For knowledge-graph extraction
- Prioritize: one-fact-per-line, stable IDs, semantic structure
- Use header: `%%mdg:RAG:1.0%%`
- Target: semantic web, triples, RAG pipelines

**Detection:**
- Header tag `%%mdg:RAG:*%%` → RAG Mode
- Keywords describing **output type** (not subject matter): "knowledge graph", "triples", "semantic extraction", "ontology" → RAG Mode
- "Draw a flowchart of my RAG pipeline" → Diagram Mode (the word "RAG" describes the subject, not the output)
- **If uncertain** → ask the user: "Should this output be a visual diagram or machine-readable triples?"
- Otherwise → Diagram Mode

## Diagram Type Selection

| Type | When to Use |
|------|-------------|
| `flowchart` | Process flows, system architecture, concept maps |
| `sequenceDiagram` | API calls, message passing, protocol handshakes |
| `erDiagram` | Database schemas, entity relationships, data models |
| `stateDiagram-v2` | State machines, lifecycle models, status workflows |
| `classDiagram` | Class models, entity relationships, UML |
| `gantt` | Timelines, project schedules, milestones |
| `mindmap` | Brainstorming, topic hierarchies, knowledge maps |
| `pie` | Proportional data, budget breakdowns, distributions |

If uncertain about layout technique, default to Technique 3 (stacked pipeline).

---


## Standard Guidelines

| Topic | Guideline |
|-------|-----------|
| Character safety | IDs = `A-Z a-z 0-9 _ -` only |
| Direction | `TB` for docs; `LR` for slides/mobile |
| Legend | Required if > 3 shape types OR > 2 color families |
| Node count | Aim ≤ 60 nodes & ≤ 100 edges for flowcharts (split if needed) |
| Horizontal chain limit | **Max 4 nodes** in a single `direction LR` chain. If more, break into multiple rows (stacked subgraphs with `direction LR` each containing ≤ 4 nodes) or switch the parent to `flowchart LR` with `direction TB` children. |
| Aspect ratio | **Target 4:3 to 3:4.** Never exceed 2:1 (wide) or 1:2 (tall). If a draft exceeds this, restructure: break long chains into rows, wrap spokes into row containers, or split into separate diagrams. |
| Accessibility | Font ≥ 14px mobile / 16px desktop; contrast ≥ 4.5:1 |
| Titles | **Every diagram must have a title** — no exceptions |
| Nesting | Limit subgraph nesting to 2 levels max (see flowchart sections below) |
| Layout engine | Default: dagre (always available). ELK: optional, better for complex diagrams but NOT available in claude.ai artifacts (see ELK section below) |

---

## Pre-Publish Checklist

Before delivering, verify:
- [ ] Header tag present and correct mode
- [ ] Metadata complete
- [ ] **Title present** — every diagram has a title via the appropriate mechanism for its type
- [ ] No spaces in subgraph identifiers
- [ ] Font size initialized
- [ ] **For flowchart**: Every classDef includes `color:#000000`
- [ ] **For flowchart**: Styles applied to individual nodes (via `class`), not subgraphs
- [ ] **For flowchart with subgraphs**: Subgraph titles styled with dark text (`color:#1a1a1a` or `color:#000000`) via `style` directive
- [ ] **For flowchart with subgraphs**: Cross-grain direction — child subgraph `direction` is perpendicular to parent flow (or deliberately overridden with justification)
- [ ] **For flowchart with subgraphs**: Subgraph arrangement — verify against Quick Reference table: pipeline (T2/T3), grid (T5), hub-and-spoke (T6). NO cross-boundary edges targeting leaf nodes inside directional containers (Emergency Rule 10).
- [ ] **For flowchart with subgraphs**: Subgraph-level connections — cross-subgraph arrows target subgraphs, not interior nodes (unless a specific interior node must be identified)
- [ ] **Aspect ratio check**: Ratio stays between 2:1 and 1:2. No `direction LR` chain exceeds 4 nodes. Hub-and-spoke has ≤ 3 unwrapped spokes.
- [ ] **For classDiagram**: Using `theme: 'base'` with proper themeVariables
- [ ] **For classDiagram**: `lineColor` set to light value (e.g., `#AAAAAA`)
- [ ] **For sequenceDiagram**: `title` directive present; participant count ≤ 8; using `+`/`-` activation shorthand
- [ ] **For erDiagram**: All relationships labeled; PK/FK annotated; singular entity names
- [ ] **For stateDiagram-v2**: Start and end states present; all transitions labeled
- [ ] **For gantt**: `title` directive present; dependencies used over hardcoded dates
- [ ] **If using advanced layout**: Invisible container/anchor classes defined
- [ ] **If using advanced layout**: All padding/anchor nodes have `invisible` class applied
- [ ] Legend if > 3 shapes or > 2 color families
- [ ] Node count ≤ 60 (or deliberately exceeded with justification)

---

## Change Log

**Current standard: MDG v1.0**

| Version | Date | Summary |
|---------|------|---------|
| 1.0 | 2026-03-07 | **Public release.** Single-file consolidation. Four rounds of multi-LLM review (GPT, Gemini, Grok, Sonnet, Haiku). No breaking changes from v0.49. |
| 0.49 | 2026-03-07 | **Round 3 micro-fixes:** RAG triple example updated to convention-compliant IDs. Frontmatter description corrected. Technique 6 duplicate sentence removed. Safe Fallback title-wrapper clarification added. |
| 0.48 | 2026-03-07 | Round 2 review (16 changes): troubleshooting section, safe fallback default, routing enforcement, asymmetric composite example, ELK tightening, hub-spoke threshold, Quick Rule. Plus 9 targeted fixes. |
| 0.47 | 2026-03-07 | Structural reorganization. Non-flowchart depth (sequence, ERD, state, Gantt, mindmap, pie, class). ELK layout engine reference. |
| 0.46 | 2026-03-06 | Principle 3 comprehensive rewrite: 5 techniques for subgraph arrangement including Grid Layout. |
| 0.45 | 2026-02-27 | Page-Fit Layout Strategy. New diagram types. |
| 0.44 | 2025-12-04 | Advanced Layout Techniques. Invisible elements toolkit. |
| 0.43 | 2025-11-28 | classDiagram guidance. `color:#000000` rule. |
| 0.40 | 2025-09-02 | Initial structured version. |
| 0.39 | 2025-05-24 | Revision. |
| 0.38d3 | 2025-05-04 | Draft 3. |
| 0.38d2 | 2025-04-27 | Draft 2. |
| 0.38d1 | 2025-04-27 | First draft. |


---

# Diagram Type Reference

## flowchart Diagrams

### flowchart Boilerplate

```mermaid
%%mdg:DGM:1.0%%
%%{init: {'theme': 'default', 'themeVariables': { 'fontSize': '20px' }}}%%
%% Date: YYYY-MM-DD
%% Title: Diagram Title
%% Project: Project Name
%% MDG Version: 1.0
%% LLM: Claude [version]
%% Human Author: [Name]
%% Location: [Location]

flowchart TB
    subgraph DiagramTitle["Diagram Title Here"]
        A[Node A] --> B[Node B]
    end

classDef primary fill:#E0E8FF,stroke:#3050C8,stroke-width:2px,color:#000000
class A,B primary

style DiagramTitle fill:#F5F8FF,stroke:#3050C8,stroke-width:2px,color:#1a1a1a,font-weight:bold
```

### Critical Syntax Rules

#### Subgraph Declaration (MOST COMMON ERROR)

❌ **INCORRECT** (causes syntax errors):
```mermaid
subgraph Current State["Current State"]
subgraph Data Layer["Data Management"]
```

✅ **CORRECT**:
```mermaid
subgraph CurrentState["Current State"]
subgraph DataLayer["Data Management"]
```

**Rule**: NO SPACES between identifier and brackets. Use CamelCase, underscores, or single words.

#### Node Styling for flowchart (CRITICAL FOR TEXT VISIBILITY)

❌ **INCORRECT** — Applying styles to subgraphs (text inside nodes will be invisible):
```mermaid
subgraph MyGroup["My Group"]
    NodeA[Node A]
    NodeB[Node B]
end
classDef myStyle fill:#E0E8FF,stroke:#3050C8,stroke-width:2px,color:#000000
class MyGroup myStyle
```

✅ **CORRECT** — Apply styles to individual nodes:
```mermaid
subgraph MyGroup["My Group"]
    NodeA[Node A]
    NodeB[Node B]
end
classDef myStyle fill:#E0E8FF,stroke:#3050C8,stroke-width:2px,color:#000000
class NodeA,NodeB myStyle
```

**Rule**: Always apply `class` statements to individual node IDs, not subgraph IDs.

#### Subgraph Title Styling (CRITICAL FOR COLORED DIAGRAMS)

When using colored backgrounds or pastel fills, subgraph titles can become hard to read. Always style subgraph titles with darker, high-contrast colors.

✅ **CORRECT** — Style subgraph titles for visibility:
```mermaid
flowchart TB
    subgraph Frontend["Frontend Layer"]
        UI[User Interface]
        Router[Router]
    end
    subgraph Backend["Backend Services"]
        API[API Gateway]
        DB[(Database)]
    end
    
    UI --> API
    Router --> API
    API --> DB

classDef primary fill:#E0E8FF,stroke:#3050C8,stroke-width:2px,color:#000000
classDef secondary fill:#E0FFE8,stroke:#30C850,stroke-width:2px,color:#000000
class UI,Router primary
class API,DB secondary

style Frontend fill:#F5F8FF,stroke:#3050C8,stroke-width:2px,color:#1a1a1a,font-weight:bold
style Backend fill:#F5FFF8,stroke:#30C850,stroke-width:2px,color:#1a1a1a,font-weight:bold
```

**Subgraph Title Styling Guidelines:**
- Use `style SubgraphID` directive (not `class`) for subgraph containers
- Set `color:#1a1a1a` or `color:#000000` for dark, readable title text
- Add `font-weight:bold` to improve title visibility
- Use lighter fill colors for subgraph backgrounds than for nodes (e.g., `#F5F8FF` instead of `#E0E8FF`)
- Ensure stroke color matches or complements the node color family

---

## Page-Fit Layout Strategy: Direction and Connection Patterns

These two principles control diagram aspect ratio and prevent oversized diagrams. Apply them by default to every flowchart with subgraphs.

### Principle 1: Cross-Grain Direction

**Rule:** Every subgraph MUST have an explicit `direction` that is the opposite of its children's direction. The alternating cross-grain pattern must be unbroken at every nesting level — no gaps allowed.

| Parent Direction | Child Subgraph Direction | Effect |
|-----------------|-------------------------|--------|
| `flowchart TB` or `flowchart TD` | `direction LR` inside subgraphs | Each step is a horizontal band; steps stack vertically |
| `flowchart LR` | `direction TB` inside subgraphs | Each step is a vertical column; steps flow horizontally |

**Critical: The chain must be explicit at every level.** If a title-wrapper subgraph sits between the `flowchart` declaration and the leaf subgraphs, it MUST have an explicit `direction` that continues the alternating pattern. Omitting `direction` on any intermediate subgraph breaks the chain and causes unpredictable layout.

```
flowchart TB
    subgraph Title["My Diagram"]
        direction TB          ← explicit, same as flowchart (contains LR children)
        subgraph Stage1["Step 1"]
            direction LR      ← opposite of parent (TB)
            A["Node A"] --> B["Node B"]
        end
        subgraph Stage2["Step 2"]
            direction LR      ← opposite of parent (TB)
            C["Node C"] --> D["Node D"]
        end
        Stage1 --> Stage2
    end
```

**Rationale:** If parent and child share the same axis, expansion compounds — a 5-step pipeline with 3 nodes per step produces 15 vertical units of height. Cross-grain direction makes each step expand *across* the flow, not *along* it. If any subgraph in the chain omits `direction`, renderers may fall back to defaults that break the intended layout.

**Critical: Limit horizontal chain length.** Even with correct cross-grain direction, a single `direction LR` subgraph with 5+ nodes in a `-->` chain produces an extremely wide, thin layout that exceeds the 2:1 aspect ratio limit. **Max 4 nodes per horizontal chain.** For longer sequences, break into multiple stacked subgraphs:

❌ **Too wide (6 nodes in one LR chain):**
```
subgraph Pipeline["Event Pipeline"]
    direction LR
    A --> B --> C --> D --> E --> F
end
```

✅ **Wrapped into rows (max 3 per row):**
```
subgraph Pipeline["Event Pipeline"]
    direction TB
    subgraph Row1["Ingestion"]
        direction LR
        A --> B --> C
    end
    subgraph Row2["Processing"]
        direction LR
        D --> E --> F
    end
    Row1 --> Row2
end
```

**When to Override (same-grain is acceptable):**
- The subgraph contains a single node (direction is irrelevant)
- The subgraph's content is genuinely sequential along the same axis as the parent (rare)
- You're deliberately creating a tall/narrow or wide/short layout for a specific medium
- Explicit edges between child subgraphs (`==>`) establish rank ordering — in this case, the edges control arrangement, not the parent `direction` (see Combined Example: Multi-Phase Timeline in Advanced Layout)

❌ **Same-grain (tall, won't fit on page):**
```mermaid
flowchart TB
    subgraph Step1["Step 1"]
        direction TB
        A["Input"] --> B["Process"] --> C["Output"]
    end
    subgraph Step2["Step 2"]
        direction TB
        D["Input"] --> E["Process"] --> F["Output"]
    end
    Step1 --> Step2
```

✅ **Cross-grain (compact, fits on page):**
```mermaid
flowchart TB
    subgraph Step1["Step 1"]
        direction LR
        A["Input"] --> B["Process"] --> C["Output"]
    end
    subgraph Step2["Step 2"]
        direction LR
        D["Input"] --> E["Process"] --> F["Output"]
    end
    Step1 --> Step2
```

**Nested Subgraphs — alternate direction at each level:**
```
flowchart TB              ← Level 0: vertical
  subgraph Phase1         ← Level 1: horizontal
    direction LR
    subgraph Detail1      ← Level 2: vertical (if needed)
      direction TB
    end
  end
```

Generally avoid more than 2 levels of nesting. If you need 3+, split into multiple diagrams.

### Principle 2: Subgraph-Level Connections

**Rule:** Arrows between subgraphs should connect to the subgraph itself, not to nodes inside the subgraph, unless there is a specific reason to target an interior node.

**Rationale:** When you write `NodeA_Inside_Sub1 --> NodeB_Inside_Sub2`, the layout engine must route an arrow from a specific interior point in Subgraph 1 to a specific interior point in Subgraph 2. This forces spacing expansion, produces long diagonal arrows, and prevents the engine from optimizing compactness.

When you write `Sub1 --> Sub2`, the engine attaches the arrow to the subgraph border at the optimal attachment point. The arrow is short, clean, and the engine retains layout freedom.

**Decision Heuristic:**

| Situation | Connection Level | Example |
|-----------|-----------------|---------|
| Sequential steps in a pipeline | Subgraph → Subgraph | `Step1 --> Step2` |
| Feedback loops between steps | Subgraph → Subgraph | `Step5 --> Step4` |
| Parallel paths from a fork | Node → Subgraph | `FORK --> PathA` |
| Data flow between specific ports | Node → Node (justified) | `API_Output --> DB_Input` |
| Error handling from a specific step | Node → Node (justified) | `Validator --> ErrorHandler` |

**The Test:** Before writing a cross-boundary node-to-node connection, ask: *"Does the reader need to know which specific interior element is the source/target, or just that these two steps are connected?"*
- If they need to know → node-to-node (justified)
- If they just need the flow → subgraph-to-subgraph (default)

❌ **Node-to-node across subgraphs (sprawling):**
```mermaid
flowchart TB
    subgraph Step1["Processing"]
        direction LR
        A["Input"] --> B["Transform"] --> C["Output"]
    end
    subgraph Step2["Validation"]
        direction LR
        D["Receive"] --> E["Validate"] --> F["Result"]
    end
    C --> D
    F -.-> A
```

✅ **Subgraph-to-subgraph (compact):**
```mermaid
flowchart TB
    subgraph Step1["Processing"]
        direction LR
        A["Input"] --> B["Transform"] --> C["Output"]
    end
    subgraph Step2["Validation"]
        direction LR
        D["Receive"] --> E["Validate"] --> F["Result"]
    end
    Step1 --> Step2
    Step2 -.-> Step1
```

### Principle 3: Subgraph Arrangement (The Single Biggest Layout Issue)

Arranging subgraphs — side-by-side or stacked — is the most common layout problem in Mermaid flowcharts.

> **dagre** (from "directed graph rendering") is the JavaScript layout engine underneath Mermaid. Mermaid handles syntax and styling; dagre makes all spatial decisions — where nodes sit, how edges route, and how subgraphs are arranged. Every layout behavior described in this section is a dagre decision, not a Mermaid decision.

> **Renderer scope:** These layout rules are empirical patterns verified in the claude.ai artifact panel running Mermaid 10.x with dagre layout. Other renderers (VS Code, GitLab, GitHub, Mermaid Live Editor) may behave differently. Treat these as high-value defaults, not mathematical guarantees. When a layout fails, simplify edges, reduce asymmetry, and prefer the fallback patterns listed below.

The `direction` directive on a **parent** subgraph to control **children's arrangement** is not dependable as a sole control mechanism (dagre frequently deprioritizes it when it conflicts with global rank assignments). However, `direction` on **child** subgraphs to control their **internal flow** is respected and critically important — it shapes each child's aspect ratio, which indirectly influences how dagre arranges peers. For simple pipeline layouts, the most reliable observed pattern is **container subgraphs with external rank-forcing edges**, combined with **`direction` on children** to control internal flow. For **grid layouts** (2×2 or N×M), parent `direction` combined with child `direction` and `~~~` ordering links is the most reliable currently-known pattern (see Technique 5).

#### The Core Problem

When you set `direction LR` inside a **parent** subgraph to arrange its **children** side by side, dagre often deprioritizes it and stacks children vertically. The `direction` directive on a parent is a *weak hint* that dagre may disregard when it conflicts with edge-derived rank assignments.

However, `direction` on a **child** subgraph controls that child's **internal flow** — and this IS respected. This matters because a child's internal flow determines its aspect ratio (tall/narrow vs short/wide), and aspect ratio influences how dagre arranges peer subgraphs.

**The key distinction:**

| `direction` applied to | Purpose | Reliability |
|----------------------|---------|-------------|
| **Parent** subgraph (alone) | Arrange children side-by-side or stacked | ⚠️ Weak hint — not dependable as sole arrangement mechanism |
| **Parent** subgraph + child `direction` + `~~~` ordering | Grid layout arrangement (2×2, N×M) | ✅ Most reliable observed pattern (see Technique 5) |
| **Child** subgraph | Control internal flow within that child | ✅ Reliable — shapes aspect ratio, indirectly influences peer arrangement |

#### ⚠️ Critical Warning: Cross-Boundary Edges and Interior Targets

**Quick Rule:** If you write `External --> Something`, that "Something" must be a **subgraph ID**, not a node inside it.

**Read this before applying any technique.** This is the most common cause of layout failure.

When edges from **outside** a container target **leaf nodes** inside that container, dagre assigns those leaf nodes their own rank based on the external edge — overriding the container's internal `direction` arrangement. This pulls siblings out of side-by-side positioning and stacks them vertically.

**The key distinction: subgraph targets vs leaf-node targets.**

| Target type | Example | Safe? |
|-------------|---------|-------|
| Child **subgraph** inside container | `External --> PathA` (PathA is a subgraph) | ✅ Safe — dagre treats subgraph-level rank assignment differently |
| **Leaf node** inside directional container | `External --> NodeX` (NodeX is a node inside a subgraph with `direction` set) | ❌ Unsafe — external rank overrides internal arrangement |
| Container subgraph itself | `StepA --> Container` | ✅ Safe — subgraph-to-subgraph connection |

❌ **Breaks BottomRow's side-by-side arrangement:**
```mermaid
    TopRow --> BottomRow
    TopRow --> ChildC       %% ChildC is a leaf node inside BottomRow
    TopRow --> ChildD       %% ChildD is a leaf node inside BottomRow
```

✅ **Preserves arrangement:**
```mermaid
    TopRow --> BottomRow    %% subgraph-to-subgraph only
```

**Technique 2 is safe** because its external edges target child **subgraphs** (e.g., `Reality --> PathA`), not leaf nodes. The failure mode occurs when you target **leaf nodes inside a subgraph that has its own `direction` set**.

**Rule:** When crossing container boundaries, target subgraphs, not their contents.

#### The Reliable Solution: Container + External Edges

The pattern that works consistently for **both** side-by-side and stacked arrangements:

1. **Use a visible container subgraph** to group related children and provide semantic context (e.g., `subgraph x["INTERPRETATION PATHWAYS"]`)
2. **Place rank-forcing edges from a node OUTSIDE the container** into the children inside it — this is what actually controls arrangement
3. **Use a transparent wrapper subgraph** for elements that should float above or outside the container (titles, headers) while still participating in layout

**Why it works:** Dagre determines rank from edges. When an external node connects to multiple children inside a container, dagre assigns them equal rank. In a `flowchart TB`, equal-rank subgraphs are placed side by side. In a `flowchart LR`, they stack vertically. The container provides the visual border; the external edges provide the layout control.

#### Technique 1: Transparent Wrapper for Floating Elements

Use `subgraph y[" "]` with transparent styling to hold title nodes or header elements outside the main visual container:

```mermaid
subgraph y[" "]
    direction TB
    Title["Diagram Title"]
    HeaderNode["Key context"]
    Title ~~~ HeaderNode
end
style y fill:transparent,stroke:transparent,stroke-width:0px
```

This lets elements float cleanly above a container without being boxed inside it.

#### Technique 2: Side-by-Side via Container + External Edges

Place peer subgraphs inside a visible container. Connect to them from an external node:

```mermaid
flowchart TB
    %% Floating header (transparent wrapper)
    subgraph y[" "]
        Title["Figure Title"]
        Reality["Starting Condition"]
        Title ~~~ Reality
    end
    style y fill:transparent,stroke:transparent,stroke-width:0px

    %% Visible container with peer subgraphs
    subgraph x["PATHWAYS"]
        subgraph PathA["Path A"]
            A1["Step 1"] --> A2["Step 2"] --> A3["Step 3"]
        end
        subgraph PathB["Path B"]
            B1["Step 1"] --> B2["Step 2"] --> B3["Step 3"]
        end
        subgraph PathC["Path C"]
            C1["Step 1"] --> C2["Step 2"] --> C3["Step 3"]
        end
    end

    %% External edges force equal rank → side-by-side
    Reality --> PathA
    Reality --> PathB
    Reality --> PathC
```

**Key:** The edges from `Reality` (outside `x`) into `PathA`, `PathB`, `PathC` (inside `x`) usually encourage equal-rank placement. In `flowchart TB`, this often yields side-by-side arrangement when child aspect ratios are compatible. Note: these external edges target child **subgraphs** — this is safe per the Critical Warning above. If peers still stack, add `direction TB` inside each child to make them narrower (Technique 4).

#### Technique 3: Stacked Arrangement via Container + Sequential Edges

The same container pattern works for stacked (vertical) arrangements. Instead of connecting all children to the same external node, connect them in sequence:

```mermaid
flowchart TB
    subgraph y[" "]
        Title["Figure Title"]
    end
    style y fill:transparent,stroke:transparent,stroke-width:0px

    subgraph x["EVIDENCE LAYERS"]
        subgraph Layer1["Mechanism Evidence"]
            L1A["Study A"] ~~~ L1B["Study B"]
        end
        subgraph Layer2["Domain Evidence"]
            L2A["Study C"] ~~~ L2B["Study D"]
        end
        subgraph Layer3["Outcome Evidence"]
            L3A["Study E"] ~~~ L3B["Study F"]
        end
    end

    Title --> x
    Layer1 --> Layer2
    Layer2 --> Layer3
```

**Key:** Sequential edges (`Layer1 --> Layer2 --> Layer3`) assign different ranks, forcing vertical stacking. Within each layer, `~~~` links keep peer nodes side by side.

#### Technique 4: `direction` on Children for Aspect Ratio Control

Use `direction TB` inside each **child** subgraph to make its internal content flow vertically. This makes each child taller and narrower, which causes dagre to place peer subgraphs side by side (because they fit horizontally). Without `direction TB`, node chains default to flowing horizontally, making each child wider, which triggers vertical stacking.

**This is the single most impactful layout technique for side-by-side arrangements.**

✅ **With `direction TB` on children — peers render side by side:**
```mermaid
flowchart TB
    subgraph x["PATHWAYS"]
        subgraph PathA["Path A"]
            direction TB
            A1["Step 1"] --> A2["Step 2"] --> A3["Step 3"]
        end
        subgraph PathB["Path B"]
            direction TB
            B1["Step 1"] --> B2["Step 2"] --> B3["Step 3"]
        end
        subgraph PathC["Path C"]
            direction TB
            C1["Step 1"] --> C2["Step 2"] --> C3["Step 3"]
        end
    end
    ExternalNode --> PathA
    ExternalNode --> PathB
    ExternalNode --> PathC
```

**Why it works:** `direction TB` forces each path's nodes into a vertical column. Three narrow vertical columns fit side by side. Without `direction TB`, the nodes chain horizontally, creating wide subgraphs that dagre stacks vertically to fit.

**Combine with external edges for stronger control:** `direction TB` on children shapes aspect ratio. External edges from a common node encourage equal rank. Together, they produce the most consistent side-by-side arrangement observed in testing.

#### Technique 5: Grid Layout (2×2 or N×M)

For arrangements where multiple rows each contain side-by-side subgraphs (e.g., a 2×2 quadrant diagram), the container + external edges pattern from Technique 2 does NOT work — because external edges targeting interior nodes of a container **break the container's internal arrangement** (see Critical Warning above). Instead, use parent `direction LR` on each row container, child `direction TB` for aspect ratio, and `~~~` for left-right ordering.

**The pattern:**

```mermaid
flowchart TB
    %% Floating title (transparent wrapper)
    subgraph y[" "]
        TitleNode["Diagram Title"]
    end
    style y fill:transparent,stroke:transparent,stroke-width:0px

    %% Row 1: children side by side
    subgraph Row1["Row 1 Label"]
        direction LR
        subgraph ChildA["Child A"]
            direction TB
            A1["Item 1"] --> A2["Item 2"]
        end
        subgraph ChildB["Child B"]
            direction TB
            B1["Item 1"] --> B2["Item 2"]
        end
        ChildA ~~~ ChildB
    end

    %% Row 2: children side by side
    subgraph Row2["Row 2 Label"]
        direction LR
        subgraph ChildC["Child C"]
            direction TB
            C1["Item 1"] --> C2["Item 2"]
        end
        subgraph ChildD["Child D"]
            direction TB
            D1["Item 1"] --> D2["Item 2"]
        end
        ChildC ~~~ ChildD
    end

    %% Connect title to first row invisibly (no visible arrow)
    TitleNode ~~~ Row1

    %% Stack rows — subgraph-to-subgraph ONLY
    Row1 --> Row2
```

**Why it works — three mechanisms combine:**
1. **`direction LR` on each row container** — hints dagre to arrange children horizontally within the row
2. **`direction TB` on each child** — makes children tall/narrow, fitting side by side
3. **`ChildA ~~~ ChildB`** — tends to preserve left-to-right ordering consistent with declaration order (verify visually — the ordering heuristic is non-deterministic)

**Critical rules for grid layouts:**
- Connect rows to each other with **subgraph-to-subgraph edges only** (`Row1 --> Row2`). Never target leaf nodes across row boundaries.
- Use `~~~` (not `-->`) from title/header nodes to avoid unwanted visible arrows.
- The `~~~` link between siblings inside a row tends to preserve declaration-order positioning — declare the left sibling first in the `~~~` expression.
- If exact ordering matters, combine `~~~` with row containers and keep sibling structure symmetric.

#### Technique 6: Hub-and-Spoke (Radial Approximation)

For diagrams with a central concept and N satellite nodes (e.g., "Core API with 5 services," "Central thesis with supporting arguments"), do NOT use grid or pipeline techniques — they force rigid structures that look wrong for radial concepts.

**The pattern:** Place the central node at top level. Connect it with subgraph-level edges to spoke containers. Do not wrap spokes in a parent container unless semantic grouping requires it.

```mermaid
flowchart TB
    Hub((Central Concept))

    subgraph SpokeA["Service A"]
        direction TB
        A1["Endpoint 1"] --> A2["Endpoint 2"]
    end
    subgraph SpokeB["Service B"]
        direction TB
        B1["Endpoint 1"] --> B2["Endpoint 2"]
    end
    subgraph SpokeC["Service C"]
        direction TB
        C1["Endpoint 1"] --> C2["Endpoint 2"]
    end

    Hub --> SpokeA
    Hub --> SpokeB
    Hub --> SpokeC
```

**Key:** No container wrapping the spokes. The hub's edges to each spoke usually encourage equal rank placement. Use `direction TB` inside spokes to keep them narrow.

**Scale threshold:** For **>3 spokes**, the layout becomes too wide for most media. Transition to a hybrid: place spokes in row containers (Technique 5 variant) with 2-3 spokes per row, stacked vertically. Or split into two hub-and-spoke diagrams (primary hub + secondary hub). A `flowchart LR` with 4+ spokes will exceed a 2:1 aspect ratio and fail the aspect-ratio guideline.

**Row-wrapped hub-and-spoke (5 spokes):**
```mermaid
flowchart LR
    Hub(("Central<br>Concept"))

    subgraph Row1["Primary"]
        direction TB
        subgraph SpokeA["Service A"]
            direction TB
            A1["Step 1"] --> A2["Step 2"]
        end
        subgraph SpokeB["Service B"]
            direction TB
            B1["Step 1"] --> B2["Step 2"]
        end
        subgraph SpokeC["Service C"]
            direction TB
            C1["Step 1"] --> C2["Step 2"]
        end
        SpokeA ~~~ SpokeB ~~~ SpokeC
    end

    subgraph Row2["Secondary"]
        direction TB
        subgraph SpokeD["Service D"]
            direction TB
            D1["Step 1"] --> D2["Step 2"]
        end
        subgraph SpokeE["Service E"]
            direction TB
            E1["Step 1"] --> E2["Step 2"]
        end
        SpokeD ~~~ SpokeE
    end

    Hub --> Row1
    Hub --> Row2
    Row1 ~~~ Row2
```

**Asymmetric composite layouts** (e.g., 1 wide row + 2 narrow below) are a variant of Technique 5: build stacked row containers where each row may have a different number of children. Use `direction LR` on each row, `~~~` inside each row for ordering, and `Row1 --> Row2` between rows.

**Asymmetric example (1 wide + 2 narrow):**
```mermaid
flowchart TB
    subgraph Row1["Overview"]
        direction LR
        Summary["Full-Width Summary Content"]
    end

    subgraph Row2["Details"]
        direction LR
        subgraph Left["Left Detail"]
            direction TB
            L1["Item A"] --> L2["Item B"]
        end
        subgraph Right["Right Detail"]
            direction TB
            R1["Item C"] --> R2["Item D"]
        end
        Left ~~~ Right
    end

    Row1 --> Row2
```

**Key:** Row1 has 1 child (naturally spans full width). Row2 has 2 children with `direction TB` (narrower, side by side). Subgraph-to-subgraph stacking only.

#### When to Use Which Technique

| Goal | Technique | Pattern |
|------|-----------|---------|
| Peer subgraphs side by side | Container + external edges from ONE node to ALL child **subgraphs** + `direction TB` inside each child | `External --> ChildA`, `External --> ChildB` + `direction TB` in each child |
| Peer subgraphs stacked vertically | Container + sequential edges between children | `Child1 --> Child2 --> Child3` |
| **Grid layout (2×2, N×M)** | **Row containers with `direction LR` + child `direction TB` + `~~~` ordering + subgraph-to-subgraph stacking** | **`direction LR` on rows, `direction TB` on children, `ChildA ~~~ ChildB` inside rows, `Row1 --> Row2` between rows** |
| **Hub-and-spoke / radial** | **Central node at top level + subgraph-level edges to spoke containers** | **`Hub --> SpokeA`, `Hub --> SpokeB` + `direction TB` in spokes; no parent container** |
| Asymmetric composite (1 wide + 2 narrow) | Stacked row containers; each row may have different child count | Variant of T5: `direction LR` on each row, `~~~` inside, `Row1 --> Row2` between |
| Mixed (some side by side, some stacked) | Combine both — same-source edges for horizontal peers, sequential edges for vertical ordering | Mix patterns as needed |
| Elements floating outside container | Transparent wrapper subgraph | `style y fill:transparent,stroke:transparent,stroke-width:0px` |
| Control child internal flow | `direction TB` or `direct

…(truncated)
