|
|
@@ -1,281 +1,1153 @@
|
|
|
-# Terminal Output Design Language
|
|
|
+# Terminal Panel Design System
|
|
|
|
|
|
-> Status: **experimental**. The first skill on this language is `fleet-ops`.
|
|
|
-> New output-heavy skills should follow this guide and source `skills/_lib/term.sh`.
|
|
|
+> **Status:** Experimental. First consumer: `fleet-ops`.
|
|
|
+>
|
|
|
+> **Format:** Adapted from [google-labs-code/design.md](https://github.com/google-labs-code/design.md) — a structured design-spec template — and remapped to bash CLIs. Where that spec talks about screens, components, and tokens, this one talks about panels, sections, and glyphs.
|
|
|
|
|
|
-claude-mods ships ~70 skills, many of which write to a TTY (`fleet-ops`,
|
|
|
-`git-ops`, `push-gate`, `sync`, ...). When you run five of them in one session
|
|
|
-and each rolled its own glyphs and dividers, the toolkit feels like five
|
|
|
-toolkits. This document is the forcing function: one palette, one helper
|
|
|
-library, one shape.
|
|
|
+---
|
|
|
|
|
|
-## Principles
|
|
|
+## 1. Vision
|
|
|
|
|
|
-1. **Readable first, structured second, decorative last.** A pipe-friendly
|
|
|
- plaintext line beats a beautiful one nobody can grep.
|
|
|
-2. **ASCII fallback is mandatory.** Every Unicode glyph has an ASCII twin.
|
|
|
- Honor `TERM_ASCII=1`, `LANG` without UTF-8, and `TERM=dumb`.
|
|
|
-3. **Respect the pipe.** No color into non-TTY stdout. Honor `NO_COLOR`.
|
|
|
- `FORCE_COLOR=1` overrides for CI tooling that wants ANSI in logs.
|
|
|
-4. **One screen of output preferred.** A status command should fit in 24
|
|
|
- lines on a default terminal. Long output earns its length.
|
|
|
-5. **80 columns is the ceiling.** Some users still split panes. Tables that
|
|
|
- exceed it must wrap or truncate, not scroll horizontally.
|
|
|
-6. **Color is signal, not skin.** Never use color as the *only* differentiator.
|
|
|
- Glyphs and labels carry the meaning; color amplifies.
|
|
|
+A unified terminal-output design language for bash-based CLIs in the claude-mods family. One panel grammar, one set of glyphs, one grid. Tools that follow it feel like instruments on the same workbench instead of seventy hand-rolled formats.
|
|
|
|
|
|
-## Glyph Palette
|
|
|
+The aspiration: outputs that read as **deliberate, bespoke, and quiet** — like a well-laid PCB. Every glyph in its place, nothing decorative, nothing shouting. When a user runs five tools in a session, the toolkit feels coherent.
|
|
|
|
|
|
-State icons. Use through `term_state_icon` when possible; the literals are
|
|
|
-listed for cross-reference.
|
|
|
+---
|
|
|
|
|
|
-| Meaning | Unicode | ASCII | Color | Use for |
|
|
|
-| ------- | ------- | ----- | ------- | -------------------------------- |
|
|
|
-| pending | ⏳ | `[.]` | yellow | running, queued, in-flight |
|
|
|
-| ready | ✅ | `[+]` | green | passed, ready to land |
|
|
|
-| done | 🚀 | `[*]` | green | merged, shipped, terminal good |
|
|
|
-| failed | ❌ | `[x]` | red | tests failed, refused, blocked |
|
|
|
-| warning | ⚠️ | `[!]` | yellow | conflict, hygiene flag |
|
|
|
-| hint | 💡 | `[i]` | cyan | suggestion, next-step pointer |
|
|
|
+## 2. Principles
|
|
|
|
|
|
-> Don't introduce new state glyphs without adding them here and to
|
|
|
-> `term_state_icon`. Improvising glyphs is what got us here.
|
|
|
+1. **Information first, ornament last.** Decoration that doesn't carry meaning gets cut.
|
|
|
+2. **Strip color and the layout still works.** Color amplifies; it never carries the only signal.
|
|
|
+3. **ASCII fallback is mandatory.** Every Unicode glyph has a 1–3 char ASCII proxy registered alongside it.
|
|
|
+4. **Use the invisible grid, not lines, to align.** Whitespace between columns aligns rows. Long horizontal rules are clutter.
|
|
|
+5. **Tether to the left.** Primary content rides the left rail. Right-side elements are leaves or iconography, never floating UI.
|
|
|
+6. **Let elements breathe.** Blank `│` rows between sections are content. Density without breath is unreadable.
|
|
|
+7. **Pops of color are dopamine; everywhere is wallpaper.** One brand emoji in the header, two health indicators in the footer, color on state words. That's the budget.
|
|
|
+8. **Borders are continuous.** Top and bottom rules run uninterrupted from corner to terminator. Gaps break the panel's "wrap the interface" feel.
|
|
|
+9. **One style per diagram.** Pick rounded corners, stick with rounded corners. Don't mix box families.
|
|
|
+10. **Same width, taller height for emphasis** — never wider. Width consistency is what makes columns line up; height variation gives presence without breaking the grid.
|
|
|
+11. **Bespoke, not branded.** No ASCII art logos. No flashy gradients. The polish is in placement and restraint.
|
|
|
|
|
|
-## Box Drawing
|
|
|
+---
|
|
|
|
|
|
-Use sparingly — borders that wrap nothing waste lines.
|
|
|
+## 3. Foundations
|
|
|
|
|
|
-| Role | Unicode | ASCII |
|
|
|
-| ----------- | ------------ | ------- |
|
|
|
-| horizontal | `─` | `-` |
|
|
|
-| vertical | `│` | `\|` |
|
|
|
-| corners | `┌ ┐ └ ┘` | `+` |
|
|
|
-| connectors | `├ ┤ ┬ ┴ ┼` | `+` |
|
|
|
-| tree branch | `├─ └─ │` | `+- \`- \|` |
|
|
|
+### 3.1 Color tokens
|
|
|
|
|
|
-`term_header` and `term_divider` already pick the right glyph based on
|
|
|
-`TERM_ASCII_MODE`. Reach for them before drawing your own boxes.
|
|
|
+Color is signal, never the only signal. Disabled when stdout isn't a TTY or `NO_COLOR` is set; forced on with `FORCE_COLOR=1`.
|
|
|
|
|
|
-## Layouts
|
|
|
+| Token | ANSI | Use for |
|
|
|
+| ------------- | ------- | -------------------------------------------------------- |
|
|
|
+| `accent` | cyan | Brand chrome (panel rules, hotkey letters, header rule) |
|
|
|
+| `pending` | yellow | RUNNING, CONFLICT, modified files, HEAD marker |
|
|
|
+| `ok` | green | READY, LANDED, healthy daemon, landed commits |
|
|
|
+| `alarm` | red | FAILED, blocked, conflicts, critical health |
|
|
|
+| `warn` | orange | Warning alerts, the inline alert triangle |
|
|
|
+| `tag` | magenta | Untracked files (lazygit/magit convention) |
|
|
|
+| `meta` | dim | Counts, ages, base branch, timestamps, dotted leaders |
|
|
|
+| `default` | fg | Branch names, file paths — the content the user came for |
|
|
|
|
|
|
-The default layout is **rule + grouped tree**: a horizontal-line "app
|
|
|
-header" on top, then items grouped by state with tree connectors. Flat
|
|
|
-tables are reserved for one-row-per-thing data where grouping would just
|
|
|
-add noise.
|
|
|
+### 3.2 Glyph palette
|
|
|
|
|
|
-### Header rule (the "app header")
|
|
|
+Every glyph below is registered with an ASCII fallback in `term.sh`. Don't introduce new ones without registering them.
|
|
|
|
|
|
-Always present. Title in cyan, trailing meta in dim. The rule extends to
|
|
|
-terminal width so the header reads as the section's banner.
|
|
|
+#### Panel and tree connectors
|
|
|
+
|
|
|
+| Role | Unicode | ASCII | Notes |
|
|
|
+| ----------------- | ------- | ------- | --------------------------------------- |
|
|
|
+| corner: panel TL | `╭` | `+` | Rounded — for the outer panel only |
|
|
|
+| corner: panel TR | `╮` | `+` | Rounded |
|
|
|
+| corner: panel BL | `╰` | `+` | Rounded |
|
|
|
+| corner: panel BR | `╯` | `+` | Rounded |
|
|
|
+| T-junction | `├` | `+` | Section attachment point |
|
|
|
+| L-corner | `└` | `` ` `` | Last leaf in a section |
|
|
|
+| horizontal | `─` | `-` | Rule fill |
|
|
|
+| vertical | `│` | `\|` | Panel left edge, section continuation |
|
|
|
+
|
|
|
+#### Rail glyphs (commit-graph and pipeline beads)
|
|
|
+
|
|
|
+| Role | Unicode | ASCII | Meaning |
|
|
|
+| ------------------ | ------- | ----- | -------------------------------- |
|
|
|
+| commit (landed) | `●` | `*` | a commit on the rail |
|
|
|
+| HEAD | `◉` | `@` | tip of the lane |
|
|
|
+| conflict | `⊗` | `X` | rebase / merge failure point |
|
|
|
+| link | `─` | `-` | rail segment between commits |
|
|
|
+
|
|
|
+#### Pip-bar glyphs (progress / completion)
|
|
|
+
|
|
|
+| Role | Unicode | ASCII |
|
|
|
+| ---------- | ------- | ----- |
|
|
|
+| pip filled | `▰` | `#` |
|
|
|
+| pip empty | `▱` | `-` |
|
|
|
+
|
|
|
+Default width: **10 pips** = clean 10% increments. Override only when the data has a natural denominator that isn't a percentage (`5 of 7 stages` → 7 pips).
|
|
|
+
|
|
|
+#### Health indicators (small bullets, colored)
|
|
|
+
|
|
|
+| Role | Unicode | ASCII | Notes |
|
|
|
+| -------- | ------- | ------- | --------------------------------------- |
|
|
|
+| healthy | `•` | `(+)` | Green, slowly pulsing in live mode |
|
|
|
+| pending | `•` | `(.)` | Yellow |
|
|
|
+| warning | `•` | `(!)` | Orange |
|
|
|
+| critical | `•` | `(!!)` | Red |
|
|
|
+| busted | `⬤` | `(X)` | LARGE grey, motionless — unmissable |
|
|
|
+| unknown | `•` | `(?)` | Dim |
|
|
|
+
|
|
|
+`•` (BULLET, U+2022) is smaller than `●` and reads as a tidy dot when colored. `⬤` (BLACK LARGE CIRCLE, U+2B24) is intentionally bigger to make a busted state unmissable.
|
|
|
+
|
|
|
+#### The terminator dot
|
|
|
+
|
|
|
+`●` is reserved as the right-edge terminator on header and footer rules. **Never** used as an inline divider, decorator, or health indicator. One job, one place.
|
|
|
+
|
|
|
+#### Brand emoji registry
|
|
|
+
|
|
|
+| Tool | Unicode | ASCII |
|
|
|
+| ------ | ------- | ----- |
|
|
|
+| fleet | ⚡ | `[F]` |
|
|
|
+| forge | 🔨 | `[B]` |
|
|
|
+| psql | 🐘 | `[P]` |
|
|
|
+| watch | 📡 | `[M]` |
|
|
|
+| deploy | 🚀 | `[D]` |
|
|
|
+| git | 🌿 | `[G]` |
|
|
|
+
|
|
|
+#### Header indicators
|
|
|
+
|
|
|
+| Role | Unicode | ASCII | Use for |
|
|
|
+| --------------- | ------- | ----- | ---------------------------------- |
|
|
|
+| branch | `⎇` | `(b)` | `⎇ main` — base branch indicator |
|
|
|
+
|
|
|
+#### Inline alert
|
|
|
+
|
|
|
+| Role | Unicode | ASCII | Color |
|
|
|
+| -------- | ------- | ----- | ------ |
|
|
|
+| warning | `▲` | `!` | orange |
|
|
|
+| critical | `▲` | `!` | red |
|
|
|
+
|
|
|
+#### Empty state
|
|
|
+
|
|
|
+| Role | Unicode | ASCII |
|
|
|
+| ---- | ------- | ----- |
|
|
|
+| tip | `💡` | `(i)` |
|
|
|
+
|
|
|
+#### Spinners (live mode only)
|
|
|
+
|
|
|
+Three families, each with a different role:
|
|
|
+
|
|
|
+**Working** — task actively progressing. Fast, 10 frames, ~80ms/frame.
|
|
|
+```
|
|
|
+⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏
|
|
|
+```
|
|
|
+ASCII fallback: `| / - \` (classic 4-frame).
|
|
|
+
|
|
|
+**Heartbeat** — daemon proof-of-life. Slow, 6 frames, ~600ms/cycle.
|
|
|
+```
|
|
|
+· ∙ • ● • ∙
|
|
|
+```
|
|
|
+ASCII fallback: `. : * :`. Used in the footer health-indicator slot. Stops and goes grey when the daemon is busted.
|
|
|
+
|
|
|
+### 3.3 Spacing & the invisible grid
|
|
|
+
|
|
|
+Layout is built on whitespace alignment, not vertical bars. The grid for a leaf row in a panel:
|
|
|
+
|
|
|
+```
|
|
|
+[panel-vert] [section-indent] [tree-conn] [name-col] [rail-col] [meta-col] [age-col]
|
|
|
+ │ ···· ├── 32 chars 14 chars 12 chars 6 chars
|
|
|
+```
|
|
|
+
|
|
|
+- **Panel vertical** — column 0, the panel's `│`.
|
|
|
+- **Section indent** — 4 cols of breathing room inside the panel.
|
|
|
+- **Tree connector** — `├──` or `└──` (4 cols including trailing space).
|
|
|
+- **Name column** — 32 cols, ellipsis-truncated past that (`feat/oauth-pkce-with-very-long…`).
|
|
|
+- **Rail column** — 14 cols, right-padded with spaces to align the next column.
|
|
|
+- **Meta column** — 12 cols (e.g., `M4 ?1`, `clean`, `blocked`).
|
|
|
+- **Age column** — 6 cols, right-aligned.
|
|
|
+
|
|
|
+These widths target an **80-col default**. They scale: a `--wide=120` mode bumps name to 48 and rail to 20. They never exceed terminal width — at <60 cols, drop the rail and meta columns rather than wrap.
|
|
|
+
|
|
|
+Section rows ride the same indent: `│ ` (panel + 3 spaces) to land at the section-indent column.
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 4. Components
|
|
|
+
|
|
|
+### 4.1 Panel
|
|
|
+
|
|
|
+The outer frame: header bar, body, footer bar. The body is wrapped by the panel's `│` running unbroken from `╭──` down to `╰──`.
|
|
|
+
|
|
|
+```
|
|
|
+╭── ⚡ fleet ───────────────────────────────── ⎇ main ───●
|
|
|
+│
|
|
|
+[body]
|
|
|
+│
|
|
|
+╰── R refresh · L land · ? help ───── • daemon • 17m ───●
|
|
|
+```
|
|
|
+
|
|
|
+**Rules**
|
|
|
+- Top rule starts at column 0 with `╭──`, ends at the right with terminator `●`.
|
|
|
+- Bottom rule mirrors with `╰──` and a terminator.
|
|
|
+- The rules have no whitespace gaps. `─` fills every span between elements.
|
|
|
+- Body lives between the rules; every body line begins with `│`.
|
|
|
+
|
|
|
+**Helper:** `term_panel_open` / `term_panel_close`.
|
|
|
+
|
|
|
+### 4.2 Header bar
|
|
|
+
|
|
|
+```
|
|
|
+╭── ⚡ fleet ───────────────────────────────── ⎇ main ───●
|
|
|
+ └┬─┘ └─┬─┘ └──┬──┘ └┬┘
|
|
|
+ │ │ │ └─ terminator
|
|
|
+ │ └─ tool name (cyan) └─ right indicator (≤ 1)
|
|
|
+ └─ brand emoji (always before name)
|
|
|
+```
|
|
|
+
|
|
|
+**Rules**
|
|
|
+- **Brand emoji + tool name** at top-left, in that order, always. The emoji *is* the tool's identity at a glance.
|
|
|
+- **One indicator** at top-right max — typically a context tag (`⎇ main`, `db: production`, `region: us-east`). Format: `<icon> <value>` or `key: value` in dim.
|
|
|
+- The rule (`─`) fills every gap between brand and indicator and indicator and terminator.
|
|
|
+
|
|
|
+**Helper:** `term_panel_open <emoji_key> <name> <indicator>`.
|
|
|
+
|
|
|
+### 4.3 Footer bar
|
|
|
+
|
|
|
+```
|
|
|
+╰── R refresh · L land · ? help ───── • daemon • 17m ───●
|
|
|
+ └─────────┬──────────┘ └────┬─────┘ └┬┘
|
|
|
+ │ │ └─ terminator
|
|
|
+ │ └─ health indicators (≤ 2)
|
|
|
+ └─ hotkeys (≤ 3)
|
|
|
+```
|
|
|
+
|
|
|
+**Rules**
|
|
|
+- **Up to 3 hotkeys** at bottom-left, format `<key> <verb>`, separated by `·`. Hotkey letters in cyan.
|
|
|
+- **Up to 2 health indicators** at bottom-right, format `• <text>`. **Two spaces** between indicators (no `·` separator — `•` is already a strong leading marker).
|
|
|
+- Continuous rule `─` fills the gap between hotkeys and health.
|
|
|
+- `●` terminator at far right.
|
|
|
+
|
|
|
+**Helper:** `term_panel_close <hotkeys> <healths>`.
|
|
|
+
|
|
|
+### 4.4 Section
|
|
|
+
|
|
|
+A grouped block under the header. Section labels are colored by state; no glyph at the junction, no trailing rule.
|
|
|
+
|
|
|
+```
|
|
|
+├── RUNNING (2)
|
|
|
+│ ├── feat/oauth-pkce ●─●─●─◉ M4 ?1 12m
|
|
|
+│ └── spike/wasm-eval ●─●─●─●─◉ M7 34m
|
|
|
+│
|
|
|
+├── READY (2)
|
|
|
+│ ├── fix/cache-bust ●─◉ clean 2m
|
|
|
+│ └── chore/bump-axios ●─◉ clean 5m
|
|
|
+```
|
|
|
+
|
|
|
+**Rules**
|
|
|
+- Section header: `├── LABEL (count)`, label colored by state.
|
|
|
+- No icon at the junction. State is carried by the **label color** plus the **label text**.
|
|
|
+- One blank `│` row of breath between sections — never zero, never two.
|
|
|
+- Empty sections are omitted; never render `(0)`.
|
|
|
+
|
|
|
+**Helper:** `term_section <state> <label> <count>`.
|
|
|
+
|
|
|
+### 4.5 Summary line
|
|
|
+
|
|
|
+A metadata-only branch of the panel. Tethers to the left rail like a section but renders in dim because it's reference, not actionable.
|
|
|
+
|
|
|
+```
|
|
|
+├── 4 lanes · 3 active
|
|
|
+```
|
|
|
+
|
|
|
+**Rules**
|
|
|
+- Same `├──` connector as a section.
|
|
|
+- No count in parens (it's a label, not a bucket).
|
|
|
+- Rendered dim throughout so it visually recedes below the colored state sections.
|
|
|
+- One blank `│` row above and below.
|
|
|
+
|
|
|
+### 4.6 Toast row
|
|
|
+
|
|
|
+A transient announcement at the top of the body, just under the header rule.
|
|
|
|
|
|
```
|
|
|
-── fleet ───────────────────────────────────────────────────── 4 lanes · 3 active
|
|
|
+╭── ⚡ fleet ────────────────────────────────── ⎇ main ───●
|
|
|
+│
|
|
|
+├── ⚡ feat/oauth-pkce just LANDED ← toast: dim cyan, fades
|
|
|
+│
|
|
|
+├── 4 lanes · 3 active
|
|
|
```
|
|
|
|
|
|
-### Grouped tree (default body)
|
|
|
+**Rules**
|
|
|
+- **At most one toast** at a time. Older toasts get replaced, not stacked.
|
|
|
+- Brand emoji leads the toast — reinforces "this is fleet news."
|
|
|
+- Color: dim cyan on the leading emoji, default fg on the message.
|
|
|
+- Lifetime: until next render in static mode; ~3s in live mode.
|
|
|
|
|
|
-**Tree-control rule:** the connectors `├─ │ └─` are the scaffold.
|
|
|
-**Nothing sits at a junction.** A junction is the point where a node's
|
|
|
-connector meets its parent's vertical — putting a glyph there breaks
|
|
|
-the eye-line that gives the tree its meaning.
|
|
|
+### 4.7 Inline alert
|
|
|
|
|
|
-- Group headers (interior nodes — they have children below) get **no
|
|
|
- icon**. State is carried by the label text plus color.
|
|
|
-- Leaves (terminal nodes — nothing continues below them) **may** carry
|
|
|
- an icon, since there's no vertical line to interrupt.
|
|
|
-- If you find yourself wanting an icon on an interior node, ask whether
|
|
|
- it's really a group or just a decorated leaf — the answer is usually
|
|
|
- the latter.
|
|
|
+A sub-row attached under a leaf, drawing attention without disrupting structure.
|
|
|
|
|
|
-#### 2-level: groups → leaves
|
|
|
+```
|
|
|
+│ ├── feat/audit-log ●─●─⊗ blocked 17m
|
|
|
+│ │ ▲ rebase against main failed at 4ff21e6
|
|
|
+│ └── feat/oauth-pkce ●─●─●─◉ M4 ?1 12m
|
|
|
+```
|
|
|
+
|
|
|
+**Rules**
|
|
|
+- Sub-row only — never replaces the leaf headline.
|
|
|
+- `▲` triangle leads the message, colored by severity:
|
|
|
+ - orange = warning, recoverable
|
|
|
+ - red = critical, blocks progress
|
|
|
+- Indented under the leaf's `│` continuation (column 8 in the standard grid).
|
|
|
+- ASCII fallback: `!`.
|
|
|
+
|
|
|
+### 4.8 Leaf
|
|
|
+
|
|
|
+A single row inside a section. The atomic unit of content.
|
|
|
+
|
|
|
+```
|
|
|
+│ ├── feat/oauth-pkce ●─●─●─◉ M4 ?1 12m
|
|
|
+ └┬─┘ └────────┬────────┘ └───┬───┘ └──┬──┘ └┬┘
|
|
|
+ │ │ │ │ └─ age (right-aligned)
|
|
|
+ │ │ │ └─ meta (file-status shorthand)
|
|
|
+ │ │ └─ leaf glyph (one style only)
|
|
|
+ │ └─ name (ellipsis-truncate at column boundary)
|
|
|
+ └─ tree connector (├── except last sibling = └──)
|
|
|
+```
|
|
|
+
|
|
|
+**Rules**
|
|
|
+- **Choose one leaf glyph style per panel.** Rail (`●─●─◉`) for git-style data. Pip bar (`▰▰▰▱`) for percentage-style. Don't mix in the same panel.
|
|
|
+- **All columns conform to the grid.** The rail/pip column is fixed-width and right-padded; meta and age land in their own columns.
|
|
|
+- **Health/icon indicator on a leaf goes at the START** of the row, before the name — only when the indicator is *useful* on a per-leaf basis (typically only in flat / ungrouped views — in grouped views the section already conveys state).
|
|
|
+- **Long names ellipsis-truncate** at the name column boundary: `feat/oauth-pkce-with-very-long…`. Don't word-wrap in the body — wrapping breaks the grid.
|
|
|
|
|
|
-The default for state-bucketed views (lanes, PR checks, jobs). Group
|
|
|
-labels read as plain text, the `│` runs unbroken down column 0.
|
|
|
+**Helper:** `term_leaf <name> <rail_or_pips> <meta> <age>`.
|
|
|
+
|
|
|
+### 4.9 Rail (commit / pipeline graph)
|
|
|
|
|
|
```
|
|
|
-── fleet ───────────────────────────────────────────────────── 4 lanes · 3 active
|
|
|
-├─ RUNNING (2)
|
|
|
-│ ├─ feat/auth-rewrite 12m
|
|
|
-│ └─ spike/wasm-eval 34m
|
|
|
-├─ READY (1)
|
|
|
-│ └─ fix/cache-bust 2m
|
|
|
-└─ LANDED (1)
|
|
|
- └─ chore/bump-deps 1h
|
|
|
+●─●─●─◉ a 3-commit lane with HEAD
|
|
|
+●─●─●─●─◉ a 4-commit lane
|
|
|
+●─◉ 1 commit ahead
|
|
|
+●─●─⊗ conflict at the third commit
|
|
|
+─ empty rail (queued, no commits yet)
|
|
|
```
|
|
|
|
|
|
-The double space after each connector (`├─ ` + leading space on the
|
|
|
-label) gives the eye a small breath before the label, reinforcing that
|
|
|
-the connector is structural and the label is content.
|
|
|
+**Rules**
|
|
|
+- Use only on leaves whose data is naturally a chain (commits, pipeline stages).
|
|
|
+- Right-pad to the rail column width so subsequent columns align.
|
|
|
+- HEAD marker (`◉`) is always last; conflict marker (`⊗`) replaces HEAD at the failure point.
|
|
|
+
|
|
|
+**Helper:** `term_rail <commits_ahead> <head_state>`.
|
|
|
+
|
|
|
+### 4.10 Pip bar (progress / completion)
|
|
|
+
|
|
|
+#### Anatomy
|
|
|
+
|
|
|
+```
|
|
|
+▰▰▰▱▱▱▱▱▱▱ 30%
|
|
|
+└─┘└──────┘
|
|
|
+filled empty
|
|
|
+state-color dim
|
|
|
+```
|
|
|
+
|
|
|
+- **Default width: 10 pips.** Clean 10% increments, easy mental math.
|
|
|
+- **Override only for natural denominators** that aren't percentage (`5 of 7 stages` → 7 pips).
|
|
|
+- **Filled pip color** = state color (depends on metric type, see below).
|
|
|
+- **Empty pip color** = dim grey, always.
|
|
|
+
|
|
|
+#### Color by metric type
|
|
|
|
|
|
-Why grouped instead of flat: when ten lanes are in flight, scanning a
|
|
|
-flat table for "what's actually ready to land?" forces your eyes to do
|
|
|
-the filtering. Grouping does it for you, and the count tells you at a
|
|
|
-glance whether the answer is none, one, or twelve.
|
|
|
+The filled-pip color depends on what the metric *means*. Three families:
|
|
|
|
|
|
-#### 3-level: groups → branches → leaves
|
|
|
+**A. Progress** — work in motion, more = closer to done.
|
|
|
+```
|
|
|
+▰▰▰▱▱▱▱▱▱▱ 30% running build yellow (in-flight)
|
|
|
+▰▰▰▰▰▰▰▰▰▰ 100% build done green (terminal good)
|
|
|
+```
|
|
|
|
|
|
-For hierarchies with intermediate structure — repos with branches with
|
|
|
-files, projects with packages with tests, lanes with commits with
|
|
|
-patches. Interior nodes (`main`, `src/`, `utils/`) stay icon-free; only
|
|
|
-the leaves carry glyphs (state of the file).
|
|
|
+**B. Score / pass rate** — static measurement, more = better.
|
|
|
+```
|
|
|
+▰▰▱▱▱▱▱▱▱▱ 20% test pass rate red (alarm)
|
|
|
+▰▰▰▰▰▱▱▱▱▱ 50% test pass rate yellow (warn)
|
|
|
+▰▰▰▰▰▰▰▰▱▱ 80% test pass rate green (ok)
|
|
|
+```
|
|
|
+Thresholds: <33% red, <66% yellow, ≥66% green. Override per-skill.
|
|
|
|
|
|
+**C. Capacity / load** — utilization, more = worse (heading toward limits).
|
|
|
```
|
|
|
-── repo ────────────────────────────────────────────────────── X:/Forge/claude-mods · 2 worktrees
|
|
|
-├─ main
|
|
|
-│ ├─ src/
|
|
|
-│ │ ├─ index.ts ⚠️ modified
|
|
|
-│ │ └─ utils/
|
|
|
-│ │ ├─ format.ts ⚠️ modified
|
|
|
-│ │ └─ parse.ts ✅ added
|
|
|
-│ └─ README.md clean
|
|
|
-└─ feat/auth-rewrite
|
|
|
- └─ src/
|
|
|
- ├─ auth.ts ✅ new
|
|
|
- └─ middleware/
|
|
|
- └─ session.ts ⚠️ modified
|
|
|
+▰▰▱▱▱▱▱▱▱▱ 20% disk used green (plenty of room)
|
|
|
+▰▰▰▰▰▰▰▱▱▱ 70% disk used yellow (warn)
|
|
|
+▰▰▰▰▰▰▰▰▰▱ 90% disk used red (alarm)
|
|
|
```
|
|
|
+Thresholds: <60% green, <80% yellow, ≥80% red. Override per-skill.
|
|
|
|
|
|
-Look at any `├─` or `└─` and trace upward: there's always a clean `│`
|
|
|
-or empty space directly above it, never a glyph. That's the rule.
|
|
|
+**Helpers:**
|
|
|
+```bash
|
|
|
+term_pip_bar progress n total # type A
|
|
|
+term_pip_bar score n total # type B
|
|
|
+term_pip_bar capacity n total # type C
|
|
|
+```
|
|
|
|
|
|
-Each level adds a 3-column indent: `│ ` while the ancestor still has
|
|
|
-siblings to render, ` ` once the ancestor is on its last sibling. The
|
|
|
-helpers in `term.sh` (`term_tree_node`, `term_tree_indent`,
|
|
|
-`term_tree_connector`) compose this prefix so you don't have to count
|
|
|
-spaces.
|
|
|
+The metric type drives color selection. Skills don't pick a color directly — they pick the *kind* of measurement and the helper does the right thing.
|
|
|
|
|
|
-### Flat status table (escape hatch)
|
|
|
+### 4.11 Health indicator
|
|
|
|
|
|
-When the data is genuinely flat — `git status`-style fields, a single
|
|
|
-PR's checks — drop the tree. Glyph-first, no nested tables.
|
|
|
+A colored bullet followed by descriptive text. Lives in the footer's bottom-right slot (≤ 2 per panel) or at the start of a leaf when needed.
|
|
|
|
|
|
```
|
|
|
-── push-gate ───────────────────────────────────────────────── refusing
|
|
|
- ✅ secret scan clean
|
|
|
- ✅ forbidden files none
|
|
|
- ❌ divergence 3 ahead, 1 behind
|
|
|
+• daemon healthy (green pulsing)
|
|
|
+• 17m idle slow / pending (yellow)
|
|
|
+• lagging warning (orange)
|
|
|
+• down critical (red)
|
|
|
+⬤ daemon busted (large grey, static)
|
|
|
```
|
|
|
|
|
|
-The header rule still anchors the section; only the body is flat.
|
|
|
+**Rules**
|
|
|
+- `•` (small bullet) leads the text, single space between.
|
|
|
+- `⬤` (large) replaces `•` only when the system is *busted* — visually unmissable.
|
|
|
+- Text is short — 1–3 words max.
|
|
|
+- Color of the bullet must match the semantic meaning.
|
|
|
+- Two spaces between consecutive indicators — no `·` separator (the bullet is a strong enough lead).
|
|
|
|
|
|
-### Section divider
|
|
|
+**Helper:** `term_health <state> <text>`.
|
|
|
|
|
|
-Plain rule between blocks. No title.
|
|
|
+### 4.12 Hotkey hint
|
|
|
|
|
|
```
|
|
|
-────────────────────────────────────────────────────────────────
|
|
|
+R refresh
|
|
|
+L land
|
|
|
+? help
|
|
|
```
|
|
|
|
|
|
-### Empty state
|
|
|
+**Rules**
|
|
|
+- Single key (or modifier+key like `^C`) followed by a verb.
|
|
|
+- Letters in cyan.
|
|
|
+- Up to 3 in the footer; dropdown to a `?` help screen if more are needed.
|
|
|
+- Separated by `·` in the rendered footer (the dot disambiguates adjacent letter+verb pairs).
|
|
|
+
|
|
|
+**Helper:** `term_hotkey <key> <verb>`.
|
|
|
|
|
|
-Dim, parenthesised, single line — never a multi-line "nothing here" banner.
|
|
|
+### 4.13 Count
|
|
|
+
|
|
|
+Always `(n)`. Bare numbers belong in prose; counts in `()` belong in chrome.
|
|
|
|
|
|
```
|
|
|
- (no lanes — run: fleet init <name>...)
|
|
|
+RUNNING (2)
|
|
|
+4 lanes · 3 active <- prose, no parens
|
|
|
```
|
|
|
|
|
|
-## Colors
|
|
|
+### 4.14 Spinner
|
|
|
+
|
|
|
+Live-mode component. Replaces a single glyph in place as it cycles through frames.
|
|
|
|
|
|
-Color is signal layered on top of glyph and label. Strip color and the
|
|
|
-output must still be readable.
|
|
|
+- **Working** spinner cycles `⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏` at ~80ms/frame on rows whose work is in progress (replaces the leaf glyph during the operation).
|
|
|
+- **Heartbeat** spinner cycles `· ∙ • ● • ∙` at ~600ms/cycle on the daemon health indicator. Stops and turns into a static grey `⬤` when the daemon is busted.
|
|
|
|
|
|
-| Color | Meaning |
|
|
|
-| ------ | ---------------------------------------- |
|
|
|
-| green | success, terminal-good (READY, LANDED) |
|
|
|
-| yellow | pending or warning (RUNNING, CONFLICT) |
|
|
|
-| red | failure (FAILED, refused) |
|
|
|
-| cyan | section headers, hints |
|
|
|
-| dim | metadata: timestamps, counts, hint text |
|
|
|
+**Helper:** `term_spinner_frame working|heartbeat tick` returns the glyph for tick `n`.
|
|
|
|
|
|
-Disabled when stdout isn't a TTY, or `NO_COLOR` is set. Forced on with
|
|
|
-`FORCE_COLOR=1`.
|
|
|
+---
|
|
|
|
|
|
-## Examples (rendered)
|
|
|
+## 5. Patterns
|
|
|
|
|
|
-### Before — `fleet-ops` rolling its own (flat table, double rules)
|
|
|
+### 5.1 Grouped tree (default)
|
|
|
+
|
|
|
+The default for state-bucketed data. One panel, summary line, then state-grouped sections, each with leaves.
|
|
|
|
|
|
```
|
|
|
-── Fleet ──────────────────────────────────────────────────────
|
|
|
- BRANCH STATUS AGE
|
|
|
-────────────────────────────────────────────────────────────────
|
|
|
- ⏳ feat/auth-rewrite RUNNING 12m
|
|
|
- ✅ fix/cache-bust READY 2m
|
|
|
- 🚀 chore/bump-deps LANDED 1h
|
|
|
-────────────────────────────────────────────────────────────────
|
|
|
+╭── ⚡ fleet ───────────────────────────────── ⎇ main ───●
|
|
|
+│
|
|
|
+├── 4 lanes · 3 active
|
|
|
+│
|
|
|
+├── RUNNING (2)
|
|
|
+│ ├── feat/oauth-pkce ●─●─●─◉ M4 ?1 12m
|
|
|
+│ └── spike/wasm-eval ●─●─●─●─◉ M7 34m
|
|
|
+│
|
|
|
+├── READY (2)
|
|
|
+│ ├── fix/cache-bust ●─◉ clean 2m
|
|
|
+│ └── chore/bump-axios ●─◉ clean 5m
|
|
|
+│
|
|
|
+├── CONFLICT (1)
|
|
|
+│ └── feat/audit-log ●─●─⊗ blocked 17m
|
|
|
+│
|
|
|
+╰── R refresh · L land · ? help ───── • daemon • 17m ───●
|
|
|
```
|
|
|
|
|
|
-### After — rule on top, grouped tree with unbroken connectors
|
|
|
+**When to use:** state matters more than time. Most CLIs.
|
|
|
+
|
|
|
+### 5.2 Flat rail (alternate)
|
|
|
+
|
|
|
+Same atoms, no grouping. Sorted by age. State moves to a per-leaf indicator at the start.
|
|
|
|
|
|
```
|
|
|
-── fleet ───────────────────────────────────────────────────── 3 lanes · 2 active
|
|
|
-├─ RUNNING (1)
|
|
|
-│ └─ feat/auth-rewrite 12m
|
|
|
-├─ READY (1)
|
|
|
-│ └─ fix/cache-bust 2m
|
|
|
-└─ LANDED (1)
|
|
|
- └─ chore/bump-deps 1h
|
|
|
+╭── ⚡ fleet ───────────────────────────────── ⎇ main ───●
|
|
|
+│
|
|
|
+├── 4 lanes · 3 active
|
|
|
+│
|
|
|
+│ • fix/cache-bust ●─◉ clean 2m
|
|
|
+│ • chore/bump-axios ●─◉ clean 5m
|
|
|
+│ • feat/oauth-pkce ●─●─●─◉ M4 ?1 12m
|
|
|
+│ • feat/audit-log ●─●─⊗ blocked 17m
|
|
|
+│ • spike/wasm-eval ●─●─●─●─◉ M7 34m
|
|
|
+│
|
|
|
+╰── R refresh · L land · ? help ───── • daemon • 17m ───●
|
|
|
```
|
|
|
|
|
|
-The header rule stays — strongest cue you're inside a skill's output.
|
|
|
-Group labels are icon-free so the `│` running down column 0 is unbroken
|
|
|
-from the first group to the last leaf. State is carried by the label
|
|
|
-text and color (yellow for RUNNING, green for READY/LANDED). The tree
|
|
|
-reads as a tree, not a list with decorations.
|
|
|
+**When to use:** chronological or activity-sorted views (`fleet --flat`).
|
|
|
|
|
|
-### `git-ops/status` reformatted in the same language
|
|
|
+### 5.3 Status panel (no tree)
|
|
|
|
|
|
+For genuinely flat data — a PR's checks, a service's health summary. No sections, no tree connectors, just leaves under the panel `│`.
|
|
|
+
|
|
|
+```
|
|
|
+╭── ⚡ push-gate ─────────────────────────── refusing ───●
|
|
|
+│
|
|
|
+│ ✓ secret scan
|
|
|
+│ ✓ forbidden files
|
|
|
+│ ✗ divergence 3 ahead, 1 behind
|
|
|
+│
|
|
|
+╰── R retry · ? help ─────────────── • blocking ───●
|
|
|
```
|
|
|
-── Repo ─────────────────────────────────────────────────────── X:/Forge/claude-mods
|
|
|
- branch claude/sleepy-johnson-74f19d
|
|
|
- HEAD 367b062 fix(skills/fleet-ops): consistent .claude/ path (2h ago)
|
|
|
- sync 0 ahead / 0 behind
|
|
|
- tree 0 staged / 2 unstaged / 1 untracked
|
|
|
|
|
|
- ⚠️ HYGIENE main checkout on 'claude/...' — feature work belongs in worktrees
|
|
|
+### 5.4 Multi-panel stacking
|
|
|
+
|
|
|
+For dashboards — fleet next to git status, build output next to test output. Side-by-side is **not** supported (column arithmetic doesn't survive); panels stack vertically.
|
|
|
+
|
|
|
```
|
|
|
+╭── ⚡ fleet ─────────────────────────── ⎇ main ───●
|
|
|
+│
|
|
|
+├── RUNNING (2)
|
|
|
+│ └── feat/oauth-pkce ●─●─●─◉ 12m
|
|
|
+│
|
|
|
+╰── R · L · ? ──── • daemon ───●
|
|
|
|
|
|
-### `push-gate` refusal
|
|
|
|
|
|
+╭── 🌿 git ───────────────────────────── ⎇ main ───●
|
|
|
+│
|
|
|
+├── HEAD (3 ahead, 0 behind)
|
|
|
+│ └── 367b062 fix(skills): consistent path ●─◉ 2h
|
|
|
+│
|
|
|
+╰── s · c · ? ──── • clean ───●
|
|
|
```
|
|
|
-── push-gate ────────────────────────────────────────────────── refusing
|
|
|
- ❌ secret scan 2 hits in src/config/keys.ts
|
|
|
- ✅ forbidden files none
|
|
|
- ✅ divergence clean
|
|
|
|
|
|
- 💡 run: gitleaks detect --source . --no-git
|
|
|
+**Rule:** exactly **2 blank lines** between stacked panels. The terminator `●` and the opening `╭──` get to breathe; less than that they cling, more than that they drift apart.
|
|
|
+
|
|
|
+### 5.5 Help screen
|
|
|
+
|
|
|
+The `?` hotkey in every footer leads here. Same panel grammar, different content shape.
|
|
|
+
|
|
|
+```
|
|
|
+╭── ⚡ fleet · help ──────────────────────────── ⎇ main ───●
|
|
|
+│
|
|
|
+├── commands
|
|
|
+│ ├── R refresh re-read lane state from disk
|
|
|
+│ ├── L land merge a READY lane into base
|
|
|
+│ ├── F flat switch to rail view, sorted by age
|
|
|
+│ └── ? help you are here
|
|
|
+│
|
|
|
+├── concepts
|
|
|
+│ ├── lane a branch managed by fleet
|
|
|
+│ ├── base the trunk lanes merge into (default: main)
|
|
|
+│ └── daemon background poller; auto-lands READY lanes
|
|
|
+│
|
|
|
+╰── q quit ─────────────────────── • v2.4.9 ───●
|
|
|
+```
|
|
|
+
|
|
|
+The header gets `· help` after the tool name. Title is contextual; everything else is the same panel.
|
|
|
+
|
|
|
+### 5.6 Empty state
|
|
|
+
|
|
|
+A whole panel when there's nothing to show. Empty states earn extra whitespace and become tutorials.
|
|
|
+
|
|
|
+```
|
|
|
+╭── ⚡ fleet ────────────────────────────────── ⎇ main ───●
|
|
|
+│
|
|
|
+│
|
|
|
+│ no lanes yet
|
|
|
+│
|
|
|
+│
|
|
|
+│ 💡 to get started:
|
|
|
+│
|
|
|
+│ 1. fleet init feat/foo bar create branches + worktrees
|
|
|
+│ 2. (work in each lane) commits, tests
|
|
|
+│ 3. fleet start run the daemon
|
|
|
+│
|
|
|
+│
|
|
|
+╰── ? help ─────────────────────────── • v2.4.9 ───●
|
|
|
+```
|
|
|
+
|
|
|
+**Rules**
|
|
|
+- Empty state body uses **flat indented content** (no leaf tree connectors). Empty states are welcome posters, not data trees, so they get to break the tree convention.
|
|
|
+- The trunk `│` still tethers everything left.
|
|
|
+- 💡 emoji leads the "to get started" tip line.
|
|
|
+- 2 blank `│` rows above and below each block (vs. 1 in non-empty panels).
|
|
|
+- Footer drops to a single hotkey (`? help`) and a single status indicator (typically version).
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 6. Edge cases
|
|
|
+
|
|
|
+### 6.1 Long titles / names
|
|
|
+
|
|
|
+Ellipsis-truncate at the name-column boundary. Don't word-wrap in the body.
|
|
|
+
|
|
|
+```
|
|
|
+│ ├── feat/oauth-pkce-with-very-l… ●─●─●─◉ M4 ?1 12m
|
|
|
+│ └── chore/bump-axios ●─◉ clean 5m
|
|
|
```
|
|
|
|
|
|
-## Anti-patterns
|
|
|
+The full name is recoverable via `--wide` or the verbose view. Truncation preserves the grid.
|
|
|
+
|
|
|
+### 6.2 Narrow terminals (<60 cols)
|
|
|
+
|
|
|
+Drop columns from the right, in order: age → meta → rail. The leaf collapses to:
|
|
|
+
|
|
|
+```
|
|
|
+│ ├── feat/oauth-pkce
|
|
|
+│ └── spike/wasm-eval
|
|
|
+```
|
|
|
+
|
|
|
+Never wrap. Wrapping breaks the grid; truncation just hides data.
|
|
|
+
|
|
|
+### 6.3 ASCII fallback (`TERM_ASCII=1`, non-UTF locale, `TERM=dumb`)
|
|
|
+
|
|
|
+Every glyph has a registered ASCII proxy:
|
|
|
+
|
|
|
+```
|
|
|
++-- [F] fleet -------------------------------- (b) main ---*
|
|
|
+|
|
|
|
++-- 4 lanes · 3 active
|
|
|
+|
|
|
|
++-- RUNNING (2)
|
|
|
+| +-- feat/oauth-pkce *-*-*-@ M4 ?1 12m
|
|
|
+| `-- spike/wasm-eval *-*-*-*-@ M7 34m
|
|
|
+|
|
|
|
++-- READY (2)
|
|
|
+| +-- fix/cache-bust *-@ clean 2m
|
|
|
+| `-- chore/bump-axios *-@ clean 5m
|
|
|
+|
|
|
|
++-- CONFLICT (1)
|
|
|
+| `-- feat/audit-log *-*-X blocked 17m
|
|
|
+|
|
|
|
+`-- R refresh · L land · ? help ---- (+) daemon (.) 17m ---*
|
|
|
+```
|
|
|
+
|
|
|
+Same skeleton. Rounded corners (`╭ ╰`) collapse to `+`. Rail dots (`● ◉ ⊗`) become `* @ X`. Health bullets (`•`) become `(+) (.) (!)`. The grid survives.
|
|
|
+
|
|
|
+### 6.4 NO_COLOR
|
|
|
+
|
|
|
+Strip every ANSI sequence. The structure (glyphs, grid, indentation) carries 100% of the information. Verify: `NO_COLOR=1 fleet` should be unambiguous.
|
|
|
+
|
|
|
+### 6.5 Rendering context
|
|
|
+
|
|
|
+Panels and diagrams render only in monospace contexts with verbatim whitespace. There are exactly two:
|
|
|
+
|
|
|
+- **TTY output** — automatic. The canonical target.
|
|
|
+- **Fenced code blocks in any markdown** — ideal. Locks monospace, preserves the grid pixel-for-pixel. Use this in README, CHANGELOG, design docs, GitHub issues, anywhere markdown is rendered.
|
|
|
+
|
|
|
+Never paste unfenced. Markdown's `|` is table syntax; box-drawing collapses; whitespace compresses; the panel renders as visual nonsense. If a panel needs to live in prose, fence it.
|
|
|
+
|
|
|
+---
|
|
|
|
|
|
-- **Decorative emoji.** ✨📦🎉 carry no state. Keep the glyph budget for the
|
|
|
- six in the palette.
|
|
|
-- **Nested tables or boxes.** A table inside a bordered box is two layouts
|
|
|
- fighting for the same line. Pick one.
|
|
|
-- **Color as the only difference.** "Red row vs green row" fails for
|
|
|
- CI logs, screen readers, and color-blind users. Always pair with a glyph.
|
|
|
-- **Lines past 80 columns by default.** If you genuinely need 120, gate it
|
|
|
- behind `--wide` or auto-detect via `tput cols`.
|
|
|
-- **Assuming color in CI.** GitHub Actions sets `TERM=dumb`. Check.
|
|
|
-- **Multi-line empty states.** `(no lanes)` beats a 4-line ASCII shrug.
|
|
|
-- **New glyphs.** If your state doesn't fit pending/ready/done/failed/warn/hint,
|
|
|
- the state probably collapses into one of them. If it really doesn't,
|
|
|
- amend this document first.
|
|
|
+## 7. Anti-patterns
|
|
|
|
|
|
-## The library
|
|
|
+- **Long horizontal rules in the body** (`──────────── 🟡`). Decorative clutter; use whitespace to separate sections instead.
|
|
|
+- **Glyphs at tree junctions.** A glyph between `├──` and the parent's `│` breaks the eye-line of the tree.
|
|
|
+- **Mixing leaf glyph styles in one panel.** Rail and pips together looks like two languages fighting.
|
|
|
+- **Floating right-side UI.** Anything important tethers to the left rail. Right side is for leaves and small iconography (terminator dot, base-branch tag) only.
|
|
|
+- **More than one brand emoji per panel.** ⚡ in the header earns its keep. ⚡ next to every "running" lane is wallpaper.
|
|
|
+- **Using `●` as decoration.** Reserved for header/footer terminators. If you need a small marker elsewhere, use `•` (bullet, smaller) or pick a different shape (`◉ ◐ ◇ ▰ ⬢`).
|
|
|
+- **Bare numbers in chrome.** `RUNNING 2` is prose. `RUNNING (2)` is a count. Counts in chrome wear parens.
|
|
|
+- **Word-wrapping leaf rows.** Breaks the grid. Truncate with `…` instead.
|
|
|
+- **Section headers with `(0)`.** Empty sections are omitted, not rendered.
|
|
|
+- **Color-only state differentiation.** Red row vs green row fails on `NO_COLOR`, screen readers, and printouts. Always pair color with text or shape.
|
|
|
+- **Wider boxes for emphasis in diagrams.** Breaks column alignment. Use taller, same width.
|
|
|
+- **Multiple corner families in one diagram.** Pick rounded, stick with rounded.
|
|
|
|
|
|
-`skills/_lib/term.sh` is the single source of truth for glyphs, colors,
|
|
|
-and layout helpers. Source it, call `term_init`, then use:
|
|
|
+---
|
|
|
+
|
|
|
+## 8. Reference example
|
|
|
+
|
|
|
+```
|
|
|
+╭── ⚡ fleet ───────────────────────────────── ⎇ main ───●
|
|
|
+│
|
|
|
+├── 4 lanes · 3 active
|
|
|
+│
|
|
|
+├── RUNNING (2)
|
|
|
+│ ├── feat/oauth-pkce ●─●─●─◉ M4 ?1 12m
|
|
|
+│ └── spike/wasm-eval ●─●─●─●─◉ M7 34m
|
|
|
+│
|
|
|
+├── READY (2)
|
|
|
+│ ├── fix/cache-bust ●─◉ clean 2m
|
|
|
+│ └── chore/bump-axios ●─◉ clean 5m
|
|
|
+│
|
|
|
+├── CONFLICT (1)
|
|
|
+│ └── feat/audit-log ●─●─⊗ blocked 17m
|
|
|
+│
|
|
|
+╰── R refresh · L land · ? help ───── • daemon • 17m ───●
|
|
|
+```
|
|
|
+
|
|
|
+Color map:
|
|
|
+- `╭── ─ ╰──` panel chrome: cyan (accent)
|
|
|
+- `⚡` brand emoji: as-is (yellow rendering)
|
|
|
+- `fleet`: cyan
|
|
|
+- `⎇ main`: dim
|
|
|
+- `4 lanes · 3 active`: dim
|
|
|
+- `├── │ └──`: dim cyan (recede)
|
|
|
+- `RUNNING`, `CONFLICT`: yellow (pending)
|
|
|
+- `READY`: green (ok)
|
|
|
+- `(2)`: dim
|
|
|
+- branch names: default fg
|
|
|
+- `●─●─●` (landed): green; `◉` (HEAD): yellow; `⊗` (conflict): red
|
|
|
+- `M4`: yellow; `?1`: magenta; `clean`: dim green; `blocked`: red
|
|
|
+- `12m`: dim
|
|
|
+- `R`, `L`, `?`: bright cyan; verbs: default
|
|
|
+- `•` (healthy): green, pulsing in live mode
|
|
|
+- `●` terminators: cyan
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 9. Implementation — `skills/_lib/term.sh`
|
|
|
+
|
|
|
+The library is the single source of truth. Skills source it; nothing else needs to know about glyphs or colors.
|
|
|
|
|
|
```bash
|
|
|
LIB="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../_lib" && pwd)"
|
|
|
. "$LIB/term.sh"
|
|
|
term_init
|
|
|
+```
|
|
|
+
|
|
|
+### Helpers
|
|
|
+
|
|
|
+```bash
|
|
|
+# Foundations
|
|
|
+term_init # detect TTY, NO_COLOR, TERM_ASCII, set globals
|
|
|
+term_color name "text" # green/yellow/red/cyan/dim/orange/magenta wrap
|
|
|
+term_emoji key # registered glyph + ASCII fallback
|
|
|
+
|
|
|
+# Components
|
|
|
+term_panel_open emoji_key name [right_indicator]
|
|
|
+term_panel_close [hotkeys] [health_indicators]
|
|
|
+term_summary_line "text" # "├── 4 lanes · 3 active" (dim)
|
|
|
+term_section state label count # "├── LABEL (n)"
|
|
|
+term_leaf name leaf_glyph meta age
|
|
|
+term_toast emoji_key "text" # toast row
|
|
|
+term_alert severity "text" # ▲ inline alert sub-row
|
|
|
+
|
|
|
+# Leaf glyph builders (pick one per panel)
|
|
|
+term_rail commits_ahead head_state # ●─●─●─◉ / ●─●─⊗
|
|
|
+term_pip_bar metric_type filled total # progress / score / capacity
|
|
|
+
|
|
|
+# Right-side furniture
|
|
|
+term_health state text # • daemon (colored, with ⬤ for busted)
|
|
|
+term_hotkey key verb # R refresh
|
|
|
+
|
|
|
+# Live mode
|
|
|
+term_spinner_frame family tick # working / heartbeat → glyph
|
|
|
+
|
|
|
+# Edge cases
|
|
|
+term_truncate "text" max_cols # ellipsis-truncate
|
|
|
+term_term_width # current cols
|
|
|
+```
|
|
|
|
|
|
-term_header "Fleet" "$count lanes"
|
|
|
-term_table_row "$(term_state_icon READY)" "$branch" "READY" "$age"
|
|
|
-term_empty "no lanes — run: fleet init <name>..."
|
|
|
+### Registries
|
|
|
+
|
|
|
+Centralized at the top of `term.sh`, sourced into associative arrays:
|
|
|
+
|
|
|
+```bash
|
|
|
+declare -A TERM_BRAND=(
|
|
|
+ [fleet]="⚡|[F]"
|
|
|
+ [forge]="🔨|[B]"
|
|
|
+ [psql]="🐘|[P]"
|
|
|
+ [watch]="📡|[M]"
|
|
|
+ [deploy]="🚀|[D]"
|
|
|
+ [git]="🌿|[G]"
|
|
|
+)
|
|
|
+
|
|
|
+declare -A TERM_HEALTH=(
|
|
|
+ [healthy]="•|(+)"
|
|
|
+ [pending]="•|(.)"
|
|
|
+ [warning]="•|(!)"
|
|
|
+ [critical]="•|(!!)"
|
|
|
+ [busted]="⬤|(X)"
|
|
|
+ [unknown]="•|(?)"
|
|
|
+)
|
|
|
+
|
|
|
+declare -A TERM_DIAGRAM_ICON=(
|
|
|
+ [user]="👤|(U)"
|
|
|
+ [web]="🌐|(W)"
|
|
|
+ [mobile]="📱|(M)"
|
|
|
+ [auth]="🔐|(A)"
|
|
|
+ [database]="🗄|(D)"
|
|
|
+ [cache]="⚡|(C)"
|
|
|
+ [queue]="📨|(Q)"
|
|
|
+ [storage]="📦|(P)"
|
|
|
+ [service]="⚙|*"
|
|
|
+ [api]="🔌|(I)"
|
|
|
+ [search]="🔍|(S)"
|
|
|
+ [timer]="⏱|(T)"
|
|
|
+ [build]="🔨|(B)"
|
|
|
+ [hook]="🪝|(H)"
|
|
|
+ [log]="📄|(F)"
|
|
|
+)
|
|
|
```
|
|
|
|
|
|
-The helpers no-op gracefully under `NO_COLOR`, non-TTY, and `TERM_ASCII=1`.
|
|
|
-That's the whole contract — if you're reaching for raw `\033[` codes in a
|
|
|
-skill, you're off the path.
|
|
|
+Adding a tool means one row. Adding a state means one row. No hardcoded escape sequences in skills.
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 10. Open questions
|
|
|
+
|
|
|
+- **`--wide` mode.** Should claude-mods skills auto-detect `tput cols >= 120` and widen the grid, or always default to 80? Lean toward always-80 unless user opts in.
|
|
|
+- **Animation framework.** Spinners and live-updating panels (`fleet --watch`). The static-output spec is clear; a live mode would need a separate component family covering frame timing and partial redraws.
|
|
|
+- **Sub-panels.** A `verbose` view could nest a sub-panel per leaf. Not covered yet — defer until two skills genuinely need it.
|
|
|
+- **Accessibility audit.** Verify the panel reads coherently to screen readers when piped through `aspell` or similar. The "structure carries information" principle should hold; needs proof.
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 11. Diagrams
|
|
|
+
|
|
|
+The panel grammar handles lists and trees. For relationships — services talking to each other, state transitions, decision flows, timelines — diagrams take over. Same grid, same glyph palette, same color tokens; just different compositions.
|
|
|
+
|
|
|
+Diagrams render in code-fenced blocks (TTY or markdown); they are otherwise subject to the same rules as panels (§6.5). They may stand alone in docs or live inside a panel as body content.
|
|
|
+
|
|
|
+### 11.1 Foundations
|
|
|
+
|
|
|
+- **Grid**: cells are 1 char wide. Connections are orthogonal — horizontal `─` and vertical `│` only. Diagonals (`\` `/`) read poorly in monospace; don't use them.
|
|
|
+- **One corner family per diagram**: rounded `╭ ╮ ╰ ╯` is the canonical choice for diagrams in this system. Mix rounded with light corners (`┌ └`) only inside layered stacks (§11.5).
|
|
|
+- **Colors**: same tokens as panels. State words wear their state colors inside diagrams too.
|
|
|
+
|
|
|
+### 11.2 Box anatomy
|
|
|
+
|
|
|
+Every box in a diagram follows the same construction rules.
|
|
|
+
|
|
|
+#### Width
|
|
|
+
|
|
|
+`width = max(label_with_icon) + 4`
|
|
|
+
|
|
|
+The longest label on the page (icon + space + text) plus 4 cells of padding (3 left, 1 right). All boxes on the same diagram are this width — alignment is the price of admission.
|
|
|
+
|
|
|
+#### Height
|
|
|
+
|
|
|
+- **Standard**: 1 content row (3 lines total: top corner, label, bottom corner).
|
|
|
+- **Emphasis**: 3 content rows (5 lines total: top corner, blank, label, blank, bottom corner). Same width, taller height — never wider.
|
|
|
+
|
|
|
+#### Label position
|
|
|
+
|
|
|
+Top-anchored, right-aligned, **1-char right padding**.
|
|
|
+
|
|
|
+```
|
|
|
+╭──────────────╮
|
|
|
+│ 🌐 web │ ← label hits "1-char-from-right"; left side absorbs slack
|
|
|
+╰──────────────╯
|
|
|
+```
|
|
|
+
|
|
|
+Left padding = `width − label_cells − 1 − 2` (corners). The constant 1-char right pad is what makes labels visibly right-anchored across boxes with mixed icon/no-icon content.
|
|
|
+
|
|
|
+Cell-width counting: emoji = 2 cells; standard glyphs and ASCII chars = 1 cell.
|
|
|
+
|
|
|
+#### Examples — same 16-wide box, varied content
|
|
|
+
|
|
|
+```
|
|
|
+╭──────────────╮ ╭──────────────╮ ╭──────────────╮
|
|
|
+│ 👤 users │ │ lb │ │ 🌐 web │
|
|
|
+╰──────────────╯ ╰──────────────╯ ╰──────────────╯
|
|
|
+
|
|
|
+╭──────────────╮ ╭──────────────╮ ╭──────────────╮
|
|
|
+│ 📱 mobile │ │ 🔐 auth │ │ 🔍 search │
|
|
|
+╰──────────────╯ ╰──────────────╯ ╰──────────────╯
|
|
|
+
|
|
|
+╭──────────────╮ ╭──────────────╮ ╭──────────────╮
|
|
|
+│ user │ │ orders │ │ pay │
|
|
|
+╰──────────────╯ ╰──────────────╯ ╰──────────────╯
|
|
|
+```
|
|
|
+
|
|
|
+Every label's last character lands at column-from-right = 1, regardless of icon presence.
|
|
|
+
|
|
|
+#### Emphasis — same width, taller
|
|
|
+
|
|
|
+```
|
|
|
+╭──────────────╮ ╭──────────────╮
|
|
|
+│ 🔌 api gw │ │ │
|
|
|
+╰──────────────╯ │ 🔌 api gw │
|
|
|
+ │ │
|
|
|
+ standard ╰──────────────╯
|
|
|
+ 3 lines total
|
|
|
+ emphasis
|
|
|
+ 5 lines total
|
|
|
+```
|
|
|
+
|
|
|
+Use sparingly: at most 1 emphasis box per diagram. The point of emphasis is to draw the eye; multiple emphases scatter it.
|
|
|
+
|
|
|
+### 11.3 Connectors and arrows
|
|
|
+
|
|
|
+#### Straight connectors
|
|
|
+
|
|
|
+```
|
|
|
+──▶ horizontal right
|
|
|
+◀── horizontal left
|
|
|
+▲ vertical up
|
|
|
+▼ vertical down
|
|
|
+```
|
|
|
+
|
|
|
+#### Bent connectors
|
|
|
+
|
|
|
+Use the rounded corner family:
|
|
|
+
|
|
|
+```
|
|
|
+──╮ ╭──
|
|
|
+ │ │
|
|
|
+ ▼ ▼
|
|
|
+
|
|
|
+ ─╯ ╰─
|
|
|
+ │ │
|
|
|
+```
|
|
|
+
|
|
|
+#### Junctions (orthogonal multi-way)
|
|
|
+
|
|
|
+```
|
|
|
+─┬─ drop down from horizontal
|
|
|
+─┴─ rise up to horizontal
|
|
|
+─├─ branch right from vertical
|
|
|
+─┤─ branch left from vertical
|
|
|
+─┼─ cross
|
|
|
+```
|
|
|
+
|
|
|
+#### Arrowheads
|
|
|
+
|
|
|
+```
|
|
|
+Standard ▶ ◀ ▲ ▼ filled triangle (default)
|
|
|
+Open ▷ ◁ △ ▽ for "weak" / optional connections
|
|
|
+ASCII > < ^ v
|
|
|
+```
|
|
|
+
|
|
|
+**Rule:** orthogonal lines only. If two boxes aren't on the same row, bend the connector with a corner; never use diagonals.
|
|
|
+
|
|
|
+### 11.4 Connector labels
|
|
|
+
|
|
|
+Labels go above the line for outgoing, below for incoming.
|
|
|
+
|
|
|
+```
|
|
|
+ req
|
|
|
+client ────────────▶ server
|
|
|
+ ◀────────────
|
|
|
+ resp
|
|
|
+```
|
|
|
+
|
|
|
+For vertical fan-outs, labels sit between the junction and the arrowhead:
|
|
|
+
|
|
|
+```
|
|
|
+ ╭─────────┴─────────╮
|
|
|
+ │ │
|
|
|
+ no yes
|
|
|
+ │ │
|
|
|
+ ▼ ▼
|
|
|
+```
|
|
|
+
|
|
|
+### 11.5 Composed patterns
|
|
|
+
|
|
|
+#### Architecture (boxes + arrows)
|
|
|
+
|
|
|
+```
|
|
|
+╭──────────────╮ ╭──────────────╮ ╭──────────────╮
|
|
|
+│ 🌐 web │ ───▶ │ 🔌 api gw │ ───▶ │ 🗄 pgsql │
|
|
|
+╰──────────────╯ ╰──────────────╯ ╰──────────────╯
|
|
|
+```
|
|
|
+
|
|
|
+#### Cluster (container holding boxes)
|
|
|
+
|
|
|
+The one place where mixing corner families is allowed: double `╔ ╝` for the container, rounded for interior nodes.
|
|
|
+
|
|
|
+```
|
|
|
+╔═ web tier ═════════════════════════╗
|
|
|
+║ ║
|
|
|
+║ ╭──────────────╮ ╭──────────────╮║
|
|
|
+║ │ 🌐 web │ │ 📱 mobile │║
|
|
|
+║ ╰──────────────╯ ╰──────────────╯║
|
|
|
+║ ║
|
|
|
+╚════════════════════════════════════╝
|
|
|
+```
|
|
|
+
|
|
|
+#### Decision flow
|
|
|
+
|
|
|
+```
|
|
|
+ ╭──────────────╮
|
|
|
+ │ start │
|
|
|
+ ╰───────┬──────╯
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+ ╭──────────────╮
|
|
|
+ │ ready? │
|
|
|
+ ╰───────┬──────╯
|
|
|
+ │
|
|
|
+ ╭───────────┴───────────╮
|
|
|
+ │ │
|
|
|
+ no yes
|
|
|
+ │ │
|
|
|
+ ▼ ▼
|
|
|
+ ╭──────────────╮ ╭──────────────╮
|
|
|
+ │ wait │ │ land │
|
|
|
+ ╰──────────────╯ ╰──────────────╯
|
|
|
+```
|
|
|
+
|
|
|
+Fan-out goes through a `┴` junction below the diamond — keeps every box the same width.
|
|
|
+
|
|
|
+#### State machine
|
|
|
+
|
|
|
+```
|
|
|
+ ╭──────────────╮ ╭──────────────╮ ╭──────────────╮
|
|
|
+ │ RUNNING │ ───▶ │ READY │ ───▶ │ LANDED │
|
|
|
+ ╰───────┬──────╯ ╰───────┬──────╯ ╰──────────────╯
|
|
|
+ │ │
|
|
|
+ ▼ ▼
|
|
|
+ ╭──────────────╮ ╭──────────────╮
|
|
|
+ │ FAILED │ │ CONFLICT │
|
|
|
+ ╰──────────────╯ ╰──────────────╯
|
|
|
+```
|
|
|
+
|
|
|
+State labels in their state colors. Terminal states (LANDED, FAILED, CONFLICT) have no outgoing arrows.
|
|
|
+
|
|
|
+#### Sequence / lifeline
|
|
|
+
|
|
|
+```
|
|
|
+client server
|
|
|
+ │ │
|
|
|
+ ├── login ────────────▶│
|
|
|
+ │ │
|
|
|
+ │◀──── token ──────────┤
|
|
|
+ │ │
|
|
|
+ ├── /api/data ────────▶│
|
|
|
+ │ │
|
|
|
+ │◀──── 200 ok ─────────┤
|
|
|
+ │ │
|
|
|
+```
|
|
|
+
|
|
|
+Lifelines as `│` columns, messages as `├──▶` arrows. Time runs top-down.
|
|
|
+
|
|
|
+#### Pipeline with status
|
|
|
+
|
|
|
+```
|
|
|
+ build test deploy
|
|
|
+╭──────────────╮ ╭──────────────╮ ╭──────────────╮
|
|
|
+│ ● ● ● │ │ ● ● ◌ │ │ ◌ ◌ ◌ │
|
|
|
+╰──────────────╯ ╰──────────────╯ ╰──────────────╯
|
|
|
+ done running pending
|
|
|
+```
|
|
|
+
|
|
|
+Each box's interior shows work units as filled/empty dots. Pipeline reads as both flow and status.
|
|
|
+
|
|
|
+#### Hierarchy
|
|
|
+
|
|
|
+```
|
|
|
+ ╭──────────────╮
|
|
|
+ │ core │
|
|
|
+ ╰───────┬──────╯
|
|
|
+ │
|
|
|
+ ╭────────────┼────────────╮
|
|
|
+ │ │ │
|
|
|
+ ▼ ▼ ▼
|
|
|
+ ╭──────────────╮╭──────────────╮╭──────────────╮
|
|
|
+ │ 🔐 auth││ data ││ ui │
|
|
|
+ ╰──────────────╯╰──────────────╯╰──────────────╯
|
|
|
+```
|
|
|
+
|
|
|
+Tree shape with proper boxes — for deps where the layout is the point.
|
|
|
+
|
|
|
+#### Layered stack (one allowed exception to rounded-only)
|
|
|
+
|
|
|
+```
|
|
|
+┌─ application ────────────────┐
|
|
|
+│ bash + term.sh │
|
|
|
+├─ runtime ────────────────────┤
|
|
|
+│ git, stat, sed, awk │
|
|
|
+├─ filesystem ─────────────────┤
|
|
|
+│ .claude/fleet/ │
|
|
|
+└──────────────────────────────┘
|
|
|
+```
|
|
|
+
|
|
|
+Light corners (`┌ ┐ └ ┘`) for stacks — distinguishes them from panels and diagrams. Layer name in the top edge of each layer.
|
|
|
+
|
|
|
+### 11.6 Icon dictionary
|
|
|
+
|
|
|
+A small registered set for diagrams. Use sparingly — at most one per box, only when the icon adds meaning. ASCII fallback registered for each.
|
|
|
+
|
|
|
+| Concept | Glyph | ASCII | Use for |
|
|
|
+| ------------------ | ----- | ----- | ---------------------------------------- |
|
|
|
+| user / actor | 👤 | `(U)` | external person/role at the system edge |
|
|
|
+| web / browser | 🌐 | `(W)` | client web tier |
|
|
|
+| mobile | 📱 | `(M)` | mobile clients |
|
|
|
+| auth / security | 🔐 | `(A)` | auth services, key vaults |
|
|
|
+| database | 🗄 | `(D)` | persistent storage |
|
|
|
+| cache | ⚡ | `(C)` | fast in-memory stores |
|
|
|
+| queue / message | 📨 | `(Q)` | message brokers, event buses |
|
|
|
+| storage / blob | 📦 | `(P)` | object storage, file blobs |
|
|
|
+| service / worker | ⚙ | `*` | background processes, scheduled jobs |
|
|
|
+| api / endpoint | 🔌 | `(I)` | api gateway, ingress |
|
|
|
+| search / index | 🔍 | `(S)` | search services |
|
|
|
+| timer / schedule | ⏱ | `(T)` | scheduled tasks, crons |
|
|
|
+| build / compile | 🔨 | `(B)` | build systems |
|
|
|
+| event / hook | 🪝 | `(H)` | webhooks, event triggers |
|
|
|
+| log / file | 📄 | `(F)` | logs, files, records |
|
|
|
+
|
|
|
+**Rules for icons in diagrams:**
|
|
|
+1. **At most one icon per box.** No stacking.
|
|
|
+2. **Icon goes inside the box, before the label.** Same row, single space between.
|
|
|
+3. **Boxes must size for emoji width.** Emoji = 2 cells; size the box accordingly.
|
|
|
+4. **Be selective.** A diagram of 16 boxes shouldn't have 16 icons — pick 4–6 *categories* of node and icon those (one for each tier or role).
|
|
|
+
|
|
|
+### 11.7 Reference exemplar — 16-element architecture
|
|
|
+
|
|
|
+```
|
|
|
+ ╭──────────────╮
|
|
|
+ │ 👤 users │
|
|
|
+ ╰───────┬──────╯
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+ ╭──────────────╮
|
|
|
+ │ lb │
|
|
|
+ ╰───────┬──────╯
|
|
|
+ │
|
|
|
+ ╭──────────┴──────────╮
|
|
|
+ │ │
|
|
|
+ ▼ ▼
|
|
|
+ ╭──────────────╮ ╭──────────────╮
|
|
|
+ │ 🌐 web │ │ 📱 mobile │
|
|
|
+ ╰───────┬──────╯ ╰───────┬──────╯
|
|
|
+ │ │
|
|
|
+ ╰─────────┬──────────╯
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+ ╭──────────────╮
|
|
|
+ │ 🔌 api gw │
|
|
|
+ ╰───────┬──────╯
|
|
|
+ │
|
|
|
+ ╭──────┬──────────┬───────┼───────┬──────────┬──────╮
|
|
|
+ │ │ │ │ │ │ │
|
|
|
+ ▼ ▼ ▼ ▼ ▼ ▼ ▼
|
|
|
+ ╭──────────────╮ ╭──────────────╮ ╭──────────────╮ ╭──────────────╮ ╭──────────────╮
|
|
|
+ │ 🔐 auth │ │ user │ │ orders │ │ pay │ │ 🔍 search │
|
|
|
+ ╰───────┬──────╯ ╰───────┬──────╯ ╰───────┬──────╯ ╰───────┬──────╯ ╰───────┬──────╯
|
|
|
+ │ │ │ │ │
|
|
|
+ ▼ ▼ ▼ ▼ ▼
|
|
|
+ ╭──────────────╮ ╭──────────────╮ ╭──────────────╮ ╭──────────────╮ ╭──────────────╮
|
|
|
+ │ 🗄 pgsql │ │ ⚡ redis │ │ 📨 kafka │ │ stripe │ │ 🗄 elastic│
|
|
|
+ ╰──────────────╯ ╰──────────────╯ ╰───────┬──────╯ ╰──────────────╯ ╰──────────────╯
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+ ╭──────────────╮
|
|
|
+ │ ⚙ worker │
|
|
|
+ ╰──────────────╯
|
|
|
+```
|
|
|
+
|
|
|
+16 elements, all the same width, all rounded corners. Icons on tier-defining nodes (clients, gateway, security, search, data layer, worker); domain services (`user`, `orders`, `pay`, `lb`, `stripe`) stay icon-free where the name is the meaning.
|
|
|
+
|
|
|
+### 11.8 Rules of thumb
|
|
|
+
|
|
|
+- **Don't draw if you can list.** A bulleted list always wins for purely sequential content. Diagrams earn their keep when there's a *spatial* relationship the reader needs to grasp.
|
|
|
+- **Pick one corner family per diagram.** Rounded everywhere; the cluster container double-line and the layered-stack light-corner are the only sanctioned exceptions.
|
|
|
+- **Width budget: 80 cols.** Diagrams that need >100 cols need to be split or rethought.
|
|
|
+- **Color is amplification.** Strip color, the diagram still works.
|
|
|
+- **No diagonals, no overlapping lines, no crossing connectors.** If your diagram needs them, it's the wrong representation for monospace.
|
|
|
+- **Anti-pattern: ASCII art logos and decorative borders.** This is about communicating structure, not flexing.
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Appendix A: rules of skill-agent-updates
|
|
|
+
|
|
|
+Output-heavy skills follow this spec and source `skills/_lib/term.sh`. See [`rules/skill-agent-updates.md`](../rules/skill-agent-updates.md).
|