Spec Visualization System — Build Plan
Context for fresh Claude: Shay wanted a dedicated, deep rework of how specs are visualized. Plain markdown wasn't carrying the complexity in the real specs (phase roadmaps, SQL schemas, surface maps, action ladders, flow diagrams). This plan scopes the work. Do it after compact with full force.
Goal
Specs stay portable markdown (works in any editor, readable in GitHub, no MDX lock-in) — but gain ~14 first-class visualization components that activate when a spec uses the viz:<type> fenced-block convention.
The reader of /specs/artifact-platform shouldn't see "a flat table of phases" — they should see a horizontal timeline with gates colored by status, useful-to-audience chips, and expand-to-see tasks under each. Same content, richer surface.
Rendering architecture
Syntax (in .md files)
Regular markdown paragraph.
```viz:phase-timeline
phases:
- id: 0
name: Stoka v1
useful_to: Visitors
status: shipped
- id: 1
name: Solo core
useful_to: You alone, as daily-use tool
status: active
gate_condition: Phase 0
Another regular paragraph. [[spec:messaging]] renders as a spec-chip inline.
The `viz:<type>` fenced block is parsed as YAML. The `[[spec:...]]`, `@handle`, and `{kind:...}` inline patterns get post-processed into chips.
### Pipeline
spec.md
↓
parseFrontmatter() → { data, body }
↓
splitIntoSegments(body) → [ { type: 'md', content }, { type: 'viz', vizType, props }, ... ]
↓
for each segment:
type=md → marked.parse()
type=viz → route to src/lib/specs/
├─ index.ts ← loadSpecs() (exists; move here)
├─ segment-parser.ts ← NEW: splits body into md/viz segments
├─ viz-registry.ts ← NEW: maps 'viz:phase-timeline' → PhaseTimeline component
├─ inline-processor.ts ← NEW: turns specx / @handle / kindx into chip HTML
└─ types.ts ← NEW: SpecSegment, VizBlock, etc. src/components/specs/
├─ PhaseTimeline.astro ← phase roadmap, horizontal, with gates
├─ SchemaERD.astro ← SQL schema entity-relationship diagram
├─ SurfaceMap.astro ← surface-card grid (Stoka Across Surfaces)
├─ ActionLadder.astro ← vertical escalation ladder (mod actions)
├─ LayerStack.astro ← stacked layers (Bon Appétit / prompt architecture)
├─ ApiRoutes.astro ← HTTP-colored route cards
├─ DecisionMatrix.astro ← comparison grid (visibility, channels×events)
├─ FlowDiagram.astro ← step-by-step flows (Telegram pairing, share cascade)
├─ Ruleset.astro ← rule-cards (mod triggers + action rungs)
├─ KindCards.astro ← kind cards (artifact kinds, inbox item kinds)
├─ Exchange.astro ← terminal-styled conversation mockup (Stoka golden examples)
├─ Callout.astro ← TBD / warning / note / info semantic blocks
├─ SpecChip.astro ← inline specslug rendering
├─ PseudonymChip.astro ← inline @handle rendering
└─ KindChip.astro ← inline kindconversation rendering src/pages/specs/[slug].astro ← UPDATE: use segment renderer, not marked.parse()
src/pages/admin/specs.astro ← UPDATE: same, with dark-theme variants of every component ERD for SQL schemas. Shows tables as boxes with column lists, relationships as connecting lines. Collapsible column details (click table → expand). Index/unique markers in-line. Kind-specific metadata JSON shown as sub-card. Data shape: Card grid — one card per surface. Each card has: surface name (title), Layer 3 content source, Layer 4 context, "what Stoka does" summary. Visual tie to the "one brain many masks" concept via a shared brain-icon in the center of the grid + radial connections. Data shape: Vertical escalation ladder. Each rung numbered, with action name, description, reversibility indicator, admin-visibility level. Shown as actual ladder visual (rungs with increasing severity). Data shape: Stacked layers (Bon Appétit artifact granularity, prompt architecture Layers 0-5). Each layer has a label, description, visibility/depth marker. Click to expand showing layer-specific details. Bon Appétit version: "reader appetite" scrollbar on the right showing reader depth. Data shape: Route table/cards. HTTP method color badges (GET=blue, POST=green, PATCH=amber, DELETE=red). Auth/role badge per route. Description + example request/response (collapsible). Data shape: Comparison grid — rows = options, columns = properties. Each cell can be: boolean (✓/—), enum (colored pill), scalar (text), or link (to spec). Highlight the "recommended" row. Used for visibility tiers, notification channels-vs-events, model decisions. Data shape: Numbered step flow with branches. Each step is a node; arrows show progression. Branches (if/else) rendered as forks. Annotations along arrows (e.g., "if artifact is private: grant access"). Can be vertical or horizontal. Data shape: Card-per-rule for moderation or any rule-based system. Each card: trigger condition (with detection snippet), action ladder rung(s) it typically escalates to, threshold visibility (public/private). Data shape: Grid of cards representing taxonomic kinds (artifact kinds, inbox item kinds). Each card: kind icon, kind name, description, kind-specific metadata schema preview. Data shape: Terminal-styled conversation mockup (for Stoka golden examples, Konan chat samples, DM previews). Monospace, speaker labels colored, cite blocks rendered inline. Data shape: Semantic callouts with icon + color. Variants: Data shape (or use a shorter syntax): In priority order (what will demo best): The admin This is Phase E because it's a big editor lift and the viewing experience is the immediate win. After compact. Full force. 14 components is a real chunk of work — don't fragment across sessions if avoidable.
### Files to create
Each viz component ships **two theme variants**: public (light-prose-friendly) and admin (dark-prose). Use `data-theme` attribute or CSS custom properties + a wrapper class.
## Component catalog (detailed)
### 1. `viz:phase-timeline`
Horizontal timeline. Each phase = a node; gates between phases shown as arrows with gate-condition text. Status colors: shipped (green-solid) · active (green-glowing) · queued (gray) · blocked (amber) · deferred (dimmed).
Data shape:
```yaml
phases:
- id: 1
name: Solo core
useful_to: You alone, as daily-use tool
status: queued
gate_condition: Phase 0 shipped
milestones: [optional list, shown in hover/expand]
2.
viz:schema-erdtables:
- name: identity.artifacts
columns:
- name: id
type: UUID
pk: true
- name: pseudonym_id
type: UUID
fk: identity.pseudonyms.id
- name: visibility
type: TEXT
default: private
enum: [private, link_only, public_anonymous]
indexes:
- { on: [pseudonym_id, status] }
relationships:
- from: identity.artifacts.pseudonym_id
to: identity.pseudonyms.id
label: author
3.
viz:surface-mapbrain: Stoka (fixed identity + voice)
surfaces:
- name: Discovery terminal
layer_3: RAG chunks from published content
layer_4: page, history, interests
role: recommends content
- ...
4.
viz:action-laddertarget: pseudonym | user
rungs:
- number: 1
name: Silent warn
description: Pseudonym sees notice
reversibility: automatic
- ...
5.
viz:layer-stacktitle: Bon Appétit granularity ladder
layers:
- name: Recipe card
subtitle: what you scan
description: headline · prompt · why it works · variations · tags
- name: Method notes
subtitle: expand once
description: what was tried · what failed · the moment it clicked
- ...
6.
viz:api-routesbase: /api/dm
routes:
- method: POST
path: /threads
auth: user
purpose: start/resume by recipient handle
body: { recipient_handle: string, note?: string }
- ...
7.
viz:decision-matrixrows: [Private, Link-only, Public anonymous]
columns: [Who sees it, Directory?, Stoka index?, Share-to-DM?]
cells:
Private: ["Only author", "No", "Personal only", "Yes, grant"]
...
highlight: Private # the default
8.
viz:flow-diagramorientation: vertical
steps:
- id: 1
actor: User
action: Click share button
- id: 2
actor: Client
action: Opens recipient picker
- id: 3
actor: Client
action: POST /api/artifacts/:id/share
branches:
- condition: thread exists
next: 4a
- condition: thread does not exist
next: 4b
- ...
9.
viz:rulesetrules:
- trigger: Report threshold
detection: "N user reports on a pseudonym within window"
rungs: [2, 3]
threshold_visibility: private
- ...
10.
viz:kind-cardskinds:
- id: conversation
icon: chat-square # icon ID from a curated set
name: Conversation
description: Bon Appétit conversation extract — recipe + method + source + transcript
metadata_schema:
- { key: recipe, type: text }
- { key: why_it_works, type: text }
- { key: variations, type: array }
- ...
11.
viz:exchangespeakers:
visitor: { color: muted, prefix: "visitor" }
stoka: { color: brand, prefix: "stoka" }
turns:
- speaker: visitor
text: "what is this?"
- speaker: stoka
text: "a terminal. i know everything published here. ask something or don't."
- speaker: visitor
text: "tell me about Debono"
- speaker: stoka
text: "it transcribes pharmacy lecture slides.\nthe interesting part is how it fails."
cite:
slug: debono-error-handling
quote: "The deck pipeline doesn't retry. It remembers what broke and why."
12.
viz:callouttbd (yellow question-mark), warning (red triangle), note (blue circle), rule (emerald lock — for "design rule"), deferred (gray arrow-right).variant: rule
title: The Unencumbered Bar
body: |
Every feature ships against this bar or doesn't ship.
Optimistic UI, no modals, keyboard-first, instant pseudonym switching.
13-15. Inline chips (processed in markdown, not viz blocks)
[[spec:messaging]] → styled chip linking to /specs/messaging@ghost-7c0a → pseudonym chip (gets hover-card in Phase 2+){kind:conversation} → kind chip with icon{phase:1} → phase chip with status colorComponent visual language (shared)
#10b981 for primary accents, amber #fbbf24 for warnings/TBDs, red for critical, muted surface grays for chrome.Implementation phases
Phase A — Foundation (post-compact, first pass)
src/lib/specs/segment-parser.ts — splits spec body on \n```viz:<type>\n...\n```\nsrc/lib/specs/viz-registry.ts — type → component mapsrc/lib/specs/inline-processor.ts — chip transforms on markdown segmentssrc/pages/specs/[slug].astro to use segment renderersrc/pages/admin/specs.astro to use same (with dark variants)Callout, SpecChip, KindChip, PseudonymChip, PhaseTimeline (the highest-impact visuals first)Phase B — The meat (post-compact, second pass)
SchemaERD, SurfaceMap, LayerStack, ActionLadder, FlowDiagramPhase C — Final wave
ApiRoutes, DecisionMatrix, Ruleset, KindCards, ExchangePhase D — Spec rewrites
README.md + artifact-platform.md + messaging.md to use viz blocks where they replace markdown tables / ASCII / SQL blocks.stoka-bot.md where high-impact (Surface Map, Layer Stack, Exchange for golden examples).Target specs for first visualization pass
artifact-platform.md — has the Bon Appétit layer stack (perfect LayerStack demo), visibility tiers (DecisionMatrix), full schema (SchemaERD), phase plan (PhaseTimeline), kinds list (KindCards)messaging.md — Telegram pairing flow (FlowDiagram), mod action ladder (ActionLadder), notification matrix (DecisionMatrix), surface map extension, mod triggers (Ruleset)stoka-bot.md — Surface Map section (SurfaceMap), prompt architecture Layers (LayerStack), golden examples (Exchange)Admin surface specific
/admin/specs page should let the author edit viz blocks with a structured editor (not raw YAML). Phase E (post all the above):
What NOT to do
Open questions
/specs build is static. No JS should be required for first paint — all viz components SSR to HTML. Interactivity (hover details, click-expand) is progressive enhancement.Success criteria
artifact-platform.md on /specs/artifact-platform feels like reading a well-designed technical book, not browsing a markdown file.messaging.md is a one-line YAML edit, not a rewrite.When to attack