Skip to main content
June 15, 2026 5 min read

Relay: reviewing agent work in a browser

I built relay so coding agents could put questions, diagrams, and work for review on a local browser board, then read the answers and comments as JSON.

AI Agents Developer Tools Open Source Human-in-the-Loop Claude Code

After months of working with coding agents in a terminal, I kept running into the same problem: reviewing their work took more effort than it should. An architecture diagram became boxes made of dashes and pipes. To comment on a migration plan, I had to describe which passage I meant. A question about a database might only need a typed answer, but a layout comparison needed something I could see.

I built relay to let an agent open a local browser board for those reviews. It can put questions beside the work they refer to and collect the answers as JSON.

Where terminal reviews get awkward

When an agent asks six questions one at a time, each answer adds another wait. Seeing them together would let me understand the decision and answer the whole set.

Visual choices are harder still. A description such as “Option B is the one with the caching layer” asks me to remember an earlier message while comparing architectures. Layouts and color schemes have the same problem. I want to see each option beside its label.

Long reviews also need a way to leave feedback at a specific point. A plan, diff summary, or table can be readable in a terminal, but responding usually means copying text or explaining which section needs attention.

A board for questions and review

An agent writes a board specification and opens it in your browser. The board can contain form controls and charts alongside diagrams or other work for review. You choose answers, leave comments, and submit. Relay returns the result to the agent as JSON.

This command opens the board and waits for your response:

rly ask --file board.json --timeout 1800

The command blocks until you submit, then prints the result to stdout as JSON. The specification contains a title, content blocks, and questions:

{
  "title": "Pick the caching strategy",
  "blocks": [
    { "type": "mermaid", "code": "graph LR; Client-->Edge; Edge-->Origin; Origin-->DB" },
    { "type": "table",
      "columns": ["Strategy", "p95 latency", "Cost/mo"],
      "rows": [["Edge KV", "12ms", "$40"], ["Redis", "8ms", "$120"]],
      "sortable": true }
  ],
  "questions": [
    { "id": "strategy", "type": "single", "label": "Which one ships first?",
      "options": [{ "value": "kv", "label": "Edge KV" }, { "value": "redis", "label": "Redis" }] }
  ]
}

A board can show all six questions together. You can zoom into a diagram or click a chart point to attach feedback to that value.

Building for agent runtimes

Agents often install tools unattended, and their runtimes may limit how long a command can wait. Those constraints shaped how Relay is packaged and how it collects answers.

Zero runtime dependencies

Relay runs on Node ≥ 18 and has no runtime dependencies in node_modules. I wanted an unattended npm i -g @khanglvm/relay to have fewer dependencies that could fail to install or introduce breaking changes and vulnerabilities.

Chart.js, Mermaid, and the Graphviz WASM build are vendored and loaded when needed. The local board serves them, so charts and diagrams work offline without a CDN request at render time.

Detached mode, because agents have time limits

A single tool call may not be allowed to wait 30 minutes for someone to review a board. Detached mode lets the agent open it now and collect the response later:

rly ask --file board.json --detach   # returns immediately: {"status":"open","url":"…"}
rly wait b-xxxxx --timeout 3500       # blocks elsewhere until you submit
rly result b-xxxxx                    # non-blocking peek — includes the live draft

After opening the board, the agent can do other work or yield while you review it. Answers autosave as you enter them. Reloading the page restores your input, and a timeout or cancellation leaves the draft available in the result.

Put the visual beside the option

Any block can appear inside an option. A layout question, for example, can show a thumbnail under each label:

{ "id": "layout", "type": "single", "label": "Hero layout?",
  "options": [
    { "value": "split", "label": "Split", "blocks": [{ "type": "image", "src": "split.png", "height": 160 }] },
    { "value": "stack", "label": "Stacked", "blocks": [{ "type": "image", "src": "stack.png", "height": 160 }] }
  ] }

Only the label row selects an option. Zooming in or leaving a comment on its visual keeps the selection unchanged.

Attach comments to the work

I use comments most often. You can attach one to any board element, including a chart point, diagram node, table cell, or selected sentence in markdown. Relay returns each comment in result.annotations with metadata identifying the target:

{
  "blockId": "b2",
  "target": { "kind": "chart-element", "label": "Feb", "value": 19 },
  "text": "That Feb spike was a one-off onboarding push — don't extrapolate it."
}

The agent can reply in the same thread on the board, keeping the discussion beside the item under review.

JSON results and exit codes

Results are JSON on stdout, with logs on stderr. The exit codes distinguish 0 submitted, 2 timeout, 3 cancelled, 4 usage error, and 5 not found. Skipped questions are absent from answers and listed in skipped, so the caller can check what happened without parsing a written explanation.

What the board supports

Without relayWith relay
Six questions, one at a time in the terminalOne board, all of them, real controls
”Option B is the one with caching”Each option carries its own image or chart
ASCII architecture artMermaid / Graphviz / PlantUML with zoom, full-screen view, and editing
Numbers buried in proseCharts and sortable tables
”Type done when you’re finished”A Submit button; answers and comments returned as JSON
Feedback = another wall of textClick any point, node, cell, or sentence to comment

Try it

Relay is open source under MIT. It started life as quest-board and is now @khanglvm/relay (CLI: rly).

npm i -g @khanglvm/relay                  # the rly CLI
npx -y skills add khanglvm/relay -g -y    # the agent skill (Claude Code, Codex, Cursor, …)

The skill gives agents guidance on when to open a board. The code, full specification format, and demo are on GitHub.