@khanglvm/relay 0.2.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/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@khanglvm/relay",
3
+ "version": "0.2.0",
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
+ "keywords": [
6
+ "ai-agents",
7
+ "claude-code",
8
+ "codex",
9
+ "cli",
10
+ "interactive-questions",
11
+ "human-in-the-loop",
12
+ "annotations",
13
+ "charts",
14
+ "prototype",
15
+ "visualization",
16
+ "agent-skill"
17
+ ],
18
+ "license": "MIT",
19
+ "author": "Le Vu Minh Khang (https://github.com/khanglvm)",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/khanglvm/relay.git"
23
+ },
24
+ "homepage": "https://github.com/khanglvm/relay#readme",
25
+ "bugs": "https://github.com/khanglvm/relay/issues",
26
+ "type": "module",
27
+ "bin": {
28
+ "rly": "bin/rly.js",
29
+ "relay": "bin/rly.js"
30
+ },
31
+ "files": [
32
+ "bin",
33
+ "src",
34
+ "vendor",
35
+ "skills",
36
+ "docs",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "engines": {
41
+ "node": ">=18.3"
42
+ },
43
+ "scripts": {
44
+ "test": "node test/smoke.mjs"
45
+ }
46
+ }
@@ -0,0 +1,156 @@
1
+ ---
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.
4
+ ---
5
+
6
+ # relay (`rly`)
7
+
8
+ CLI that opens a local web board for the user, blocks until they click
9
+ **Submit**, and prints their answers plus element-level annotations as JSON to
10
+ stdout. Works for any agent (Claude Code, Codex, …). Answers autosave in real
11
+ time; the tab auto-closes after submit.
12
+
13
+ If `rly` is not installed: `npm i -g @khanglvm/relay` or invoke via
14
+ `npx -y @khanglvm/relay <command …>`.
15
+
16
+ **Full reference: run `rly agent` (complete guide) and `rly schema` (spec JSON
17
+ Schema).** The essentials are below.
18
+
19
+ ## When to use rly vs your native question tool
20
+
21
+ | Situation | Use |
22
+ |---|---|
23
+ | One trivial confirmation ("proceed?") | native tool |
24
+ | 2+ questions, or options that need descriptions | **rly** |
25
+ | Choice is easier to make visually (layouts, designs, diagrams) | **rly** (blocks per question) |
26
+ | Show metrics / trends / data comparisons | **rly** (chart + table blocks) |
27
+ | Present a prototype / demo an idea | **rly show** — never hand-roll an HTML file + server |
28
+ | Gather requirements / plan approval / feedback round | **rly** |
29
+ | Architecture or flow that benefits from a diagram | **rly** (mermaid block) |
30
+ | Something you can decide yourself from context | neither — just decide |
31
+
32
+ Once the user has answered one board in a session, prefer boards for later
33
+ question rounds too — they've shown they engage with them. Batch related
34
+ questions into ONE board rather than opening several in a row.
35
+
36
+ ## Choose a pattern
37
+
38
+ 1. **Blocking** — simple, but your shell tool must tolerate waiting:
39
+
40
+ ```sh
41
+ rly ask --file spec.json --timeout 1800 # prints result JSON when user submits
42
+ ```
43
+
44
+ 2. **Detached** — use when your shell tool has an execution time limit
45
+ (e.g. run it, then wait in a separate call):
46
+
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
+ ```
52
+
53
+ Exit codes: 0 submitted · 2 timeout · 3 cancelled · 5 not found. On
54
+ timeout/cancel the result still contains the autosaved `draft` of partial
55
+ answers and any annotations written so far.
56
+
57
+ ## Minimal spec
58
+
59
+ ```json
60
+ {
61
+ "title": "Pick the approach",
62
+ "intro": "Context for the user. Hover chart points or select text to leave comments.",
63
+ "questions": [
64
+ { "id": "approach", "type": "single", "label": "Which one?", "required": true,
65
+ "options": [{ "value": "a", "label": "A", "description": "fast" }, "B"], "other": true },
66
+ { "id": "parts", "type": "multi", "label": "Include?", "options": ["api", "ui"], "note": true },
67
+ { "id": "ship", "type": "yesno", "label": "Ship now?" },
68
+ { "id": "why", "type": "textarea", "label": "Reasoning?" },
69
+ { "id": "conf", "type": "scale", "label": "Confidence", "min": 1, "max": 5 }
70
+ ]
71
+ }
72
+ ```
73
+
74
+ Types: `single`, `multi`, `yesno`, `text`, `textarea`, `scale`. Users may
75
+ submit with unanswered questions (returned in `skipped`) unless
76
+ `"allowPartial": false` or per-question `"required": true`.
77
+
78
+ Set `"note": true` on a question to add a small optional free-text field under
79
+ it — use when the user may want to qualify their choice. Returned as
80
+ `result.notes[questionId]`.
81
+
82
+ Quick one-liners without a spec file:
83
+
84
+ ```sh
85
+ rly ask -q "Deploy now?::yesno" -q "!Env::single::dev,staging,prod" # "!" = required
86
+ ```
87
+
88
+ ## Blocks cheat-sheet
89
+
90
+ Add `"blocks": [...]` to the root or to any question.
91
+
92
+ ```jsonc
93
+ { "type": "markdown", "md": "## Section\n**prose**" }
94
+ { "type": "mermaid", "code": "graph TD; A-->B", "height": 400 }
95
+ { "type": "chart", "kind": "bar", "title": "...",
96
+ "labels": ["Jan","Feb"], "series": [{"label":"x","data":[1,2]}], "height": 320 }
97
+ { "type": "chart", "config": { /* full Chart.js v4 config */ }, "height": 300 }
98
+ { "type": "table", "columns": ["A","B"], "rows": [["x","y"]], "sortable": true }
99
+ { "type": "code", "lang": "js", "code": "const x = 1;" }
100
+ { "type": "html", "html": "<p>hi</p>", "height": 360 }
101
+ { "type": "html", "htmlFile": "viz.html", "height": 400 }
102
+ ```
103
+
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.
107
+
108
+ ## Annotations
109
+
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.
112
+
113
+ `result.annotations` is an array of:
114
+
115
+ ```json
116
+ {
117
+ "id": "a1",
118
+ "questionId": "q-id or null",
119
+ "blockId": "b2",
120
+ "target": {
121
+ "kind": "chart-element | mermaid-node | table-cell | text | html-element",
122
+ "..."
123
+ },
124
+ "text": "user comment",
125
+ "createdAt": "ISO"
126
+ }
127
+ ```
128
+
129
+ Read annotations before generating your next output — a comment on a specific
130
+ data point often carries sharper signal than a checkbox answer.
131
+
132
+ ## Recipes
133
+
134
+ **Plan approval** — board-level `markdown` block rendering the plan, one `yesno`
135
+ "Approve this plan?", one `multi` "Which parts should change?" (`"note": true`),
136
+ one `textarea` for concerns.
137
+
138
+ **Requirements gathering** — one board with: `single` for the core approach
139
+ (options with `description`s + `"other": true`), `multi` for scope, `scale` for
140
+ urgency, `textarea` for constraints.
141
+
142
+ **A/B design review** — `single` question with a `blocks` array containing an
143
+ `html` block showing both options side by side; options `["A", "B"]`; `scale`
144
+ for confidence; `textarea` for what's missing from both.
145
+
146
+ **Metrics review** — board-level `chart` block (bar or line) showing the key
147
+ numbers, followed by a `table` block for the raw data; at least one question
148
+ asking what to act on. In the intro, tell the user they can click chart points
149
+ and table cells to comment on specific values.
150
+
151
+ ## Reuse & management
152
+
153
+ `rly history` (saved boards) · `rly spec <id>` (print spec to modify) ·
154
+ `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>`.
156
+ Multiple boards can run concurrently.
@@ -0,0 +1,118 @@
1
+ {
2
+ "title": "Q2 engineering review",
3
+ "intro": "Below you'll find the sprint metrics, architecture overview, and a data table. Hover chart bars, click diagram nodes, or click table cells to leave inline comments — they come back with your answers. Select any text in a markdown section to annotate it too.",
4
+ "blocks": [
5
+ {
6
+ "type": "markdown",
7
+ "md": "## Sprint velocity\nThe chart below shows shipped vs planned story points for each sprint this quarter. Click any bar to comment on a specific sprint."
8
+ },
9
+ {
10
+ "type": "chart",
11
+ "kind": "bar",
12
+ "title": "Q2 velocity — shipped vs planned",
13
+ "labels": ["S1", "S2", "S3", "S4", "S5", "S6"],
14
+ "series": [
15
+ { "label": "Shipped", "data": [34, 41, 29, 47, 38, 52], "color": "#4d8a66" },
16
+ { "label": "Planned", "data": [40, 40, 40, 40, 40, 40], "color": "#c2674b" }
17
+ ],
18
+ "height": 320
19
+ },
20
+ {
21
+ "type": "markdown",
22
+ "md": "## System architecture\nThe diagram below shows the current service topology. Click any node to comment on it."
23
+ },
24
+ {
25
+ "type": "mermaid",
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
+ "height": 300
28
+ },
29
+ {
30
+ "type": "markdown",
31
+ "md": "## Service health snapshot\nCurrent status as of the last deployment. Click any cell to comment."
32
+ },
33
+ {
34
+ "type": "table",
35
+ "columns": [
36
+ { "key": "service", "label": "Service" },
37
+ { "key": "status", "label": "Status", "align": "center" },
38
+ { "key": "p99ms", "label": "p99 (ms)", "align": "right" },
39
+ { "key": "errRate", "label": "Error rate", "align": "right" },
40
+ { "key": "owner", "label": "Owner" }
41
+ ],
42
+ "rows": [
43
+ { "service": "Gateway", "status": "healthy", "p99ms": 42, "errRate": "0.1%", "owner": "platform" },
44
+ { "service": "AuthService", "status": "healthy", "p99ms": 98, "errRate": "0.0%", "owner": "identity" },
45
+ { "service": "APIService", "status": "degraded", "p99ms": 620, "errRate": "2.4%", "owner": "core" },
46
+ { "service": "Worker", "status": "healthy", "p99ms": 310, "errRate": "0.3%", "owner": "core" }
47
+ ],
48
+ "sortable": true
49
+ },
50
+ {
51
+ "type": "markdown",
52
+ "md": "## Config reference\nDeployment config in use this quarter:"
53
+ },
54
+ {
55
+ "type": "code",
56
+ "lang": "yaml",
57
+ "code": "api_service:\n replicas: 4\n memory_limit: 512Mi\n cpu_limit: 500m\n db_pool_size: 20\n cache_ttl_s: 300"
58
+ }
59
+ ],
60
+ "questions": [
61
+ {
62
+ "id": "biggest_concern",
63
+ "type": "single",
64
+ "label": "Which area needs the most attention next quarter?",
65
+ "required": true,
66
+ "options": [
67
+ { "value": "api_perf", "label": "API Service performance", "description": "p99 and error rate are high" },
68
+ { "value": "velocity", "label": "Sprint predictability", "description": "variance between sprints" },
69
+ { "value": "arch", "label": "Architecture complexity", "description": "service sprawl, dependency depth" },
70
+ { "value": "on_call", "label": "On-call burden", "description": "toil from degraded services" }
71
+ ],
72
+ "other": true,
73
+ "note": true
74
+ },
75
+ {
76
+ "id": "api_degraded_cause",
77
+ "type": "single",
78
+ "label": "What is most likely causing the APIService degradation?",
79
+ "options": [
80
+ { "value": "db_pool", "label": "DB connection pool exhaustion" },
81
+ { "value": "cache_miss","label": "Cache miss storm" },
82
+ { "value": "upstream", "label": "Upstream traffic spike" },
83
+ { "value": "unknown", "label": "Unknown — needs investigation" }
84
+ ],
85
+ "other": true
86
+ },
87
+ {
88
+ "id": "ship_reliability_work",
89
+ "type": "yesno",
90
+ "label": "Should we dedicate at least one sprint to reliability before adding features?"
91
+ },
92
+ {
93
+ "id": "velocity_target",
94
+ "type": "scale",
95
+ "label": "How ambitious should Q3's velocity target be?",
96
+ "min": 1,
97
+ "max": 5,
98
+ "minLabel": "conservative (≤40 pts)",
99
+ "maxLabel": "aggressive (60+ pts)",
100
+ "blocks": [
101
+ {
102
+ "type": "markdown",
103
+ "md": "Current average: **40 pts/sprint**. Improving reliability tooling could raise the ceiling, but also costs sprint capacity up front."
104
+ }
105
+ ]
106
+ },
107
+ {
108
+ "id": "other_notes",
109
+ "type": "textarea",
110
+ "label": "Anything else I should factor in for Q3 planning?",
111
+ "placeholder": "team changes, external deadlines, tech debt priorities…"
112
+ }
113
+ ],
114
+ "note": true,
115
+ "allowPartial": false,
116
+ "autoClose": true,
117
+ "submitLabel": "Submit review"
118
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "title": "Auth feature — decisions needed",
3
+ "intro": "I'm about to implement authentication. Three decisions before I start. Hover chart points or select text to leave comments.",
4
+ "questions": [
5
+ {
6
+ "id": "provider",
7
+ "type": "single",
8
+ "label": "Which auth approach?",
9
+ "required": true,
10
+ "options": [
11
+ { "value": "oauth", "label": "OAuth (GitHub + Google)", "description": "no password storage, needs provider setup" },
12
+ { "value": "magic-link", "label": "Magic links", "description": "email-based, no passwords" },
13
+ { "value": "password", "label": "Classic email + password", "description": "full control, more security surface" }
14
+ ],
15
+ "other": true
16
+ },
17
+ {
18
+ "id": "scope",
19
+ "type": "multi",
20
+ "label": "Which surfaces need auth in this iteration?",
21
+ "options": ["web app", "REST API", "admin panel", "CLI"]
22
+ },
23
+ { "id": "mfa", "type": "yesno", "label": "Include 2FA now (vs. a later iteration)?" },
24
+ { "id": "priority", "type": "scale", "label": "How urgent is this feature?", "min": 1, "max": 5, "minLabel": "whenever", "maxLabel": "blocking" },
25
+ { "id": "constraints", "type": "textarea", "label": "Any constraints I should know about?", "placeholder": "compliance, existing user table, …" }
26
+ ]
27
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "title": "Dashboard layout — pick a direction",
3
+ "intro": "Two interactive mockups below. Click around, then answer. Select any text to leave inline comments.",
4
+ "questions": [
5
+ {
6
+ "id": "layout",
7
+ "type": "single",
8
+ "label": "Which layout direction?",
9
+ "required": true,
10
+ "blocks": [
11
+ {
12
+ "type": "html",
13
+ "html": "<!doctype html><html><body style=\"margin:0;font-family:system-ui;display:flex;gap:12px;padding:12px;background:#fff\"><div style=\"flex:1;border:2px solid #3b6ef6;border-radius:10px;padding:10px\"><b>A · sidebar</b><div style=\"display:flex;gap:6px;margin-top:8px\"><div style=\"width:60px;height:120px;background:#dbe4ff;border-radius:6px\"></div><div style=\"flex:1;height:120px;background:#f1f3f9;border-radius:6px\"></div></div></div><div style=\"flex:1;border:2px solid #999;border-radius:10px;padding:10px\"><b>B · topbar</b><div style=\"margin-top:8px\"><div style=\"height:24px;background:#dbe4ff;border-radius:6px\"></div><div style=\"height:90px;background:#f1f3f9;border-radius:6px;margin-top:6px\"></div></div></div></body></html>",
14
+ "height": 220
15
+ }
16
+ ],
17
+ "options": [
18
+ { "value": "sidebar", "label": "A — sidebar navigation" },
19
+ { "value": "topbar", "label": "B — topbar navigation" }
20
+ ]
21
+ },
22
+ { "id": "density", "type": "scale", "label": "Information density?", "min": 1, "max": 5, "minLabel": "airy", "maxLabel": "dense" },
23
+ { "id": "missing", "type": "textarea", "label": "Anything missing from both?" }
24
+ ]
25
+ }