Claude-skill-registry adr-graph-easy-architect
ASCII architecture diagrams for ADRs via graph-easy. TRIGGERS - ADR diagram, architecture diagram, ASCII diagram.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/adr-graph-easy-architect" ~/.claude/skills/majiayu000-claude-skill-registry-adr-graph-easy-architect && rm -rf "$T"
skills/data/adr-graph-easy-architect/SKILL.md- curl piped into shell
- uses sudo
- makes HTTP requests (curl)
ADR Graph-Easy Architect
Create comprehensive ASCII architecture diagrams for Architecture Decision Records (ADRs) using graph-easy. Pure text output with automatic layout - no image rendering required.
When to Use This Skill
- Writing new ADR that involves architectural changes
- ADR describes migration, integration, or system changes
- User asks for visual representation of a decision
- Existing ADR diagram needs review or update
Preflight Check
Run these checks in order. Each layer depends on the previous.
Layer 1: Package Manager
/usr/bin/env bash << 'SETUP_EOF' # Detect OS and set package manager case "$(uname -s)" in Darwin) PM="brew" ;; Linux) PM="apt" ;; *) echo "ERROR: Unsupported OS (require macOS or Linux)"; exit 1 ;; esac command -v $PM &>/dev/null || { echo "ERROR: $PM not installed"; exit 1; } echo "✓ Package manager: $PM" SETUP_EOF
Layer 2: Perl + cpanminus (mise-first approach)
# Prefer mise for unified tool management if command -v mise &>/dev/null; then # Install Perl via mise mise which perl &>/dev/null || mise install perl # Install cpanminus under mise perl mise exec perl -- cpanm --version &>/dev/null 2>&1 || { echo "Installing cpanminus under mise perl..." mise exec perl -- curl -L https://cpanmin.us | mise exec perl -- perl - App::cpanminus } echo "✓ cpanminus installed (via mise perl)" else # Fallback: Install cpanminus via system package manager command -v cpanm &>/dev/null || { echo "Installing cpanminus via $PM..." case "$PM" in brew) brew install cpanminus ;; apt) sudo apt install -y cpanminus ;; esac } echo "✓ cpanminus installed" fi
Layer 3: Graph::Easy Perl module
# Check if Graph::Easy is installed (mise-first) if command -v mise &>/dev/null; then mise exec perl -- perl -MGraph::Easy -e1 2>/dev/null || { echo "Installing Graph::Easy via mise perl cpanm..." mise exec perl -- cpanm Graph::Easy } echo "✓ Graph::Easy installed (via mise perl)" else perl -MGraph::Easy -e1 2>/dev/null || { echo "Installing Graph::Easy via cpanm..." cpanm Graph::Easy } echo "✓ Graph::Easy installed" fi
Layer 4: Verify graph-easy is in PATH
# Verify graph-easy is accessible and functional command -v graph-easy &>/dev/null || { echo "ERROR: graph-easy not found in PATH" exit 1 } # Test actual functionality (--version exits with code 2, unreliable) echo "[Test] -> [OK]" | graph-easy &>/dev/null && echo "✓ graph-easy ready"
All-in-One Preflight Script
/usr/bin/env bash << 'PREFLIGHT_EOF' # Copy-paste this entire block to ensure graph-easy is ready (macOS + Linux) # Prefers mise for unified cross-platform tool management # Check for mise first (recommended) if command -v mise &>/dev/null; then echo "Using mise for Perl management..." mise which perl &>/dev/null || mise install perl mise exec perl -- cpanm --version &>/dev/null 2>&1 || \ mise exec perl -- curl -L https://cpanmin.us | mise exec perl -- perl - App::cpanminus mise exec perl -- perl -MGraph::Easy -e1 2>/dev/null || mise exec perl -- cpanm Graph::Easy else # Fallback: system package manager echo "💡 Tip: Install mise for unified tool management: curl https://mise.run | sh" case "$(uname -s)" in Darwin) PM="brew" ;; Linux) PM="apt" ;; *) echo "ERROR: Unsupported OS"; exit 1 ;; esac command -v $PM &>/dev/null || { echo "ERROR: $PM not installed"; exit 1; } command -v cpanm &>/dev/null || { [ "$PM" = "apt" ] && sudo apt install -y cpanminus || brew install cpanminus; } perl -MGraph::Easy -e1 2>/dev/null || cpanm Graph::Easy fi # Verify graph-easy is in PATH and functional command -v graph-easy &>/dev/null || { echo "ERROR: graph-easy not in PATH after installation" exit 1 } # Test actual functionality (--version exits with code 2, unreliable) echo "[Test] -> [OK]" | graph-easy &>/dev/null && echo "✓ graph-easy ready" PREFLIGHT_EOF
Part 1: DSL Syntax
Basic Elements
# Nodes (square brackets) [Node Name] # Edges (arrows) [A] -> [B] # Labeled edges [A] -- label --> [B] # Bidirectional [A] <-> [B] # Chain [A] -> [B] -> [C]
Groups (Containers)
# Named group with dashed border ( Group Name: [Node A] [Node B] ) # Nested connections ( Before: [Old System] ) ( After: [New System] ) [Before] -> [After]
Node Labels
# Custom label (different from ID) [db] { label: "PostgreSQL Database"; } # ASCII markers for visual distinction INSIDE boxes # (emojis break box alignment - use ASCII markers instead) [deleted] { label: "[x] Old Component"; } [added] { label: "[+] New Component"; } [warning] { label: "[!] Deprecated"; } [success] { label: "[OK] Passed"; }
Character rules for nodes:
- Graphical emojis (🚀 💡 ✅ ❌) - NEVER (double-width breaks box alignment)
- Unicode symbols (✓ ✗ ⚠ → ←) - OK (single-width, safe)
- ASCII markers ([x] [+] [!] :) ) - ALWAYS safe (monospace)
Use
graph { label: "..."; } for graphical emojis in title/legend.
Example: Emoji breaks alignment (DON'T DO THIS)
# BAD - emoji inside node [rocket] { label: "🚀 Launch"; }
Renders broken:
┌────────────┐ │ 🚀 Launch │ <-- box edge misaligned due to double-width emoji └────────────┘
Example: ASCII marker preserves alignment (DO THIS)
# GOOD - ASCII marker inside node [rocket] { label: "[>] Launch"; }
Renders correctly:
┌────────────┐ │ [>] Launch │ └────────────┘
Example: Emoji safe in graph title (OK)
# OK - emoji in graph label (outside boxes) graph { label: "🚀 Deployment Pipeline"; flow: east; } [Build] -> [Test] -> [Deploy]
Renders correctly (emoji in title, not in boxes):
🚀 Deployment Pipeline ┌───────┐ ┌──────┐ ┌────────┐ │ Build │ --> │ Test │ --> │ Deploy │ └───────┘ └──────┘ └────────┘
Flow Direction (MANDATORY: Always specify)
# MANDATORY: Always specify flow direction explicitly graph { flow: south; } # Top-to-bottom (architecture, decisions) graph { flow: east; } # Left-to-right (pipelines, sequences)
Never rely on default flow - explicit is clearer.
Graph Title and Legend (Outside Boxes - Emojis Safe Here)
Emojis break alignment INSIDE boxes but are SAFE in graph titles/legends.
Emoji Selection Guide - Choose emoji that matches diagram purpose:
| Diagram Type | Emoji | Example Title |
|---|---|---|
| Migration/Change | 🔄 | |
| Deployment/Release | 🚀 | |
| Data Flow | 📊 | |
| Security/Auth | 🔐 | |
| Error/Failure | ⚠️ | |
| Decision/Branch | 🔀 | |
| Architecture | 🏗️ | |
| Network/API | 🌐 | |
| Storage/Database | 💾 | |
| Monitoring/Observability | 📡 | |
| Hook/Event | 🪝 | |
| Before/After comparison | ⏮️/⏭️ | / |
# Title with semantic emoji graph { label: "🚀 Deployment Pipeline"; flow: east; } # Title with legend (multiline using \n) graph { label: "🪝 Hook Flow\n──────────\n✓ Allow ✗ Deny ⚠ Warn"; flow: south; }
Rendered:
Hook Flow ────────── ✓ Allow ✗ Deny ⚠ Warn ╭───────╮ │ Start │ ╰───────╯
Rule: Emojis ONLY in
graph { label: "..."; } - NEVER inside [ node ]
Node Styling (Best Practices)
# Rounded corners for start/end nodes [ Start ] { shape: rounded; } [ End ] { shape: rounded; } # Double border for emphasis [ Critical Step ] { border: double; } # Bold border for important nodes [ Key Decision ] { border: bold; } # Dotted border for optional/skippable [ Optional ] { border: dotted; } # Multiline labels with \n [ Hook Input\n(stdin JSON) ]
Rendered examples:
╭─────────╮ ┌─────────┐ │ Rounded │ │ Default │ ╰─────────╯ └─────────┘ ╔═════════╗ ┏━━━━━━━━━┓ ║ Double ║ ┃ Bold ┃ ╚═════════╝ ┗━━━━━━━━━┛
Note: Dotted borders (
) use{ border: dotted; }characters that render inconsistently on GitHub. Use sparingly.⋮
Edge Styles
[ A ] -> [ B ] # Solid arrow (default) [ A ] ..> [ B ] # Dotted arrow [ A ] ==> [ B ] # Bold/double arrow [ A ] - -> [ B ] # Dashed arrow [ A ] -- label --> [ B ] # Labeled edge
Part 2: Common Diagram Patterns
Migration (Before → After)
graph { flow: south; } [Before] -- migrate --> [After]
Multi-Component System
graph { flow: south; } [A] -> [B] -> [C] [B] -> [D]
Pipeline (Left-to-Right)
graph { flow: east; } [Input] -> [Process] -> [Output]
Decision with Options
graph { flow: south; } [Decision] -> [Option A] [Decision] -> [Option B]
Grouped Components
( Group: [Component 1] [Component 2] ) [External] -> [Component 1]
Bidirectional Flow
[Client] <-> [Server] [Server] -> [Database]
Part 3: Rendering
Command (MANDATORY: Always use boxart)
# MANDATORY: Always use --as=boxart for clean output graph-easy --as=boxart << 'EOF' graph { flow: south; } [A] -> [B] -> [C] EOF
Never use
--as=ascii - it produces ugly +--+ boxes instead of clean ┌──┐ lines.
Output Modes
| Mode | Command | Usage |
|---|---|---|
| | MANDATORY - clean Unicode lines |
| | NEVER USE - ugly output, legacy only |
Validation Workflow
# 1. Write DSL to heredoc # 2. Render with boxart graph-easy --as=boxart << 'EOF' [Your] -> [Diagram] -> [Here] EOF # 3. Review output # 4. Iterate if needed # 5. Copy final ASCII to ADR
Part 4: Embedding in ADR
Markdown Format (MANDATORY: Always Include Source)
CRITICAL: Every rendered diagram MUST be followed by a collapsible
<details> block containing the graph-easy source code. This is non-negotiable for:
- Reproducibility: Future maintainers can regenerate the diagram
- Editability: Source can be modified and re-rendered
- Auditability: Changes to diagrams are trackable in git diffs
## Architecture ``` ┌──────────┐ ┌──────────┐ ┌──────────┐ │ Before │ ──> │ After │ ──> │ Database │ └──────────┘ └──────────┘ └──────────┘ ``` <details> <summary>graph-easy source</summary> ``` graph { flow: east; } [Before] -> [After] -> [Database] ``` </details>
The
block is MANDATORY - never embed a diagram without its source.<details>
GFM Collapsible Section Syntax
GitHub Flavored Markdown supports HTML
<details> and <summary> tags for collapsible sections. Key syntax rules:
Structure:
<details> <summary>Click to expand</summary> <!-- BLANK LINE REQUIRED HERE --> Content goes here (Markdown supported) <!-- BLANK LINE REQUIRED HERE --> </details>
Critical rules:
- Blank lines required - Must have empty line after
and before<summary>
for Markdown to render</details> - No indentation -
and<details>
must be at column 0 (no leading spaces)<summary> - Summary is clickable label - Text in
appears as the collapsed header<summary> - Markdown inside works - Code blocks, headers, lists all render correctly inside
Optional: Default expanded:
<details open> <summary>Expanded by default</summary> Content visible on page load </details>
Common mistake (Markdown won't render):
<details> <summary>Broken</summary> No blank line - this won't render as Markdown! </details>
References:
File Organization
No separate asset files needed - diagram is inline in the markdown.
Regeneration
If ADR changes, regenerate by running the source through graph-easy again:
# Extract source from <details> block, pipe through graph-easy graph-easy --as=boxart << 'EOF' # paste source here EOF
Reference: Monospace-Safe Symbols
Avoid emojis - they have variable width and break box alignment on GitHub.
Status Markers
| Meaning | Marker |
|---|---|
| Added/New | |
| Removed/Deleted | |
| Changed/Updated | |
| Warning/Deprecated | |
| Deferred/Pending | |
| Current/Active | |
| Optional | |
| Locked/Fixed | |
Box Drawing (U+2500-257F)
─ │ ┌ ┐ └ ┘ ├ ┤ ┬ ┴ ┼ (light) ═ ║ ╔ ╗ ╚ ╝ ╠ ╣ ╦ ╩ ╬ (double)
Arrows & Pointers
→ ← ↑ ↓ (arrows) ∨ ∧ (logic - graph-easy uses these) < > ^ v (ASCII arrows)
Shapes & Bullets
• ○ ● (bullets) □ ■ (squares) ◇ ◆ (diamonds)
Math & Logic
× ÷ ± ≠ ≤ ≥ ∞ (math) ∧ ∨ ¬ (logic)
Reference: Common Patterns
# Vertical flow (architecture) graph { flow: south; } # Horizontal flow (pipeline) graph { flow: east; } # Labeled edge [A] -- label text --> [B] # Group with border ( Group Name: [Node A] [Node B] ) # Custom node label [id] { label: "Display Name"; }
Graph Label (MANDATORY: EVERY diagram MUST have emoji + title)
WARNING: This is the most commonly forgotten requirement. Diagrams without labels are invalid.
Correct Example
graph { label: "🔄 Database Migration"; flow: south; } [Old DB] -> [New DB]
Anti-Pattern (INVALID - DO NOT DO THIS)
graph { flow: south; } [Old DB] -> [New DB]
Why this is wrong: Missing
label: with emoji. The preflight validator will BLOCK any ADR containing diagrams without graph { label: "emoji ..."; }.
Mandatory Checklist (Before Rendering)
Graph-Level (MUST have)
-
- semantic emoji + title (MOST FORGOTTEN - check first!)graph { label: "🚀 Title"; } -
orgraph { flow: south; }
- explicit directiongraph { flow: east; } - Command uses
- NEVER--as=boxart--as=ascii
Embedding (MUST have - non-negotiable)
-
block with source - EVERY diagram MUST have collapsible source code block<details> - Format: rendered diagram in
block, followed immediately by```
with source in<details><summary>graph-easy source</summary>
block``` - Never commit a diagram without its reproducible source
Node Styling (Visual hierarchy)
- Start/end nodes:
- entry/exit points{ shape: rounded; } - Critical/important nodes:
or{ border: double; }{ border: bold; } - Optional/skippable nodes:
{ border: dotted; } - Default nodes: no styling (standard
border)┌──┐ - Long labels use
for multiline - max ~15 chars per line\n
Edge Styling (Semantic meaning)
- Main/happy path:
solid arrow-> - Conditional/alternate:
dotted arrow..> - Emphasized/critical:
bold arrow==> - Edge labels are SHORT (1-3 words):
,-- YES -->-- error -->
Character Safety (Alignment)
- NO graphical emojis inside nodes (🚀 💡 ✅ ❌ break alignment)
- Unicode symbols OK inside nodes (✓ ✗ ⚠ are single-width)
- ASCII markers ALWAYS safe ([x] [+] [!] [OK])
- Graphical emojis ONLY in
titlegraph { label: "..."; }
Structure (Organization)
- Groups
used for logical clustering when 4+ related nodes( Name: ... ) - Node IDs short, labels descriptive:
[db] { label: "PostgreSQL"; } - No more than 7-10 nodes per diagram (split if larger)
Success Criteria
Correctness
- Parses without error - graph-easy accepts the DSL
- Renders cleanly - no misaligned boxes or broken lines
- Matches content - all key elements from description represented
- Source preserved (MANDATORY) - EVERY diagram MUST have
block with graph-easy DSL source immediately after the rendered output<details>
Aesthetics
- Uses boxart - clean Unicode lines
, not ASCII┌──┐+--+ - Visual hierarchy - start/end rounded, important bold/double, optional dotted
- Consistent styling - same border style = same semantic meaning throughout
- Readable labels - multiline with
, no truncation\n - Clear flow - direction matches natural reading (top-down or left-right)
Comprehensiveness
- Semantic emoji in title - emoji consciously chosen to match diagram purpose (see Emoji Selection Guide)
- Legend if needed - multiline title with
for complex diagrams\n - Edge semantics - solid=normal, dotted=conditional, bold=critical
- Logical grouping - related nodes in
containers( Group: ... )
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| graph-easy not installed | Run preflight check |
| Misaligned boxes | Used | Always use |
| Box border broken | Graphical emoji in node | Remove 🚀💡, use ✓✗ or [x][+] |
| Nodes overlap | Too complex | Split into multiple diagrams (max 7-10 nodes) |
| Edge labels cut off | Label too long | Shorten to 1-3 words |
| No title showing | Wrong syntax | Use |
| Weird layout | No flow direction | Add or |
| Parse error | Special chars in node | Escape or simplify node names |