edn-renderer is the browser frontend for the edn-relay workflow.
It keeps a websocket connection to the relay, subscribes to a chosen channel
such as genui, stores the incoming Cirru EDN layout DSL, renders the layout,
and sends an ack back to the CLI.
The sidebar is collapsed by default so more horizontal space is reserved for the rendered result.
The current implementation already supports the full loop:
- start
edn-relay serve - open
edn-rendererin a browser - run
edn-relay send --channel genui <LAYOUT>from the CLI - render the DSL in the page
- confirm success with a returned ack payload and layout id
It also supports inspection and local mutation of the currently rendered layout through relay requests, so a CLI agent can read a summarized tree, fetch one node's full DSL, and patch or replace that node without resending the whole page.
Reference screenshot:
corepack enable && corepack prepare yarn@4.12.0 --activate
yarn install
cr js
yarn vite --host 127.0.0.1 --port 3010Published bootstrap page:
https://r.tiye.me/Erigeron/edn-renderer/- supports
?channel=<NAME>to preselect a channel - supports
?server=<WS_URL>or?port=<PORT>to override the relay websocket target
If Vite fails because rolldown native bindings are missing, run yarn install
again so the unplugged package is materialized on disk.
Start the frontend dev server:
yarn vite --host 127.0.0.1 --port 3010Open the page in a browser. In parallel, run the relay:
edn-relay serveIf you want the published bootstrap page instead of a local dev server, run:
edn-relay open-published --channel genuiThen send a layout DSL from the CLI:
LAYOUT=$(cat <<'EOF'
{}
:type |card
:text "|CLI Demo"
:children $ []
{} (:type |badge) (:text |preview)
{} (:type |divider)
{} (:type |text) (:text "|Hello from installed CLI")
{} (:type |row)
:children $ []
{} (:type |button) (:text |Confirm)
{} (:type |input) (:name |email) (:placeholder |Email)
EOF
)
edn-relay send --channel genui "$LAYOUT"Expected result:
- CLI prints an
ackframe whose payload contains:status |okand:layout_id - the page shows the layout id and request id
- the renderer preview updates immediately
When a meaningful layout is already loaded in the page, the top bar exposes 2 extra actions:
Save: asks relay to persist the current report under~/.config/ed-relay/<channel>/Library: opens the saved report list for the current channel and lets you load one entry back into the preview
The browser does not write local files directly. Instead it sends a generic
relay request to the reserved internal channel __relay_store__, and relay
stores opaque Cirru EDN files on disk.
Validated flow:
- send a layout into
genui - click
Save - confirm a new
.cirrufile appears under~/.config/ed-relay/genui/ - click
Library - click a saved report entry
- confirm the preview loads the saved layout back into the page
Once a layout is already loaded in the page, you can inspect and edit it with small relay payloads.
Get a token-efficient layout summary tree:
edn-relay send --channel genui '
{}
:op :layout
'Inspect one node by 1-based path such as 2.1:
edn-relay send --channel genui '
{}
:op :node
:path |2.1
'Patch one node in place by merging a subset of fields:
edn-relay send --channel genui '
{}
:op :patch
:path |1
:changes $ {}
:text |Updated
'Replace one node's DSL completely:
edn-relay send --channel genui '
{}
:op :replace
:path |2.1
:node $ {}
:type |text
:text |Replaced
'Path rules:
rootmeans the whole layout1,2,3address root children with 1-based indices2.1means the first child under the second root childlayoutreturns summaries, whilenodereturns the full DSL for that path
Current built-in nodes:
columnrowcardtextbadgedividermarkdownmermaidchartbuttoninput
Detailed DSL rules and examples live in COMPONENTS.md.
Current analysis-oriented rendering behavior:
markdownrenders headings, bullets, quotes, and wrapped paragraphsmermaidrenders a Mermaid SVG diagram from the provided source textchartrenders a compact horizontal bar chart from:series
Compile the Calcit app with:
cr jsFor a dedicated renderer, CLI, and browser validation checklist, see TESTING.md.
For isolated browser validation, use the chrome-devtools workflow described in
Agents.md.
MIT