[HN Gopher] I turned Markdown into a protocol for generative UI
       ___________________________________________________________________
        
       I turned Markdown into a protocol for generative UI
        
       There's a lot of work happening around both generative UI and code
       execution for AI agents. I kept wondering: how do you bring them
       together into a fully featured architecture? I built a prototype:
       - 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!
        
       Author : FabianCarbonara
       Score  : 64 points
       Date   : 2026-03-19 13:42 UTC (9 hours ago)
        
 (HTM) web link (fabian-kuebler.com)
 (TXT) w3m dump (fabian-kuebler.com)
        
       | eightysixfour wrote:
       | There seems to be a lot of movement in this direction, how do you
       | feel about Markdown UI?
       | 
       | https://markdown-ui.com/
        
         | threatofrain wrote:
         | I'd much prefer MDX.
        
         | FabianCarbonara wrote:
         | Markdown UI and my approach share the "markdown as the medium"
         | insight, but they're fundamentally different bets:
         | 
         | 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.
        
       | zeroq wrote:
       | If you're still looking for a name let me suggest "hyper text".
       | 
       | 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.
        
         | altruios wrote:
         | Every turn of the wheel someone wants to make a new one.
         | 
         | Maybe one day someone will invent a rounder wheel.
        
           | doublerabbit wrote:
           | Personally I think we should move to heptagons, they're round
           | enough.
           | 
           | The wheel is what I would call, passe.
        
             | altruios wrote:
             | Every day the wheel of society turns a little further off
             | course.
             | 
             | Soon we'll be optimizing for minimizing the sides of a
             | wheel (triangles are not the final form here...) /s
        
         | FabianCarbonara wrote:
         | Ha, history does rhyme ;) Happy if you reach out via mail!
        
           | heckintime wrote:
           | I think he's talking about CSS
        
         | noman-land wrote:
         | If HTML happened again except this time it was markdown, maybe
         | more non-nerds would be able to use it? XML just looks gnarly.
        
       | iusethemouse wrote:
       | There's definitely a lot of merit to this idea, and the gifs in
       | the article look impressive. My strong opinion is that there's a
       | lot more to (good) UIs than what an LLM will ever be able to
       | bring (happy to be proven wrong in a few years...), but for
       | utilitarian and on-the-fly UIs there's definitely a lot of
       | promise
        
       | theturtletalks wrote:
       | OpenUI and JSON-render are some other players in this space.
       | 
       | 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 wrote:
         | In my approach, callbacks are first-class. The agent defines
         | server-side functions and passes them to the UI:
         | 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.
        
       | wangmander wrote:
       | Using markdown as the transport layer is clever because every LLM
       | already speaks it fluently. You're not teaching the model a new
       | format, you're just giving existing behavior a runtime.
        
         | Retr0id wrote:
         | What's the going rate these days for decade-old HN accounts to
         | repurpose as AI spambots?
        
           | pohl wrote:
           | I don't know, but feel free to send me an offer.
        
       | tantalor wrote:
       | The nice thing about standards is that you have so many to choose
       | from
        
       | joelres wrote:
       | I quite like this! I've been incrementally building similar
       | tooling for a project I've been working on, and I really
       | appreciate the ideas here.
       | 
       | 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!
        
         | FabianCarbonara wrote:
         | Thanks! Really interesting to hear you're working on something
         | similar.
         | 
         | You're right that the level of expressiveness is the key design
         | decision. There's a real spectrum:
         | 
         | - pre-registered blocks (safe, predictable)
         | 
         | - code execution with a component library (middle ground)
         | 
         | - full arbitrary code (maximum flexibility).
         | 
         | My approach can slide along that spectrum: you could constrain
         | the agent to only use a specific set of pre-imported components
         | rather than writing arbitrary JSX. The mount() primitive and
         | data flow patterns still work the same way, you just limit what
         | the LLM is allowed to render.
         | 
         | Would love to hear what you learn if you explore it!
        
           | joelres wrote:
           | Will do! I'm using a JSON DSL currently, I wonder if there's
           | a best choice for format that is both at the correct level of
           | expressiveness and also easy enough for the LLM to generate
           | in a valid way. I do think markdown has advantage of being
           | very trivial for LLMs, but my current JSON blocks strategy
           | might be better for more complex data.... will play around.
        
       | smahs wrote:
       | In an agentic loop, the model can keep calling multiple tools for
       | each specialized artifact (like how claude webapp renders
       | HTML/SVG artifacts within a single turn). Models are already
       | trained for this (tested this approach with qwen 3.5 27B and it
       | was able to follow claude's lead from the previous turns).
        
       | 4ndrewl wrote:
       | The bots that read the instruction and yet add the emoji to the
       | _beginning_ of the PR title though. Even bigger red flag I guess?
        
       | pbkhrv wrote:
       | Very cool. I'm imagining using this with Claude Code, allowing it
       | to wire this up to MCP or to CLI commands somehow and using that
       | whole system as an interactive dashboard for administering a
       | kubernetes cluster or something like that - and the hypothetical
       | first feature request is to be able to "freeze" one of these UI
       | snippets and save it as some sort of a "view" that I can access
       | later. Use case: it happens to build a particularly convenient
       | way to do a bunch of calls to kubectl, parse results and present
       | them in some interactive way - and I'd like to reuse that same
       | widget later without explaining/iterating on it again.
        
         | FabianCarbonara wrote:
         | Exactly this!
         | 
         | Right now this uses React for Web but could also see it in the
         | terminal via Ink.
         | 
         | And I love the "freeze" idea -- maybe then you could even share
         | the mini app.
        
       | dominotw wrote:
       | would be nice if it wasnt just ui but other form like voice
       | narration, sounds ect
        
       | Lws803 wrote:
       | I see potential to take over Notion's / Obsidian's business here.
       | Imagine highly customizable notebooks people can generate on the
       | fly with the right kind of UI they need. Compared to fixed blocks
       | in Notion
        
         | rthrfrd wrote:
         | That's what I'm building, along with the invisible unified data
         | model underneath, that is needed to tie everything together.
         | Always glad for feedback, reach out in my profile if it sounds
         | interesting!
        
       | realrocker wrote:
       | The streamed execution idea is novel to me. Not sure what's it
       | significance ?
       | 
       | I have been working on something with a similar goal:
       | 
       | https://github.com/livetemplate/tinkerdown
        
         | kristopolous wrote:
         | Add a video or a live demo, there's still too much friction on
         | this readme.
         | 
         | Always Show then Ask.
        
         | FabianCarbonara wrote:
         | and I meant to say: tinkerdown looks pretty cool!
        
       | z3ugma wrote:
       | I will say I came upon this same design pattern to make all my
       | chats into semantic Markdown that is backward compatible with
       | markdown. I did:
       | 
       | ````assistant
       | 
       | <Short Summary title>
       | 
       | gemini/3.1-pro - 20260319T050611Z
       | 
       | Response from the assistant
       | 
       | ````
       | 
       | with a similar block for tool calling This can be parsed
       | semantically as part of the conversation but also is rendered as
       | regular Markdown code block when needed
       | 
       | Helps me keep AI chats on the filesystem, as a valid document,
       | but also add some more semantic meaning atop of Markdown
        
       | nthypes wrote:
       | Why not MDX?
        
       | AiStockAgent62 wrote:
       | counterpoint: this assumes everyone has the same constraints. not
       | always true
        
       ___________________________________________________________________
       (page generated 2026-03-19 23:01 UTC)