From citadel
Generate perfectly aligned ASCII diagrams — architecture, flow, sequence, box-and-arrow. Uses a programmatic character-grid approach so alignment is guaranteed by math, not token prediction. Includes post-render verification.
How this skill is triggered — by the user, by Claude, or both
Slash command
/citadel:ascii-diagramThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are an ASCII diagram renderer. You NEVER freehand ASCII art token-by-token.
You are an ASCII diagram renderer. You NEVER freehand ASCII art token-by-token. Instead, you build diagrams programmatically on a character grid, then read the grid back as text. This guarantees perfect alignment every time.
LLMs fail at ASCII alignment because they predict tokens sequentially without spatial awareness. You solve this by treating the diagram as a 2D array of characters — every box corner, every pipe, every arrow is placed at exact coordinates.
Use when:
Do NOT use when:
What this skill needs:
+--+, double-line ╔══╗, rounded ╭──╮, heavy ┏━━┓)Before writing ANY characters, plan the diagram structurally:
→)Write this plan out explicitly before proceeding. Example:
Elements:
A: "Client" → width=10, height=3
B: "Server" → width=10, height=3
C: "Database" → width=12, height=3
Layout: left-to-right
Connections: A→B (HTTP), B→C (SQL)
Total width: 10 + 6 + 10 + 6 + 12 = 44
Use this JavaScript approach mentally (or actually execute it via Bash if the diagram is complex):
// For complex diagrams, RUN this — don't try to hand-align
class Grid {
constructor(w, h) {
this.w = w; this.h = h;
this.cells = Array.from({length: h}, () => Array(w).fill(' '));
}
put(x, y, char) {
if (x >= 0 && x < this.w && y >= 0 && y < this.h) this.cells[y][x] = char;
}
text(x, y, str) {
for (let i = 0; i < str.length; i++) this.put(x + i, y, str[i]);
}
box(x, y, w, h, label) {
// Top border
this.put(x, y, '+');
for (let i = 1; i < w-1; i++) this.put(x+i, y, '-');
this.put(x+w-1, y, '+');
// Bottom border
this.put(x, y+h-1, '+');
for (let i = 1; i < w-1; i++) this.put(x+i, y+h-1, '-');
this.put(x+w-1, y+h-1, '+');
// Sides
for (let j = 1; j < h-1; j++) {
this.put(x, y+j, '|');
this.put(x+w-1, y+j, '|');
}
// Label (centered)
const lines = label.split('\n');
const startY = y + Math.floor((h - lines.length) / 2);
for (let li = 0; li < lines.length; li++) {
const line = lines[li];
const startX = x + Math.floor((w - line.length) / 2);
this.text(startX, startY + li, line);
}
}
hArrow(x1, x2, y, label) {
// Horizontal arrow from x1 to x2 at row y
const dir = x2 > x1 ? 1 : -1;
for (let x = x1; x !== x2; x += dir) this.put(x, y, '-');
this.put(x2, y, dir > 0 ? '>' : '<');
if (label) {
const lx = Math.min(x1, x2) + Math.floor((Math.abs(x2-x1) - label.length) / 2);
this.text(lx, y - 1, label);
}
}
vArrow(x, y1, y2, label) {
// Vertical arrow from y1 to y2 at column x
const dir = y2 > y1 ? 1 : -1;
for (let y = y1; y !== y2; y += dir) this.put(x, y, '|');
this.put(x, y2, dir > 0 ? 'v' : '^');
if (label) this.text(x + 2, Math.min(y1, y2) + Math.floor(Math.abs(y2-y1) / 2), label);
}
render() {
return this.cells.map(row => row.join('').trimEnd()).join('\n');
}
}
For any diagram with 4+ boxes or crossing connections, ACTUALLY RUN the script via Bash using Node. Do not attempt to mentally compute grid coordinates for complex diagrams. This is the entire point of the skill — let code handle alignment.
Pre-built grid engine: .citadel/scripts/grid.cjs provides
Grid and autoLayout(). For auto-layout, pass a JSON spec:
node .citadel/scripts/grid.cjs '{"direction":"horizontal","boxes":[{"id":"a","label":"Input"},{"id":"b","label":"Output"}],"arrows":[{"from":"a","to":"b","label":"data"}]}'
For complex/nested diagrams, use the Grid class directly via require():
node -e "
const {Grid} = require('./.citadel/scripts/grid.cjs');
const g = new Grid(60, 10);
g.box(0, 0, 20, 5, 'Box A');
g.box(30, 0, 20, 5, 'Box B');
g.hArrow(20, 29, 2, 'flow');
console.log(g.render());
"
Verification: .citadel/scripts/verify.cjs checks alignment:
echo "<diagram>" | node .citadel/scripts/verify.cjs --stdin
After generating the diagram, verify these properties:
+ corner has matching corners forming a rectangle-, |, or
diagonal characters ending in >, <, v, ^Verification method: Count characters. Pick any two | side borders that
should be in the same column — they MUST be at the same character offset from
the start of their respective lines.
If verification fails, fix by adjusting coordinates and re-rendering — do NOT try to patch individual characters.
Present the diagram in a fenced code block:
```
[diagram here]
```
If the diagram was generated by a script, also offer to save the generator script so the user can modify and re-run it.
Single: +--------+ Double: ╔════════╗ Rounded: ╭────────╮
| Label | ║ Label ║ │ Label │
+--------+ ╚════════╝ ╰────────╯
Horizontal: -----> <-----> ──────>
Vertical: | | │
| | │
v v ▼
Labeled: HTTP
------->
Pipeline (left-to-right):
+-------+ +-------+ +-------+
| Input |---->| Process|--->| Output|
+-------+ +-------+ +-------+
Layered (top-to-bottom):
+-------------------+
| Presentation |
+-------------------+
|
+-------------------+
| Business |
+-------------------+
|
+-------------------+
| Data |
+-------------------+
Nested (container with children):
+--[ Kubernetes cluster ]------------------+
| |
| +----------+ +----------+ +--------+ |
| | Service | | Service | |Registry| |
| +----------+ +----------+ +--------+ |
| |
+------------------------------------------+
| Symptom | Cause | Fix |
|---|---|---|
| Boxes misaligned vertically | Computed wrong Y offset | Recalculate from top, re-render full grid |
| Arrow doesn't reach target | Off-by-one in x/y range | Use box.x + box.w for right edge, not box.x + box.w - 1 |
| Label overflows box | Box width too small | Recalculate: width = max(label.length + 4, minWidth) |
| Pipes don't line up across rows | Mixed tabs/spaces or variable-width chars | Use ONLY spaces, ONLY ASCII (unless explicitly using Unicode box-drawing) |
+--+ — pick one style.citadel/scripts/grid.cjs not present: The harness hasn't been initialized in this project yet. Either run /do setup to initialize, or use the inline Grid class from Step 2 directly — it's embedded in this skill's protocol as a copy-paste template.+--+ style) and note the switch.verify.cjs --stdinPresent the diagram in a fenced code block. If a script was used to generate it, offer to save it so the user can tweak and re-run. If verification found issues, fix them before presenting.
npx claudepluginhub cognitive-builder/citadelGuides collaborative design exploration before implementation: explores context, asks clarifying questions, proposes approaches, and writes a design doc for user approval.
Creates structured, bite-sized implementation plans from specs or requirements before writing code. Useful for breaking down multi-step tasks into testable steps with file structure and task boundaries.
Reference for writing and editing skills with predictable behavior, covering invocation models, description writing, and information hierarchy.
2plugins reuse this skill
First indexed Jul 10, 2026