From citadel
Generates perfectly aligned ASCII diagrams for architecture, flow, sequence, box-and-arrow using programmatic character-grid layout planning and post-render verification. Embed in markdown, code comments, or plain text.
npx claudepluginhub sethgammon/citadel --plugin citadelThis skill uses the workspace's default tool permissions.
**Use when:**
Generates plain ASCII box-flow diagrams (boxes + arrows) for plain-text environments like terminals without renderers. Supports alignment rules, truncation, and split strategies for complex graphs up to 12 nodes.
Provides ASCII diagram patterns for architecture, workflows, file trees, and data visualizations. Use for terminal-rendered box-drawing layouts, progress bars, swimlanes, and blast radius charts.
Generates ASCII art diagrams for charts, flowcharts, presentations, and visual documentation. Activates automatically on ASCII art diagram creator requests.
Share bugs, ideas, or general feedback.
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 --stdinDisclosure: "Generating ASCII diagram. Output to screen (or file if requested)." Reversibility: green — outputs ASCII diagram to screen or a new file; no existing files modified Trust gates:
Present 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.