@khanglvm/relay 0.2.0 → 0.4.0

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.
package/README.md CHANGED
@@ -5,23 +5,38 @@
5
5
  `rly` lets an AI agent (Claude Code, Codex, or anything that can run a CLI) ask
6
6
  its user structured questions in a clean browser page — single/multi choice,
7
7
  yes-no, free text, rating scales — and/or present rich content blocks (markdown,
8
- charts, diagrams, tables, code, custom HTML), then **block until the user clicks
8
+ charts, diagrams, tables, code, sandboxed HTML, Graphviz and PlantUML diagrams), then **block until the user clicks
9
9
  Submit** and read the answers as JSON. No more "type *done* in the terminal",
10
10
  no more hand-rolled HTML + throwaway servers.
11
11
 
12
12
  Users can **hover chart points, diagram nodes, table cells, or select text to
13
13
  leave inline comments** — returned alongside answers as `result.annotations`.
14
+ Agents can reply to those comments and reopen the board as a conversation thread.
14
15
 
15
16
  - Zero runtime dependencies — plain Node ≥ 18, vanilla HTML/CSS/JS UI
16
17
  - Light/dark theme (auto + manual toggle), responsive, content-focused
17
18
  - Real-time answer autosave (drafts survive timeout/cancel)
18
19
  - Auto-closes the tab after submit and unblocks the CLI
19
- - Native content blocks: markdown, mermaid diagrams, Chart.js charts, tables, code, sandboxed HTML
20
- - Chart.js and Mermaid are **vendored and lazy-loaded** only when a board uses them — the base board stays dependency-free and as fast as before
20
+ - Native content blocks: markdown, mermaid diagrams, Graphviz diagrams, PlantUML, Chart.js charts, tables, code, sandboxed HTML
21
+ - Chart.js, Mermaid, and Graphviz are **vendored and lazy-loaded** only when a board uses them — the base board stays dependency-free and as fast as before
21
22
  - Element-level annotations: users comment on chart points, diagram nodes, table cells, text, or custom HTML elements; returned as `result.annotations`
23
+ - **Threaded annotation replies**: agents can reply to user comments via `rly reopen --replies`; conversations shown inline in the board
24
+ - **Live board mutation**: `rly update` lets an agent push a new spec to an already-open board; the page reloads and prefills answers from draft
22
25
  - Multiple boards at once, local history: reuse / modify / reopen / remove
23
26
  - Agent-first: JSON on stdout, logs on stderr, `--detach` + `wait` for shell tools with execution time limits, built-in agent guide & skill
24
27
 
28
+ ## See it
29
+
30
+ | Light theme | Dark theme |
31
+ |---|---|
32
+ | ![relay board light theme](https://raw.githubusercontent.com/khanglvm/relay/main/docs/assets/board-light.png) | ![relay board dark theme](https://raw.githubusercontent.com/khanglvm/relay/main/docs/assets/board-dark.png) |
33
+
34
+ | Annotation popover | Mobile |
35
+ |---|---|
36
+ | ![Annotation comment on a chart bar](https://raw.githubusercontent.com/khanglvm/relay/main/docs/assets/annotations.png) | ![Mobile view at 375px](https://raw.githubusercontent.com/khanglvm/relay/main/docs/assets/mobile.png) |
37
+
38
+ ![relay demo — board to annotation to summary](https://raw.githubusercontent.com/khanglvm/relay/main/docs/assets/demo.gif)
39
+
25
40
  ## Install
26
41
 
27
42
  ```sh
@@ -198,14 +213,55 @@ on phones. Height: 100–2400 px, default 360. Fragments (no `<html>` tag) are
198
213
  auto-wrapped to match the current theme; full documents receive a
199
214
  `?theme=light|dark` query param.
200
215
 
216
+ ### Graphviz diagram
217
+
218
+ ```json
219
+ { "type": "graphviz", "dot": "digraph { a -> b -> c }", "height": 300 }
220
+ ```
221
+
222
+ Rendered entirely **offline** via the vendored `viz-standalone.js` (Graphviz compiled to
223
+ WebAssembly). Never upscaled past the diagram's natural width; shrinks on narrow screens;
224
+ container max-height 1200 px with scroll. Nodes (`g.node`) and edges (`g.edge`) are
225
+ individually annotatable. Use Graphviz for precise dependency graphs, call graphs, or
226
+ state machines where Mermaid's auto-layout doesn't give enough control.
227
+
228
+ ### PlantUML diagram
229
+
230
+ ```json
231
+ { "type": "plantuml", "code": "@startuml\nA -> B: request\n@enduml", "height": 340 }
232
+ ```
233
+
234
+ Rendered via a **PlantUML server** (default: `https://www.plantuml.com/plantuml`). The
235
+ diagram source is deflate-encoded client-side and sent as a URL parameter — no server
236
+ round-trip for the page itself, just an `<img>` request. If the server is unreachable or
237
+ the browser lacks `CompressionStream`, a muted error card is shown.
238
+
239
+ **Privacy note:** diagram source is encoded and sent to the configured PlantUML server.
240
+ For sensitive diagrams, host your own server and pass `"server": "https://plantuml.example.com"`.
241
+
242
+ The rendered image is registered as a single annotatable element (target kind `image`).
243
+ Use PlantUML for UML sequence diagrams, class diagrams, and component diagrams.
244
+
201
245
  ## Annotations
202
246
 
203
247
  Users can leave inline comments on any annotatable element — chart data points,
204
- mermaid nodes, table cells, text selections inside markdown, and labelled
248
+ mermaid nodes, graphviz nodes and edges, table cells, text selections inside markdown, and labelled
205
249
  elements inside custom HTML. A small pin icon appears on hover; clicking opens a
206
250
  comment popover. Comments are autosaved with the draft and returned in the final
207
251
  result.
208
252
 
253
+ **Threaded replies:** each annotation can have replies. Agents can read
254
+ `result.annotations`, compose replies, and reopen the board as a conversation:
255
+
256
+ ```sh
257
+ # After reading result.annotations from a previous board:
258
+ rly reopen <id> --replies replies.json
259
+ # replies.json: [{"annotationId":"a1","text":"Good catch — fixed in the next sprint."}]
260
+ ```
261
+
262
+ The board reopens with agent replies shown inline under each comment. Users can reply
263
+ back; the conversation grows with each `rly reopen --replies` cycle.
264
+
209
265
  ### result.annotations shape
210
266
 
211
267
  ```json
@@ -226,22 +282,31 @@ result.
226
282
  "value": 19
227
283
  },
228
284
  "text": "Feb spike was due to the onboarding push — not repeatable.",
229
- "createdAt": "2026-06-11T10:23:00.000Z"
285
+ "author": "user",
286
+ "createdAt": "2026-06-11T10:23:00.000Z",
287
+ "replies": [
288
+ { "author": "agent", "text": "Confirmed — excluded from the trend line.", "createdAt": "2026-06-11T11:00:00.000Z" }
289
+ ]
230
290
  }
231
291
  ],
232
292
  "durationMs": 58000
233
293
  }
234
294
  ```
235
295
 
296
+ Each annotation has an optional `author` (`"user"` | `"agent"`, default `"user"`) and
297
+ an optional `replies` array (capped at 50; each reply: `{author, text, createdAt}`).
298
+
236
299
  ### Annotation target kinds
237
300
 
238
301
  | kind | what the user clicked |
239
302
  |---|---|
240
303
  | `chart-element` | a bar, point, or pie slice — includes `datasetIndex`, `index`, `label`, `value` |
241
304
  | `mermaid-node` | a node in a diagram — includes `nodeId`, `text` |
305
+ | `graphviz-node` | a node or edge in a Graphviz diagram — includes `nodeId`, `text` |
242
306
  | `table-cell` | a cell — includes `row` (0-based), `col` (column key), `value` |
243
307
  | `text` | a text selection inside a markdown block — includes `quote`, `prefix`, `suffix` |
244
308
  | `html-element` | a labelled element inside custom HTML (via `kit.js`) — includes `label`, optional `detail` |
309
+ | `image` | a PlantUML diagram image — includes `label` |
245
310
 
246
311
  ### kit.js — annotatable custom HTML
247
312
 
@@ -272,6 +337,8 @@ opens the annotation popover in the parent page anchored to that element.
272
337
  | `rly list [--json]` | Running boards |
273
338
  | `rly open [id]` | Re-open the browser tab of a running board |
274
339
  | `rly reopen <id>` | Serve a saved board again, **prefilled with saved answers** |
340
+ | `rly reopen <id> --replies file.json` | Reopen with agent replies appended to matching annotations |
341
+ | `rly update <id> [--file spec.json \| --title T \| --intro I \| -q "…"]` | Push a new spec to a running board — page reloads, answers survive via draft |
275
342
  | `rly reuse <id> [--dump]` | Re-run a past board as a new one (blank) |
276
343
  | `rly stop <id> \| --all` | Stop running board(s) — draft preserved |
277
344
  | `rly history [--limit n] [--json]` | Saved boards |
@@ -289,6 +356,17 @@ Exit codes: `0` submitted/acknowledged · `2` timeout · `3` cancelled ·
289
356
 
290
357
  Storage: `~/.relay` (override with `RLY_HOME`). Boards bind to `127.0.0.1` only.
291
358
 
359
+ ## Presence, push-wake & diagram co-editing (v0.4)
360
+
361
+ While a board is open the page reports user activity; `rly result <id>`
362
+ includes `presence` ({visible, focused, secondsSinceActivity}) and
363
+ `rly wait <id> --while-active --idle-grace 180` keeps waiting while the user
364
+ is demonstrably engaged instead of dying on a fixed timer. For pushes,
365
+ `--on-result '<cmd>'` (on ask/show/reopen/reuse) and `rly wait --notify-cmd`
366
+ execute your command with the result JSON on stdin the moment the board
367
+ finishes. Mermaid blocks with `"editable": true` let the user edit the diagram
368
+ source with live preview — their version returns as `result.blockEdits`.
369
+
292
370
  ## Agent skill (Claude Code, Codex, …)
293
371
 
294
372
  A universal [SKILL.md](skills/relay/SKILL.md) is bundled:
package/docs/AGENT.md CHANGED
@@ -149,6 +149,16 @@ per question (`"blocks": [...]` on a question object). Heights clamp to
149
149
  // Mermaid diagram — vendored, lazy-loaded; natural height, max 1200 px + scroll
150
150
  { "type": "mermaid", "code": "graph TD; A-->B; B-->C", "height": 400 }
151
151
 
152
+ // Graphviz diagram — vendored viz-standalone.js (Graphviz-WASM), fully offline
153
+ // Nodes (g.node) and edges (g.edge) are individually annotatable
154
+ { "type": "graphviz", "dot": "digraph { a -> b -> c }", "height": 300 }
155
+
156
+ // PlantUML diagram — rendered via a PlantUML server (default: plantuml.com)
157
+ // Source is deflate-encoded client-side; only an img URL is sent to the server.
158
+ // Use "server" for a self-hosted instance to avoid leaking sensitive diagrams.
159
+ { "type": "plantuml", "code": "@startuml\nA -> B: request\n@enduml", "height": 340 }
160
+ { "type": "plantuml", "code": "...", "server": "https://plantuml.example.com", "height": 300 }
161
+
152
162
  // Chart — shorthand (lazy-loads vendored Chart.js; default height 320)
153
163
  {
154
164
  "type": "chart",
@@ -202,6 +212,8 @@ per question (`"blocks": [...]` on a question object). Heights clamp to
202
212
  | Block | Best for |
203
213
  |---|---|
204
214
  | `mermaid` | flows, state machines, architecture overviews, sequence diagrams |
215
+ | `graphviz` | precise dependency graphs, call graphs, state machines when Mermaid's auto-layout falls short; individually annotatable nodes and edges |
216
+ | `plantuml` | UML diagrams (sequence, class, component) via server rendering; great for detailed interface contracts |
205
217
  | `chart` | numbers, trends, comparisons, metrics |
206
218
  | `table` | structured comparisons, option matrices, data grids |
207
219
  | `markdown` | prose context, background, instructions, section headings |
@@ -262,27 +274,100 @@ intro. Annotations are autosaved with the draft and returned in the final result
262
274
  "id": "a1",
263
275
  "questionId": "q-id or null for board-level",
264
276
  "blockId": "b2",
265
- "target": { ... },
266
- "text": "user comment text",
267
- "createdAt": "2026-06-11T10:23:00.000Z"
277
+ "target": { "kind": "chart-element", "datasetIndex": 0, "index": 1, "label": "Feb", "value": 19 },
278
+ "text": "Feb spike was from the onboarding push — not repeatable.",
279
+ "author": "user",
280
+ "createdAt": "2026-06-11T10:23:00.000Z",
281
+ "replies": [
282
+ { "author": "agent", "text": "Confirmed — excluded from the trend line.", "createdAt": "2026-06-11T11:00:00.000Z" }
283
+ ]
268
284
  }
269
285
  ]
270
286
  ```
271
287
 
272
- ### All 5 target kinds
288
+ `author` is `"user"` (default, when absent) or `"agent"`. `replies` is an array of
289
+ `{author, text, createdAt}` objects, capped at 50 per annotation.
290
+
291
+ ### All target kinds
273
292
 
274
293
  | kind | Fields | Triggered by |
275
294
  |---|---|---|
276
295
  | `chart-element` | `datasetIndex`, `index`, `label`, `value` | clicking a bar, point, or pie slice |
277
296
  | `mermaid-node` | `nodeId`, `text` | clicking a diagram node |
297
+ | `graphviz-node` | `nodeId`, `text` | clicking a Graphviz node or edge |
278
298
  | `table-cell` | `row` (0-based), `col` (column key), `value` | clicking a table cell |
279
299
  | `text` | `quote`, `prefix` (≤30 chars before), `suffix` (≤30 after) | selecting text in a markdown block |
280
300
  | `html-element` | `label`, `detail?` | clicking a `relayKit.commentable()` element |
301
+ | `image` | `label` | clicking the PlantUML diagram image |
281
302
 
282
303
  Read annotations as first-class feedback — they often carry the sharpest insight
283
304
  (e.g. a user circling the one data point that concerns them, or quoting the exact
284
305
  sentence they disagree with).
285
306
 
307
+ ### Threaded replies — `rly reopen --replies`
308
+
309
+ After reading `result.annotations`, an agent can reply to specific comments and
310
+ reopen the board as a conversation:
311
+
312
+ ```sh
313
+ rly reopen <id> --replies replies.json
314
+ ```
315
+
316
+ `replies.json` is an array of `{"annotationId": "a1", "text": "..."}` objects.
317
+ The server seeds the draft from the saved result, appends each reply with
318
+ `author: "agent"` and `createdAt: now`, then serves the board prefilled. Unknown
319
+ annotation IDs cause a `CliError` (exit 4) listing valid IDs.
320
+
321
+ The UI shows agent and user replies as a thread under each comment — agent replies
322
+ use an accent chip, user replies use a muted chip.
323
+
324
+ ## Presence — is the user still there?
325
+
326
+ While a board is open, the page reports activity (visibility, focus, idle
327
+ time). Use it instead of guessing timeouts:
328
+
329
+ ```sh
330
+ rly result b-xxxxx # open board → includes "presence":
331
+ # {open, seen, visible, focused, secondsSinceActivity, secondsSincePing}
332
+ rly wait b-xxxxx --timeout 550 --while-active --idle-grace 180
333
+ ```
334
+
335
+ `--while-active` keeps extending the wait as long as the user is demonstrably
336
+ active (page visible/focused and interaction within `--idle-grace` seconds,
337
+ default 180); once they go idle it returns the normal `wait-timeout` JSON,
338
+ with `presence` attached so you can decide what to do next. Prefer this over
339
+ raising `--timeout`.
340
+
341
+ ## Push-wake — get notified instead of polling
342
+
343
+ ```sh
344
+ rly ask --file spec.json --detach --on-result 'curl -s -X POST localhost:9999/wake -d @-'
345
+ rly wait b-xxxxx --notify-cmd 'touch /tmp/board-done'
346
+ ```
347
+
348
+ `--on-result` (on ask/show/reopen/reuse) runs your shell command the moment
349
+ the board reaches a terminal status — submitted, acknowledged, timeout, or
350
+ cancelled — with the full result JSON piped to stdin and `RLY_BOARD_ID`,
351
+ `RLY_STATUS`, `RLY_URL` in the environment. `--notify-cmd` does the same from
352
+ a `wait` that obtains a terminal result. Write a file your harness watches,
353
+ hit a webhook — whatever wakes you.
354
+
355
+ ## Editable diagrams — let the user redraw your mermaid
356
+
357
+ Add `"editable": true` to any mermaid block. The user gets an "Edit diagram"
358
+ button with live-preview source editing (syntax errors shown inline without
359
+ destroying the last good render; Reset restores your original). Their edited
360
+ source returns in the result:
361
+
362
+ ```json
363
+ "blockEdits": { "b2": "graph TD; A-->B; B-->C[their new step]" }
364
+ ```
365
+
366
+ Diff it against your original to see exactly what the user changed. Recipe:
367
+ propose an architecture as an editable mermaid block + a `yesno` "Does this
368
+ match your mental model?" + a `textarea` for anything the diagram can't say.
369
+ Edits autosave with the draft, so they survive reloads and timeouts too.
370
+
286
371
  ## Managing boards
287
372
 
288
373
  ```sh
@@ -290,6 +375,8 @@ rly list [--json] # running boards (id, url, pid)
290
375
  rly open [id] # re-open the browser tab of a running board
291
376
  rly reopen <id> # serve a SAVED board again, prefilled with its saved
292
377
  # answers/draft; user can edit and resubmit
378
+ rly reopen <id> --replies replies.json
379
+ # reopen with agent replies (see Threaded replies above)
293
380
  rly reuse <id> # re-run a past board as a NEW board (blank answers)
294
381
  rly spec <id> # print a saved spec — edit it, then `rly ask --file`
295
382
  rly history [--json] # saved boards with statuses
@@ -300,6 +387,26 @@ rly rm <id> | --all # delete saved board(s)
300
387
  Multiple boards can run at once (each gets its own port on 127.0.0.1).
301
388
  Storage lives in `~/.relay` (override with `RLY_HOME`).
302
389
 
390
+ ## Live board mutation — `rly update`
391
+
392
+ Push a new spec to an already-open board without stopping it:
393
+
394
+ ```sh
395
+ rly update <boardId> --file new-spec.json # replace the full spec
396
+ rly update <boardId> --title "New title" # patch just the title
397
+ rly update <boardId> --intro "New intro" # patch just the intro
398
+ rly update <boardId> -q "!Priority::single::p0,p1,p2" # append a question
399
+ ```
400
+
401
+ The page **reloads** for the user and prefills their previous answers from the
402
+ autosaved draft — answers for question IDs that no longer exist are silently
403
+ ignored. A small toast "Board updated by the agent" appears for 4 seconds.
404
+
405
+ Stdout: `{"status":"updated","boardId":"…","rev":2,"url":"…"}`.
406
+
407
+ **Caution:** the page reloads for the user. Batch your changes into one `rly update`
408
+ call rather than calling it repeatedly in a loop.
409
+
303
410
  ## Tips for agents
304
411
 
305
412
  - Prefer `--detach` + `rly wait` if your shell tool kills long commands.
@@ -313,5 +420,11 @@ Storage lives in `~/.relay` (override with `RLY_HOME`).
313
420
  leave inline comments — they won't discover it otherwise.
314
421
  - Check `result.annotations` before generating your next output; a comment on a
315
422
  specific data point or a quoted sentence often overrides the checkbox answer.
423
+ - Use `rly reopen <id> --replies replies.json` to answer the user's element
424
+ comments and reopen the board as a conversation thread.
425
+ - Use `rly update <id>` to push spec changes to a running board — the page
426
+ reloads and answers survive via draft autosave. Batch updates; do not spam.
427
+ - For sensitive PlantUML diagrams, set `"server": "https://your-server"` to avoid
428
+ sending source to the public plantuml.com server.
316
429
  - Bundled universal skill (Claude Code, Codex, any SKILL.md-aware agent):
317
430
  `rly skill install` — or `npx skills add khanglvm/relay`.
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanglvm/relay",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Browser-based question boards with rich blocks (markdown, charts, mermaid, tables, code, sandboxed HTML) and element-level annotations for AI coding agents (Claude Code, Codex, …): ask users structured questions, present interactive visuals, collect inline comments, wait for submit, read answers as JSON.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: relay
3
- description: Ask the user interactive questions in a browser board (single/multi choice, yes-no, free text, scale) and/or present rich content blocks (markdown, mermaid diagrams, charts, interactive tables, code, sandboxed HTML), then wait for Submit and read JSON answers plus element-level annotations. PROACTIVELY use whenever you would otherwise (a) call a native ask-user/question tool with 2+ questions or options that need explanation, (b) describe a UI/design/plan/architecture in prose that a visual would show better draft diagrams (mermaid), charts, and interactive tables as native blocks, or (c) hand-roll an HTML file or local server to demo an idea - relay replaces all three. Triggers - clarify requirements before ambiguous work, choose between approaches, plan approval, design/UX feedback, mockup or prototype review, compare alternatives, survey, metrics review, "ask the user", "show the user", "which do you prefer", "get feedback", diagram, chart, data table, architecture overview, metrics. Skip only for a single trivial yes/no confirmation.
3
+ description: Show the user anything visual in an interactive browser board - repo/file structures, architecture diagrams (mermaid, graphviz, plantuml, uml), charts, sortable data tables, code, prototypes - and/or ask structured questions (single/multi choice, yes-no, free text, scale), then wait for Submit and read JSON answers plus element-level comments and user-edited diagrams. PROACTIVELY use whenever you would otherwise (a) draw an ASCII tree/table/diagram in the terminal or describe a structure/design/plan in prose - render it as interactive blocks instead, (b) call a native ask-user/question tool with 2+ questions or options that need explanation, or (c) hand-roll an HTML file or local server to demo an idea - relay replaces all three. Triggers - show me the structure, repo/project/folder structure, file tree, directory layout, codebase map, architecture overview, dependency graph, sequence/class diagram, uml, visualize, diagram, chart, data table, metrics review, mockup or prototype review, plan approval, design/UX feedback, compare alternatives, let the user edit the diagram, clarify requirements before ambiguous work, survey, "ask the user", "show the user", "which do you prefer", "get feedback". Skip only for a single trivial yes/no confirmation.
4
4
  ---
5
5
 
6
6
  # relay (`rly`)
@@ -35,20 +35,34 @@ questions into ONE board rather than opening several in a row.
35
35
 
36
36
  ## Choose a pattern
37
37
 
38
- 1. **Blocking** simple, but your shell tool must tolerate waiting:
38
+ **DEFAULT: detached.** Most agent shell tools kill long-running commands, and a
39
+ blocking `rly ask` that gets killed cancels the board. Always prefer:
39
40
 
40
- ```sh
41
- rly ask --file spec.json --timeout 1800 # prints result JSON when user submits
42
- ```
41
+ ```sh
42
+ rly ask --file spec.json --detach # returns {"boardId":"b-…","url":…} immediately
43
+ rly wait b-xxxxx --timeout 550 # blocks until submit, prints result JSON
44
+ # (on exit 2 "wait-timeout" just run wait again)
45
+ rly result b-xxxxx # non-blocking peek (includes live draft)
46
+ ```
47
+
48
+ For long waits prefer presence-aware waiting over a huge --timeout:
49
+
50
+ ```sh
51
+ rly wait b-xxxxx --timeout 550 --while-active --idle-grace 180
52
+ # keeps extending while the user is demonstrably viewing/typing on the board;
53
+ # returns wait-timeout promptly once they are idle/gone (presence included)
54
+ rly result b-xxxxx # while open also shows presence {visible, focused, secondsSinceActivity}
55
+ ```
43
56
 
44
- 2. **Detached** use when your shell tool has an execution time limit
45
- (e.g. run it, then wait in a separate call):
57
+ Push-wake instead of polling: add --on-result '<shell cmd>' to ask/show/reopen
58
+ (or --notify-cmd on wait) - the command runs the moment the board finishes,
59
+ with the full result JSON on stdin and RLY_BOARD_ID/RLY_STATUS/RLY_URL in env.
46
60
 
47
- ```sh
48
- rly ask --file spec.json --detach # {"boardId":"b-…","url":…} immediately
49
- rly wait b-xxxxx --timeout 3500 # blocks until submit, prints result JSON
50
- rly result b-xxxxx # non-blocking peek (includes live draft)
51
- ```
61
+ Blocking mode (`rly ask --file spec.json --timeout 1800`, no --detach) is fine
62
+ ONLY when your shell tool has no execution time limit.
63
+
64
+ Useful flags: `--no-open` (don't auto-open the browser for tests/CI; real
65
+ users need the tab, so omit it normally) · `--title` · `--timeout <sec>`.
52
66
 
53
67
  Exit codes: 0 submitted · 2 timeout · 3 cancelled · 5 not found. On
54
68
  timeout/cancel the result still contains the autosaved `draft` of partial
@@ -66,7 +80,8 @@ answers and any annotations written so far.
66
80
  { "id": "parts", "type": "multi", "label": "Include?", "options": ["api", "ui"], "note": true },
67
81
  { "id": "ship", "type": "yesno", "label": "Ship now?" },
68
82
  { "id": "why", "type": "textarea", "label": "Reasoning?" },
69
- { "id": "conf", "type": "scale", "label": "Confidence", "min": 1, "max": 5 }
83
+ { "id": "conf", "type": "scale", "label": "Confidence", "min": 1, "max": 5,
84
+ "minLabel": "low", "maxLabel": "high" }
70
85
  ]
71
86
  }
72
87
  ```
@@ -92,6 +107,9 @@ Add `"blocks": [...]` to the root or to any question.
92
107
  ```jsonc
93
108
  { "type": "markdown", "md": "## Section\n**prose**" }
94
109
  { "type": "mermaid", "code": "graph TD; A-->B", "height": 400 }
110
+ { "type": "graphviz", "dot": "digraph { a -> b }", "height": 300 }
111
+ { "type": "plantuml", "code": "@startuml\nA->B\n@enduml", "height": 300 }
112
+ { "type": "plantuml", "code": "...", "server": "https://plantuml.example.com" }
95
113
  { "type": "chart", "kind": "bar", "title": "...",
96
114
  "labels": ["Jan","Feb"], "series": [{"label":"x","data":[1,2]}], "height": 320 }
97
115
  { "type": "chart", "config": { /* full Chart.js v4 config */ }, "height": 300 }
@@ -101,14 +119,15 @@ Add `"blocks": [...]` to the root or to any question.
101
119
  { "type": "html", "htmlFile": "viz.html", "height": 400 }
102
120
  ```
103
121
 
104
- Chart.js and Mermaid are **vendored and lazy-loaded** — the base board stays
105
- dependency-free. Legacy `"html"` / `"htmlFile"` / `"htmlHeight"` on root or
106
- questions are still accepted and normalised automatically.
122
+ Chart.js, Mermaid, and Graphviz are **vendored and lazy-loaded** — the base board
123
+ stays dependency-free. PlantUML uses the public plantuml.com server by default;
124
+ pass `"server"` for a self-hosted instance. Legacy `"html"` / `"htmlFile"` /
125
+ `"htmlHeight"` on root or questions are still accepted and normalised automatically.
107
126
 
108
127
  ## Annotations
109
128
 
110
- Users can hover chart points, diagram nodes, table cells, or select text in
111
- markdown to leave inline comments. Always mention this in the board intro.
129
+ Users can hover chart points, diagram nodes (mermaid + graphviz), table cells, or
130
+ select text in markdown to leave inline comments. Always mention this in the board intro.
112
131
 
113
132
  `result.annotations` is an array of:
114
133
 
@@ -117,18 +136,32 @@ markdown to leave inline comments. Always mention this in the board intro.
117
136
  "id": "a1",
118
137
  "questionId": "q-id or null",
119
138
  "blockId": "b2",
120
- "target": {
121
- "kind": "chart-element | mermaid-node | table-cell | text | html-element",
122
- "..."
123
- },
139
+ "target": { "kind": "chart-element | mermaid-node | graphviz-node | table-cell | text | html-element | image", "..." },
124
140
  "text": "user comment",
125
- "createdAt": "ISO"
141
+ "author": "user",
142
+ "createdAt": "ISO",
143
+ "replies": [{ "author": "agent", "text": "acknowledged", "createdAt": "ISO" }]
126
144
  }
127
145
  ```
128
146
 
129
147
  Read annotations before generating your next output — a comment on a specific
130
148
  data point often carries sharper signal than a checkbox answer.
131
149
 
150
+ ### Reply to annotations (agent → user conversation)
151
+
152
+ ```sh
153
+ # 1. Read result from a previous board
154
+ rly result <id> # or rly wait <id>
155
+
156
+ # 2. Build replies file
157
+ # replies.json: [{"annotationId":"a1","text":"Good catch — fixed."}]
158
+
159
+ # 3. Reopen as a conversation
160
+ rly reopen <id> --replies replies.json
161
+ ```
162
+
163
+ Unknown annotation IDs cause an error listing valid IDs (exit 4).
164
+
132
165
  ## Recipes
133
166
 
134
167
  **Plan approval** — board-level `markdown` block rendering the plan, one `yesno`
@@ -148,9 +181,31 @@ numbers, followed by a `table` block for the raw data; at least one question
148
181
  asking what to act on. In the intro, tell the user they can click chart points
149
182
  and table cells to comment on specific values.
150
183
 
184
+ ## Diagram co-editing (user edits your diagram)
185
+
186
+ Add "editable": true to a mermaid block: the user gets an Edit button with
187
+ live-preview source editing. Their version comes back as
188
+ result.blockEdits["<blockId>"] - diff it against your original to see what
189
+ they changed. Recipe: propose an architecture as an editable mermaid block +
190
+ one yesno "Does this match your mental model?" + a textarea for notes.
191
+
151
192
  ## Reuse & management
152
193
 
153
194
  `rly history` (saved boards) · `rly spec <id>` (print spec to modify) ·
154
195
  `rly reuse <id>` (re-run blank) · `rly reopen <id>` (re-open with saved
155
- answers prefilled) · `rly list` / `rly open` / `rly stop <id>` · `rly rm <id>`.
196
+ answers prefilled) · `rly reopen <id> --replies file.json` (add agent replies) ·
197
+ `rly list` / `rly open` / `rly stop <id>` · `rly rm <id>`.
156
198
  Multiple boards can run concurrently.
199
+
200
+ ### Live mutation — `rly update`
201
+
202
+ Push a new spec to a running board. The page reloads and prefills answers from the
203
+ autosaved draft — answers survive, the user sees a toast "Board updated by the agent".
204
+
205
+ ```sh
206
+ rly update <boardId> --file new-spec.json # replace spec
207
+ rly update <boardId> --title T --intro I # patch fields
208
+ rly update <boardId> -q "!Priority::single::p0,p1" # append question
209
+ ```
210
+
211
+ Batch your changes into one call — the page reloads for the user on each update.
@@ -26,6 +26,15 @@
26
26
  "code": "graph LR\n Client-->|HTTPS|Gateway\n Gateway-->AuthService\n Gateway-->APIService\n APIService-->DB[(Postgres)]\n APIService-->Cache[(Redis)]\n APIService-->Queue[[Job queue]]\n Queue-->Worker\n Worker-->DB",
27
27
  "height": 300
28
28
  },
29
+ {
30
+ "type": "markdown",
31
+ "md": "## Service dependency graph\nThe Graphviz diagram below shows precise call-time dependencies between services. Click any node or edge to leave a comment."
32
+ },
33
+ {
34
+ "type": "graphviz",
35
+ "dot": "digraph services {\n rankdir=LR\n node [shape=box style=filled fontname=Helvetica fontsize=11]\n Gateway [fillcolor=\"#c8e6c9\"]\n APIService [fillcolor=\"#fff9c4\"]\n AuthService[fillcolor=\"#c8e6c9\"]\n DB [shape=cylinder fillcolor=\"#bbdefb\"]\n Cache [shape=cylinder fillcolor=\"#bbdefb\"]\n Worker [fillcolor=\"#fff9c4\"]\n Gateway -> APIService\n Gateway -> AuthService\n APIService -> DB\n APIService -> Cache\n APIService -> Worker [style=dashed label=\"async\"]\n Worker -> DB\n}",
36
+ "height": 260
37
+ },
29
38
  {
30
39
  "type": "markdown",
31
40
  "md": "## Service health snapshot\nCurrent status as of the last deployment. Click any cell to comment."
@@ -0,0 +1,15 @@
1
+ {
2
+ "title": "Architecture review — redraw it if I got it wrong",
3
+ "intro": "Below is my proposed architecture. If it doesn't match your mental model, click 'Edit diagram' and change it directly — I'll read your version.",
4
+ "blocks": [
5
+ {
6
+ "type": "mermaid",
7
+ "editable": true,
8
+ "code": "graph TD; client[Web Client] --> api[API Gateway]; api --> auth[Auth Service]; api --> core[Core Service]; core --> db[(Postgres)]; core --> queue[[Job Queue]]"
9
+ }
10
+ ],
11
+ "questions": [
12
+ { "id": "match", "type": "yesno", "label": "Does this match your mental model (after your edits, if any)?", "required": true },
13
+ { "id": "notes", "type": "textarea", "label": "Anything the diagram can't express?", "placeholder": "constraints, scaling concerns, naming…" }
14
+ ]
15
+ }