@polderlabs/bizar 4.4.8 → 4.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,275 +1,163 @@
1
1
  ---
2
2
  name: glyph
3
- description: Create and consume Bizar glyphs visual plan/recap artifacts in `artifacts/<slug>/`. Glyphs are MDX files with frontmatter and a block vocabulary. Use for design proposals, decision recaps, and postmortems.
4
- version: 2
3
+ description: Create visual glyphs at `artifacts/<slug>/` for plans, recaps, design proposals, postmortems, handoffs. Glyphs should be compact and visual — one screen, dense info, no walls of text. This skill enforces that.
4
+ version: 4
5
5
  ---
6
6
 
7
- # Glyphs — Visual Plan Artifacts
7
+ # Glyphs
8
8
 
9
- A **glyph** is a visual artifact used for plans, recaps, design proposals, and postmortems. It's an MDX file at `artifacts/<slug>/artifact.mdx` (or `~/.config/opencode/artifacts/<slug>/` for global glyphs) that the dashboard renders with comment-pin overlay and right-click context menu.
10
-
11
- ## When to create a glyph
12
-
13
- - **Design proposal** — you're proposing a new component, system, or workflow
14
- - **Decision recap** — multiple options were considered; one was chosen; the reasoning matters
15
- - **Postmortem** — something broke; here's the timeline and root cause
16
- - **Implementation plan** — breaking down a non-trivial feature into phases
17
- - **Handoff** — work moving from one agent to another
18
-
19
- If it's a one-line fix, don't make a glyph. If it's a 5-minute edit, don't make a glyph. Glyphs are for work that needs visible structure.
20
-
21
- ## File structure
9
+ A **glyph** is an MDX file the dashboard renders with a comment-pin overlay and right-click menu. Three files per glyph:
22
10
 
23
11
  ```
24
12
  artifacts/<slug>/
25
- ├── meta.json # title, slug, status, author, created, lastEdited
26
- ├── artifact.mdx # ← source of truth (git-tracked, diff-friendly)
27
- └── comments.json # ← free-placed pins (mutable, gitignored usually)
13
+ ├── meta.json title, status, author, created
14
+ ├── artifact.mdx ← source of truth
15
+ └── comments.json ← free-placed pins (mutable)
28
16
  ```
29
17
 
30
- Two locations are scanned:
31
- 1. **Per-project:** `<projectRoot>/.bizar/artifacts/<slug>/`
32
- 2. **Global:** `~/.config/opencode/artifacts/<slug>/`
33
-
34
- The dashboard uses whichever exists. The project's `artifacts/<slug>/` is preferred when running inside a worktree.
18
+ Two locations: `<projectRoot>/.bizar/artifacts/` (preferred) and `~/.config/opencode/artifacts/` (global).
35
19
 
36
20
  ## Frontmatter
37
21
 
38
22
  ```yaml
39
23
  ---
40
24
  title: "Short, action-oriented title"
41
- brief: "One sentence: what this glyph is about."
25
+ brief: "One sentence."
42
26
  status: draft | review | shipped | archived
43
27
  kind: plan | postmortem | recap | design
44
28
  ---
45
29
  ```
46
30
 
47
- The frontmatter is parsed once and exposed to the React renderer. Unknown keys are passed through. Status controls the badge color + whether the glyph is read-only.
48
-
49
- ## Block vocabulary
50
-
51
- ```mdx
52
- <RichText id="...">markdown content (headings, lists, code blocks, etc.)</RichText>
31
+ ## The 6 rules read this first, every time
53
32
 
54
- <Callout id="..." tone="info|warn|success|danger">markdown content</Callout>
33
+ These are non-negotiable. The existing 357-line v3-to-v4-consolidation glyph is a cautionary tale — don't write that one.
55
34
 
56
- <Stat id="..." label="..." value="..." trend="up|down|flat" hint="..." />
35
+ ### Rule 1 One screen
57
36
 
58
- <Checklist
59
- id="..."
60
- items={[
61
- { id: "i1", label: "...", checked: true },
62
- { id: "i2", label: "...", checked: false }
63
- ]}
64
- />
37
+ A glyph MUST fit on one screen of the dashboard (≈ 1000px tall at desktop width). Long glyphs are skimmed and abandoned. If you can't fit the work in 5-10 blocks, you're covering too much. Break the work into multiple glyphs, one per phase.
65
38
 
66
- <Table
67
- id="..."
68
- columns={["A", "B"]}
69
- rows={[["x", "y"], ["p", "q"]]}
70
- />
39
+ ### Rule 2 — One idea per block
71
40
 
72
- <CodeTabs
73
- id="..."
74
- tabs={[
75
- { id: "t1", label: "file.ts", language: "typescript", code: "...", caption: "..." }
76
- ]}
77
- />
41
+ If a block covers two ideas, split it. Each block is a single visual unit. The dashboard groups blocks into sections by id prefix — use that.
78
42
 
79
- <Decision
80
- id="..."
81
- title="..."
82
- question="..."
83
- options={[
84
- { id: "a", label: "...", detail: "...", recommended: true }
85
- ]}
86
- />
43
+ ### Rule 3 — RichText is glue, not body
87
44
 
88
- <OpenQuestions
89
- id="..."
90
- questions={[
91
- { id: "q1", label: "...", kind: "choice|text|multi", options: ["A", "B"] }
92
- ]}
93
- />
45
+ RichText is for 1-3 sentence transitions between visual blocks. NEVER use RichText for the actual content. If you find yourself writing 4+ sentences in a RichText, switch to:
94
46
 
95
- <FileTree
96
- id="..."
97
- title="..."
98
- entries={[
99
- { path: "src/foo.ts", change: "added|modified|removed|renamed", note: "..." }
100
- ]}
101
- />
47
+ - **A table** if you're listing things with attributes
48
+ - **A decision** if you're explaining why one option won
49
+ - **A file tree** if you're listing changes
50
+ - **A stat** if you're highlighting a number
51
+ - **A workflow** if you're describing a sequence
102
52
 
103
- <Workflow
104
- id="..."
105
- steps={[
106
- { id: "s1", label: "...", type: "task|decision|note" }
107
- ]}
108
- connections={[
109
- { from: "s1", to: "s2", label: "yes" }
110
- ]}
111
- />
53
+ ### Rule 4 — Lead with visuals
112
54
 
113
- <Mockup
114
- id="..."
115
- title="..."
116
- x={40} y={120} w={280} h={180}
117
- html="<div class='mockup-card'>...</div>"
118
- />
55
+ The first block after the title/headline should be a visual: a Stat, a Callout, or a Table. Never open with a long RichText. The user decides in 5 seconds whether to keep scrolling based on the visual.
119
56
 
120
- <Diagram
121
- id="..."
122
- title="..."
123
- dataHtml="<svg>...</svg>"
124
- dataCss=".diagram-node { fill: var(--bg-1); }"
125
- />
126
- ```
57
+ ### Rule 5 — One headline callout
127
58
 
128
- ## What data shape each block expects
59
+ Use `<Callout tone="success|danger">` once, near the top, as the TL;DR. Everything else supports it.
129
60
 
130
- The dashboard validates every block's `data` shape BEFORE rendering. If a field is missing or the wrong type, the block renders an inline error card instead of crashing the whole canvas (v4.4.8+). The same thing happens if a block throws during render — a per-block `ErrorBoundary` catches it.
61
+ ### Rule 6 Truncate hints, not bodies
131
62
 
132
- | Block | Required `data` fields |
133
- | --- | --- |
134
- | `RichText` | none (children are markdown) |
135
- | `Callout` | none; optional `tone: 'info' \| 'warn' \| 'success' \| 'danger'` (default: info) |
136
- | `Stat` | `label: string`, `value: string \| number`; optional `trend`, `hint` |
137
- | `Checklist` | `items: Array<{ id, label, checked }>` |
138
- | `Table` | `columns: string[]`, `rows: string[][]` (each row is a cell array) |
139
- | `CodeTabs` | `tabs: Array<{ id, label, language, code, caption? }>` |
140
- | `Decision` | `options: Array<{ id, label, detail, recommended? }>`; optional `title`, `question` |
141
- | `OpenQuestions` | `questions: Array<{ id, label, kind, options? }>` |
142
- | `FileTree` | `entries: Array<{ path, change, note? }>` where `change ∈ {added, modified, removed, renamed}` |
143
- | `Diff` | `before: string`, `after: string`; optional `filename`, `language`, `mode` |
144
- | `Workflow` | `steps: Array<{ id, label, type }>`; optional `connections` |
145
- | `Mockup` | `html: string`; optional `title`, `x`, `y`, `w`, `h` |
146
- | `Diagram` | `dataHtml: string`; optional `title`, `dataCss` |
63
+ Stat `hint` props should be 1 short clause. Long hints mean the value needs to be a different block.
147
64
 
148
- ## Common pitfalls
65
+ ## The block vocabulary — minimal reference
149
66
 
150
- These are the bugs we've actually hit. Read this section before writing a glyph.
67
+ | Block | What it shows | Required `data` |
68
+ | --- | --- | --- |
69
+ | `<RichText>` | 1-3 sentences of glue | none |
70
+ | `<Callout tone>` | Boxed TL;DR | none (tone defaults to info) |
71
+ | `<Stat label value trend hint />` | Big number + label | `label`, `value` |
72
+ | `<Checklist items />` | Checkbox list | `items: [{id,label,checked}]` |
73
+ | `<Table columns rows />` | Tabular data | `columns: []`, `rows: [[]]` |
74
+ | `<CodeTabs tabs />` | Tabbed code | `tabs: [{id,label,language,code}]` |
75
+ | `<Decision title question options />` | Multi-option choice | `options: [{id,label,detail,recommended?}]` |
76
+ | `<OpenQuestions questions />` | Unanswered questions | `questions: [{id,label,kind,options?}]` |
77
+ | `<FileTree title entries />` | File-by-file changes | `entries: [{path,change,note?}]` |
78
+ | `<Diff before after filename language mode />` | Before/after | `before`, `after` |
79
+ | `<Workflow steps connections />` | Node graph | `steps: [{id,label,type}]` |
80
+ | `<Mockup title x y w h html />` | Inline UI mockup | `html` |
81
+ | `<Diagram title dataHtml dataCss />` | Inline SVG | `dataHtml` |
151
82
 
152
- ### 1. Backticks inside attribute strings break the parser
83
+ Every block needs a unique `id`. RichText + Callout use open/close tags (markdown body); everything else is self-closing.
153
84
 
154
- The MDX parser scans for `` ` `` to delimit template literals in JSX. A literal backtick inside an attribute value — even inside a double-quoted string — will close the surrounding context and produce a parse error.
85
+ ## Skeleton
155
86
 
156
87
  ```mdx
157
- <!-- WRONG: \` inside a string value kills the parser -->
158
- <RichText id="x">Run \`bizar install\` to bootstrap.</RichText>
88
+ <RichText id="overview">
89
+ ## What this is
159
90
 
160
- <!-- RIGHT: use straight quotes or rephrase -->
161
- <RichText id="x">Run 'bizar install' to bootstrap.</RichText>
162
- <RichText id="x">Run the installer to bootstrap.</RichText>
163
- ```
91
+ One sentence the reader can't miss.
92
+ </RichText>
164
93
 
165
- The parser's JSX-attribute walker does NOT track string literals when counting braces — so any `{` or `}` inside a string value also throws the parser off. Quote all strings that contain braces.
94
+ <Stat id="headline" label="X shipped" value="7" trend="flat" hint="across v3.22 v4.4.7" />
166
95
 
167
- ### 2. The parser counts braces naively (does NOT track strings)
96
+ <Callout id="tldr" tone="success">
97
+ One-sentence TL;DR.
98
+ </Callout>
168
99
 
169
- The `parseJsxValue` function uses a brace-depth counter that doesn't know about string literals. If you have something like:
100
+ <Table
101
+ id="releases"
102
+ columns={["v", "what", "fix"]}
103
+ rows={[
104
+ ["3.22", "unified", "—"],
105
+ ["4.4.1", "bg fix", "process exit crash"],
106
+ ]}
107
+ />
170
108
 
171
- ```mdx
172
- <FileTree entries={[{ path: "x", change: "added", note: "this {weird} note" }]} />
109
+ <FileTree
110
+ id="files"
111
+ title="Files changed"
112
+ entries={[
113
+ { path: "cli/provision.mjs", change: "added", note: "unified provisioner" },
114
+ ]}
115
+ />
173
116
  ```
174
117
 
175
- …the inner `{` and `}` inside the string still increment the brace depth. With deeply-nested or brace-laden strings the walker terminates at the wrong closing brace, leaving a truncated value for `parseJsxValue`.
176
-
177
- **Rule of thumb:** keep string values brace-free. If you must use `{...}` in a note, escape or rephrase.
178
-
179
- ### 3. Trailing commas in arrays used to be a phantom-element bug
118
+ ## The 5 things that break a glyph
180
119
 
181
- Before v4.4.8, an array ending with a trailing comma — e.g. `[a, b,]` — caused the parser to call `parseValue` on the closing `]`, which fell through to the bareword-identifier fallback and returned `{__ident: ''}` as a phantom element. The FileTree then had one extra broken entry that crashed the React renderer (`t.bg` on undefined).
120
+ These shipped as bugs. Read before writing.
182
121
 
183
- v4.4.8 fixed this in the parser. But: don't rely on trailing commas, even where supported — keep the array clean.
122
+ ### 1. Backticks inside attribute strings
184
123
 
185
- ### 4. `FileTree` `change` field must be exact
186
-
187
- `change` must be exactly one of: `added`, `modified`, `removed`, `renamed`. Anything else (including the empty string or `null`) makes `FILE_CHANGE[e.change]` return `undefined` and the renderer crashes with "can't access property 'bg' of undefined".
188
-
189
- ```mdx
190
- <!-- WRONG -->
191
- { path: "src/foo.ts", change: null, note: "..." }
192
- { path: "src/foo.ts", change: "", note: "..." }
124
+ The parser scans for `` ` `` and breaks. Use straight quotes or rephrase:
193
125
 
194
- <!-- RIGHT -->
195
- { path: "src/foo.ts", change: "modified", note: "..." }
196
- { path: "src/foo.ts", change: "added", note: "..." }
197
126
  ```
198
-
199
- If a file's status is genuinely unclear, use `modified` with a `note` that explains why.
200
-
201
- ### 5. MDX heading with `<N`
202
-
203
- A heading like `## Mobile (under 768px)` is fine. But `## Mobile <768px` breaks the MDX validator because `<7` looks like a malformed JSX tag. Always escape or rephrase:
204
-
205
- ```mdx
206
- ## Mobile (under 768px) <!-- fine -->
207
- ## Mobile: under 768px <!-- fine -->
208
- ## Mobile &lt; 768px <!-- fine but ugly -->
127
+ WRONG: Run `bizar install` to bootstrap.
128
+ RIGHT: Run 'bizar install' to bootstrap.
209
129
  ```
210
130
 
211
- ### 6. Block IDs must be unique within a glyph
131
+ ### 2. Braces inside string values
212
132
 
213
- If you copy a `<RichText>` block, change its `id`. The compiler may warn but won't fail. Two blocks with the same id will collide on the comment-pin overlay.
133
+ The brace counter doesn't know about strings. `{` / `}` in notes still bump depth. Keep note strings brace-free.
214
134
 
215
- ### 7. Children vs self-closing
135
+ ### 3. `FileTree` `change` must be exact
216
136
 
217
- Blocks with content (`RichText`, `Callout`) use open/close tags with children. Blocks with only data (`Stat`, `Table`, `FileTree`, `Decision`, etc.) are self-closing no children, no closing tag.
137
+ `added | modified | removed | renamed`. Empty string or `null` crashes on `t.bg`. Default to `modified` with a `note` when unclear.
218
138
 
219
- ```mdx
220
- <!-- self-closing -->
221
- <Stat id="x" label="..." value="..." />
139
+ ### 4. Duplicate block ids
222
140
 
223
- <!-- with children -->
224
- <RichText id="x">markdown content here</RichText>
225
- <Callout id="x" tone="warn">important message</Callout>
226
- ```
141
+ Comment pins and error reporting key off ids. Two blocks with the same id collide.
227
142
 
228
- ### 8. Em-dashes and special characters
143
+ ### 5. `## Heading <768px`
229
144
 
230
- The parser's JSON-like value reader handles `\\`, `\"`, `\'`, `\n`, `\t`, `\r` inside string literals. Em-dashes (`—`), curly quotes (`""`), and other Unicode characters are fine. Just avoid `\``.
145
+ The parser sees `<7` as a malformed JSX tag. Use parentheses or colons.
231
146
 
232
- ## meta.json example
147
+ ## Validate before shipping
233
148
 
234
- ```json
235
- {
236
- "title": "Chat UI — Complete Rewrite (Gemini-Inspired)",
237
- "slug": "chat-ui-rewrite",
238
- "status": "draft",
239
- "author": "drb0rk",
240
- "created": "2026-06-26T20:30:00.000Z",
241
- "lastEdited": "2026-06-26T20:30:00.000Z"
242
- }
149
+ ```bash
150
+ node -e "import('./bizar-dash/src/server/glyphs/mdx-compiler.mjs').then(m => { \
151
+ const fs = require('node:fs'); \
152
+ const out = m.compileGlyphMdxSync(fs.readFileSync('artifacts/<slug>/artifact.mdx','utf8')); \
153
+ console.log('blocks:', out.blocks.length, 'errors:', out.errors.length); \
154
+ })"
243
155
  ```
244
156
 
245
- `lastEdited` is updated whenever the dashboard re-saves the glyph via the toolbar.
246
-
247
- ## Validation workflow
248
-
249
- Before committing a glyph:
250
-
251
- 1. Run the compiler against your MDX:
252
- ```bash
253
- node -e "import('./bizar-dash/src/server/glyphs/mdx-compiler.mjs').then(m => { const fs = require('node:fs'); const src = fs.readFileSync('artifacts/<slug>/artifact.mdx', 'utf8'); const out = m.compileGlyphMdxSync(src); console.log('blocks:', out.blocks.length, 'errors:', out.errors); out.errors.forEach(e => console.error(' line', e.line, ':', e.message)); })"
254
- ```
255
- This catches parser bugs (missing tags, malformed attrs, etc.) before they hit the dashboard.
256
-
257
- 2. Visually inspect the rendered output by hitting `GET /api/artifacts/<slug>/render`. The response is the compiled JSON the React renderer consumes. Look for blocks with missing data fields — those will show up as `data: {}` or `data: []`.
258
-
259
- 3. Open the glyph in the dashboard. v4.4.8+ shows a red error banner at the top of the canvas if any block failed to render. The banner lists every block error AND every compiler warning.
260
-
261
- ## How to view in the dashboard
262
-
263
- Glyphs are rendered at `/artifacts/<slug>`. The dashboard shows them with:
264
- - **Section grouping** — by block id prefix (e.g. all blocks with ids starting `overview_` go into the "Overview" section)
265
- - **Comment pin overlay** — right-click anywhere to add a comment
266
- - **Floating toolbar** — Send to agent, share, fullscreen
267
- - **Error banner** — v4.4.8+: red banner at the top with block render errors and compiler warnings. The page is no longer blank when something fails — you'll see exactly which block crashed and why.
268
- - **Status badge** — `draft | review | shipped | archived`. `shipped` locks editing.
157
+ Also check yourself: does it fit on one screen? Are there any 4-sentence RichText blocks? Are the stats/tables/file trees doing the heavy lifting? If not, rewrite.
269
158
 
270
159
  ## See also
271
160
 
272
- - `bizar-dash/src/web/views/glyphs/components.tsx` — block component implementations
273
- - `bizar-dash/src/server/glyphs/mdx-compiler.mjs` — MDX parser (custom, no @mdx-js dependency at runtime)
274
- - `bizar-dash/src/web/views/glyphs/GlyphRenderer.tsx` — React renderer (v4.4.8+ has the error banner + ErrorBoundary)
275
- - `artifacts/sample-plan-login/` — a complete worked example
161
+ - `bizar-dash/src/server/glyphs/mdx-compiler.mjs` — parser
162
+ - `bizar-dash/src/web/views/glyphs/GlyphRenderer.tsx` — React renderer (has error banner)
163
+ - `bizar-dash/src/web/views/glyphs/components.tsx` — block implementations
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polderlabs/bizar",
3
- "version": "4.4.8",
3
+ "version": "4.4.10",
4
4
  "description": "Norse-pantheon multi-agent system for opencode — 13 agents across 4 cost tiers with cost-aware routing, plans, and a configurable agent harness. v4 ships as a single npm package bundling the dashboard server, opencode plugin, and typed SDK.",
5
5
  "type": "module",
6
6
  "bin": {