Hacker News
I turned Markdown into a protocol for generative UI
- Markdown as protocol — one stream carrying text, executable code, and data
- Streaming execution — code fences execute statement by statement as they stream in
- A mount() primitive — the agent creates React UIs with full data flow between client, server, and LLM
Let me know what you think!
joelres
|next
[-]
I think the key decision for someone implementing a flexible UI system like this is the required level of expressiveness. To me, the chief problem with having agents build custom html pages (as another comment suggested) is far too unconstrained. I've been working with a system of pre-registered blocks and callbacks that are very constrained. I quite like this as a middleground, though it may still be too dynamic for my use case. Will explore a bit more!
zeroq
|next
|previous
[-]
It embodies the whole idea of having data, code and presentation at the same place.
If you're open for contributions I already have an idea for cascading styles system in mind.
noman-land
|root
|parent
|next
[-]
theturtletalks
|next
|previous
[-]
I’m building an agentic commerce chat that uses MCP-UI and want to start using these new implementations instead of MCP-UI but can’t wrap my head around how button on click and actions work? MCP-UI allows onClick events to work since you’re “hard coding” the UI from the get-go vs relying on AI generating undertemistic JSON and turning that into UI that might be different on every use.
FabianCarbonara
|root
|parent
[-]
const onRefresh = async () => {
data.loading = true;
data.messages = await loadMessages();
data.loading = false;
};
mount({
data,
callbacks: { onRefresh },
ui: ({ data, callbacks }) => (
<Button onClick={callbacks.onRefresh}>Refresh</Button>
)
});
When the user clicks the button, it invokes the server-side function. The callback fetches fresh data, updates state via reactive proxies, and the UI reflects it — all without triggering a new LLM turn.So the UI is generated dynamically by the LLM, but the interactions are real server-side code, not just display. Forms work the same way — "await form.result" pauses execution until the user submits.
The article has a full walkthrough of the four data flow patterns (forms, live updates, streaming data, callbacks) with demos.
iusethemouse
|next
|previous
[-]
eightysixfour
|next
|previous
[-]
FabianCarbonara
|root
|parent
|next
[-]
Markdown UI is declarative — you embed predefined widget types in markdown. The LLM picks from a catalog. It's clean and safe, but limited to what the catalog supports.
My approach is code-based — the LLM writes executable TypeScript in markdown code fences, which runs on the server and can render any React UI. It also has server-side state, so the UI can do forms, callbacks, and streaming data — not just display widgets.