--- name: graph-easy description: Create ASCII diagrams for markdown using graph-easy. TRIGGERS - ASCII diagram, graph-easy, architecture diagram, markdown diagram. --- # Graph-Easy Diagram Skill Create ASCII architecture diagrams for any GitHub Flavored Markdown file using graph-easy. Pure text output with automatic layout - no image rendering required. ## When to Use This Skill - Adding diagrams to README files - Design specification documentation - Any GFM markdown file needing architecture visualization - Creating flowcharts, pipelines, or system diagrams - User mentions "diagram", "ASCII diagram", "graph-easy", or "architecture chart" **NOT for ADRs** - Use `adr-graph-easy-architect` for Architecture Decision Records (includes ADR-specific patterns like 2-diagram requirement and before/after templates). ## Preflight Check Run these checks in order. Each layer depends on the previous. ### Layer 1: Package Manager ```bash /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) ```bash # 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 ```bash # 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 ```bash # 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 hangs waiting for stdin AND exits with code 2) echo "[Test] -> [OK]" | graph-easy &>/dev/null && echo "✓ graph-easy ready" ``` ### All-in-One Preflight Script ```bash /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 hangs waiting for stdin AND exits with code 2) 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 ( Frontend: [React App] [API Client] ) ( Backend: [API Server] [Database] ) [API Client] -> [API Server] ``` ### 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 (rocket, bulb, checkmark) - NEVER (double-width breaks box alignment) - Unicode symbols (check, cross, arrow) - 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 | +--------------+ ``` ### 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 | swap | `"Database Migration"` | | Deployment/Release | rocket | `"Deployment Pipeline"` | | Data Flow | chart | `"Data Ingestion Flow"` | | Security/Auth | lock | `"Authentication Flow"` | | Error/Failure | warn | `"Error Handling"` | | Decision/Branch | split | `"Routing Decision"` | | Architecture | build | `"System Architecture"` | | Network/API | globe | `"API Integration"` | | Storage/Database | disk | `"Storage Layer"` | | Monitoring/Observability | signal | `"Monitoring Stack"` | ``` # Title with semantic emoji graph { label: "Deployment Pipeline"; flow: east; } # Title with legend (multiline using \n) graph { label: "Hook Flow\n----------\nAllow Deny Warn"; flow: south; } ``` ### 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 (`{ border: dotted; }`) use special 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 ### Pipeline (Left-to-Right) ``` graph { flow: east; } [Input] -> [Process] -> [Output] ``` ### Multi-Component System ``` graph { flow: south; } [API Gateway] -> [Service A] [API Gateway] -> [Service B] [Service A] -> [Database] [Service B] -> [Database] ``` ### Decision with Options ``` graph { flow: south; } [Decision] -> [Option A] [Decision] -> [Option B] [Decision] -> [Option C] ``` ### Grouped Components ``` ( Frontend: [React App] [Vue App] ) ( Backend: [API Server] [Worker] ) [React App] -> [API Server] [Vue App] -> [API Server] [API Server] -> [Worker] ``` ### Bidirectional Flow ``` [Client] <-> [Server] [Server] -> [Database] ``` ### Layered Architecture ``` graph { flow: south; } ( Presentation: [UI Components] ) ( Business: [Services] ) ( Data: [Repository] [Database] ) [UI Components] -> [Services] [Services] -> [Repository] [Repository] -> [Database] ``` --- ## Part 3: Rendering ### Command (Platform-Aware) ```bash # For GitHub markdown (RECOMMENDED) - renders as solid lines graph-easy --as=ascii << 'EOF' graph { flow: south; } [A] -> [B] -> [C] EOF # For terminal/local viewing - prettier Unicode lines graph-easy --as=boxart << 'EOF' graph { flow: south; } [A] -> [B] -> [C] EOF ``` ### Output Modes | Mode | Command | When to Use | | -------- | ------------- | --------------------------------------------------------------- | | `ascii` | `--as=ascii` | **GitHub markdown** - `+--+` renders as solid lines everywhere | | `boxart` | `--as=boxart` | **Terminal only** - `┌──┐` looks nice locally, dotted on GitHub | **Why ASCII for GitHub?** GitHub's markdown preview renders Unicode box-drawing characters (`┌─┐│└─┘`) as **dotted lines**, breaking the visual appearance. Pure ASCII (`+---+`, `|`) renders correctly as solid lines on all platforms. ### Validation Workflow ```bash # 1. Write DSL to heredoc # 2. Render with ascii (for GitHub) or boxart (for terminal) graph-easy --as=ascii << 'EOF' [Your] -> [Diagram] -> [Here] EOF # 3. Review output # 4. Iterate if needed # 5. Copy final output to markdown # 6. Validate alignment (RECOMMENDED) ``` ### Post-Generation Alignment Validation (Recommended) After embedding diagram in markdown, validate alignment to catch rendering issues. **Use the doc-tools plugin skill:** ``` Skill: doc-tools:ascii-diagram-validator ``` Or invoke directly: `Skill(doc-tools:ascii-diagram-validator)` with the target file path. **Why validate?** - Catches copy-paste alignment drift - Detects font rendering issues - Ensures vertical columns align properly - Graph-easy output is machine-aligned, but manual edits can break it **When to skip**: If diagram was just generated by graph-easy and not manually edited, validation is optional (output is inherently aligned). --- ## Part 4: Embedding in Markdown ### Markdown Format (MANDATORY: Always Include Source) **CRITICAL**: Every rendered diagram MUST be followed by a collapsible `
` 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 ````markdown ## Architecture ``` +----------+ +----------+ +----------+ | Input | --> | Process | --> | Output | +----------+ +----------+ +----------+ ```
graph-easy source ``` graph { flow: east; } [Input] -> [Process] -> [Output] ```
```` **The `
` block is MANDATORY** - never embed a diagram without its source. ### GFM Collapsible Section Syntax GitHub Flavored Markdown supports HTML `
` and `` tags for collapsible sections. Key syntax rules: **Structure:** ```html
Click to expand Content goes here (Markdown supported)
``` **Critical rules:** 1. **Blank lines required** - Must have empty line after `` and before `
` for Markdown to render 2. **No indentation** - `
` and `` must be at column 0 (no leading spaces) 3. **Summary is clickable label** - Text in `` appears as the collapsed header 4. **Markdown inside works** - Code blocks, headers, lists all render correctly inside **Optional: Default expanded:** ```html
Expanded by default Content visible on page load
``` **Common mistake (Markdown won't render):** ```html
Broken No blank line - this won't render as Markdown!
``` **References:** - [GitHub Docs: Collapsed sections](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/organizing-information-with-collapsed-sections) ### Regeneration If the markdown changes, regenerate by running the source through graph-easy again: ```bash # Extract source from
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 | `[x]` | | Changed/Updated | `[*]` | | Warning/Deprecated | `[!]` | | Deferred/Pending | `[~]` | | Current/Active | `[>]` | | Optional | `[?]` | | Locked/Fixed | `[=]` | ### Box Drawing (U+2500-257F) ``` - | + + + + + + + + + (light) = | + + + + + + + + + (double) ``` ### Arrows & Pointers ``` -> <- up down (arrows) v ^ (logic - graph-easy uses these) < > ^ v (ASCII arrows) ``` ### Shapes & Bullets ``` * o O (bullets) [ ] # (squares) < > <> (diamonds) ``` --- ## 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: "🚀 Deployment Pipeline"; flow: east; } [Build] -> [Test] -> [Deploy] ``` ### Anti-Pattern (INVALID - DO NOT DO THIS) ``` graph { flow: east; } [Build] -> [Test] -> [Deploy] ``` **Why this is wrong**: Missing `label:` with emoji. Every diagram needs context at a glance. --- ## Mandatory Checklist (Before Rendering) ### Graph-Level (MUST have) - [ ] **`graph { label: "🚀 Title"; }`** - semantic emoji + title (MOST FORGOTTEN - check first!) - [ ] `graph { flow: south; }` or `graph { flow: east; }` - explicit direction - [ ] Command uses `--as=ascii` for GitHub markdown (or `--as=boxart` for terminal only) ### Embedding (MUST have - non-negotiable) - [ ] **`
` block with source** - EVERY diagram MUST have collapsible source code block - [ ] Format: rendered diagram in code block, followed immediately by `
graph-easy source` with source in code block - [ ] Never commit a diagram without its reproducible source ### Post-Embedding Validation (Recommended) - [ ] Run `ascii-diagram-validator` on the file after embedding diagram - [ ] Especially important if diagram was manually edited after generation - [ ] Catches alignment drift from copy-paste or font rendering issues ### Node Styling (Visual hierarchy) - [ ] Start/end nodes: `{ shape: rounded; }` - entry/exit points - [ ] Critical/important nodes: `{ border: double; }` or `{ border: bold; }` - [ ] Optional/skippable nodes: `{ border: dotted; }` - [ ] Default nodes: no styling (standard border) - [ ] Long labels use `\n` for multiline - max ~15 chars per line ### 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 (single-width) - [ ] ASCII markers ALWAYS safe ([x] [+] [!] [OK]) - [ ] Graphical emojis ONLY in `graph { label: "..."; }` title ### Structure (Organization) - [ ] Groups `( Name: ... )` used for logical clustering when 4+ related nodes - [ ] Node IDs short, labels descriptive: `[db] { label: "PostgreSQL"; }` - [ ] No more than 7-10 nodes per diagram (split if larger) ## Success Criteria ### Correctness 1. **Parses without error** - graph-easy accepts the DSL 2. **Renders cleanly** - no misaligned boxes or broken lines 3. **Matches content** - all key elements from description represented 4. **Source preserved (MANDATORY)** - EVERY diagram MUST have `
` block with graph-easy DSL source immediately after the rendered output ### Aesthetics 1. **Platform-appropriate output** - `--as=ascii` for GitHub (solid lines), `--as=boxart` for terminal only 2. **Readable labels** - multiline with `\n`, no truncation 3. **Clear flow** - direction matches natural reading (top-down or left-right) 4. **Consistent styling** - same border style = same semantic meaning throughout ### Comprehensiveness 1. **Edge semantics** - solid=normal, dotted=conditional, bold=critical 2. **Logical grouping** - related nodes in `( Group: ... )` containers ## Troubleshooting | Issue | Cause | Solution | | ------------------- | ------------------------ | --------------------------------------------- | | `command not found` | graph-easy not installed | Run preflight check | | Dotted lines on GH | Used `--as=boxart` | Use `--as=ascii` for GitHub markdown | | Box border broken | Graphical emoji in node | Remove emojis, use ASCII markers [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 `graph { label: "Title"; flow: south; }` | | Weird layout | No flow direction | Add `graph { flow: south; }` or `flow: east` | | Parse error | Special chars in node | Escape or simplify node names | ## Resources - [Graph::Easy on CPAN](https://metacpan.org/dist/Graph-Easy) - [Graph::Easy Manual](http://bloodgate.com/perl/graph/manual/) - [Graph::Easy GitHub](https://github.com/ironcamel/Graph-Easy)