@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 +83 -5
- package/docs/AGENT.md +117 -4
- package/docs/assets/annotations.png +0 -0
- package/docs/assets/board-dark.png +0 -0
- package/docs/assets/board-light.png +0 -0
- package/docs/assets/demo.gif +0 -0
- package/docs/assets/mobile.png +0 -0
- package/package.json +1 -1
- package/skills/relay/SKILL.md +79 -24
- package/skills/relay/examples/blocks-showcase.json +9 -0
- package/skills/relay/examples/diagram-coedit.json +15 -0
- package/src/cli.js +287 -15
- package/src/server.js +148 -11
- package/src/spec.js +37 -4
- package/src/ui/annotate.css +57 -5
- package/src/ui/annotate.js +130 -5
- package/src/ui/app.js +117 -2
- package/src/ui/blocks.css +97 -0
- package/src/ui/blocks.js +281 -19
- package/src/ui/style.css +9 -0
- package/vendor/VERSIONS.json +2 -1
- package/vendor/viz-standalone.js +9 -0
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,
|
|
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
|
|
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
|
+
|  |  |
|
|
33
|
+
|
|
34
|
+
| Annotation popover | Mobile |
|
|
35
|
+
|---|---|
|
|
36
|
+
|  |  |
|
|
37
|
+
|
|
38
|
+

|
|
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
|
-
"
|
|
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": "
|
|
267
|
-
"
|
|
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
|
-
|
|
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.
|
|
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",
|
package/skills/relay/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: relay
|
|
3
|
-
description:
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
|
|
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
|
-
|
|
45
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
|
105
|
-
dependency-free.
|
|
106
|
-
|
|
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
|
|
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
|
-
"
|
|
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
|
|
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
|
+
}
|