|
| 1 | +--- |
| 2 | +name: diagram |
| 3 | +description: Create effective D2/Mermaid diagrams optimized for terminal display |
| 4 | +--- |
| 5 | + |
| 6 | +# Create Diagram |
| 7 | + |
| 8 | +Create effective D2 or Mermaid diagrams optimized for terminal display. |
| 9 | + |
| 10 | +## When to Use |
| 11 | + |
| 12 | +- Architecture or infrastructure diagrams |
| 13 | +- System interaction flows (request paths, failure cascades) |
| 14 | +- Process flowcharts or state machines |
| 15 | +- Incident failure diagrams showing what went wrong |
| 16 | + |
| 17 | +## Workflow |
| 18 | + |
| 19 | +1. **Identify components**: Ask what nodes (services, databases, users) and edges (connections, data flows) to show |
| 20 | +2. **Draft the D2/Mermaid code**: Write a first version following the terminal best practices below |
| 21 | +3. **Review for readability**: Check label lengths, node count, layout direction |
| 22 | +4. **Place in document**: Add as a fenced code block in the appropriate section |
| 23 | + |
| 24 | +## Terminal Best Practices |
| 25 | + |
| 26 | +Diagrams render as ASCII art in the terminal. Follow these rules for clean output. |
| 27 | + |
| 28 | +### Keep it small |
| 29 | + |
| 30 | +Aim for **5-7 nodes** max. Terminals are typically 80-120 columns wide. More nodes = unreadable overlaps. |
| 31 | + |
| 32 | +If you need more, use **containers** to group related nodes: |
| 33 | + |
| 34 | +```d2 |
| 35 | +vpc: VPC { |
| 36 | + api: API |
| 37 | + db: Database {shape: cylinder} |
| 38 | + api -> db |
| 39 | +} |
| 40 | +client: Client |
| 41 | +client -> vpc.api |
| 42 | +``` |
| 43 | + |
| 44 | +### Use short labels |
| 45 | + |
| 46 | +Edge labels over ~15 characters get moved to a legend at the bottom, disconnecting them from context. |
| 47 | + |
| 48 | +- Bad: `api -> db: "sends authenticated read requests for user data"` |
| 49 | +- Good: `api -> db: reads` |
| 50 | + |
| 51 | +Node labels should also be concise. Use the key as short ID and label for display: |
| 52 | + |
| 53 | +```d2 |
| 54 | +pg: PostgreSQL {shape: cylinder} |
| 55 | +``` |
| 56 | + |
| 57 | +### Set direction |
| 58 | + |
| 59 | +Default is top-to-bottom. For terminal, `direction: right` often works better as it uses horizontal space: |
| 60 | + |
| 61 | +```d2 |
| 62 | +direction: right |
| 63 | +a: Service A |
| 64 | +b: Service B |
| 65 | +a -> b: calls |
| 66 | +``` |
| 67 | + |
| 68 | +### Use shapes for meaning |
| 69 | + |
| 70 | +Supported shapes that render distinctly: |
| 71 | + |
| 72 | +- `shape: cylinder` — databases, connection pools, queues |
| 73 | +- `shape: diamond` — decision points |
| 74 | +- `shape: hexagon` — APIs or key services |
| 75 | +- `shape: circle` — users, external actors |
| 76 | +- Default rectangle — everything else |
| 77 | + |
| 78 | +### Cycles are warned |
| 79 | + |
| 80 | +A cycle like `A -> B -> C -> A` triggers a D002 warning. This is informational — cycles in incident/failure diagrams are often intentional. To avoid warnings on return paths, restructure as: |
| 81 | + |
| 82 | +```d2 |
| 83 | +# Instead of A -> B and B -> A, use: |
| 84 | +a <-> b: request/response |
| 85 | +``` |
| 86 | + |
| 87 | +### Mermaid vs D2 |
| 88 | + |
| 89 | +Both work. D2 is simpler for architecture diagrams. Mermaid is better for state machines and sequence diagrams. |
| 90 | + |
| 91 | +```mermaid |
| 92 | +stateDiagram-v2 |
| 93 | + proposed --> accepted |
| 94 | + proposed --> rejected |
| 95 | + accepted --> deprecated |
| 96 | + accepted --> superseded |
| 97 | +``` |
| 98 | + |
| 99 | +## Common Patterns |
| 100 | + |
| 101 | +### Incident failure diagram |
| 102 | + |
| 103 | +```d2 |
| 104 | +users: Users {shape: circle} |
| 105 | +api: API |
| 106 | +db: Database {shape: cylinder} |
| 107 | +
|
| 108 | +users -> api: requests |
| 109 | +api -> db: queries |
| 110 | +api -> users: 503 errors |
| 111 | +``` |
| 112 | + |
| 113 | +### Architecture overview |
| 114 | + |
| 115 | +```d2 |
| 116 | +direction: right |
| 117 | +client: Browser |
| 118 | +api: API {shape: hexagon} |
| 119 | +db: PostgreSQL {shape: cylinder} |
| 120 | +cache: Redis {shape: cylinder} |
| 121 | +
|
| 122 | +client -> api: HTTPS |
| 123 | +api -> db: reads/writes |
| 124 | +api -> cache: cached reads |
| 125 | +``` |
| 126 | + |
| 127 | +### Decision flow |
| 128 | + |
| 129 | +```d2 |
| 130 | +direction: right |
| 131 | +start: Request |
| 132 | +auth: Authenticated? {shape: diamond} |
| 133 | +allow: Allow |
| 134 | +deny: Deny |
| 135 | +
|
| 136 | +start -> auth |
| 137 | +auth -> allow: yes |
| 138 | +auth -> deny: no |
| 139 | +``` |
| 140 | + |
| 141 | +## Tips |
| 142 | + |
| 143 | +- Always test rendering width: `dg show DOC-ID` shows actual terminal output |
| 144 | +- If labels overflow to legend, shorten them — inline labels are always more readable |
| 145 | +- Use comments (`# ...` in D2) to document intent without affecting rendering |
| 146 | +- Prefer D2 for static architecture, Mermaid `stateDiagram-v2` for lifecycles |
0 commit comments