MDMA: Markdown that mountsreal applications.
MDMA extends Markdown with interactive components defined in fenced ```mdma blocks. Give an LLM the spec and it returns structured, validated, renderable UI (forms, tables, approval gates) instead of a wall of text. Renders in React, Vue and React Native — and holds up on models small enough to run on open weights.
Parse → validate → run → render
Four small packages take a markdown file the whole way to a live, stateful interface. Use the ones you need.
Remark plugin: Markdown → MDMA AST.
Static analysis, 17 lint rules, auto-fix.
State, bindings, audit log, policies.
React components for every block type.
- Vue renderer — Vue 3 renderer, same API surface as React.
- Native renderer — The same documents as native iOS / Android UI.
- AG-UI bridge — Stream MDMA over AG-UI, route actions back.
- Prompt pack — Author, fixer and agent prompts per model.
- Attachables — Handlers for the stateful component types.
- Spec — Zod schemas and types for every component.
- CLI — mdma create (prompt builder) and mdma validate.
- MCP server — Serves the spec, prompts and docs to an LLM.
Every version, and what changed in it, is on the changelog.
Ten component types
MDMA defines ten interactive component types: form, button, tasklist, table, callout, approval-gate, webhook, chart, thinking, and custom. Each is a schema in the spec. Write its short YAML in an ```mdma block and the renderer for your framework turns it into a live, stateful element.
Typed fields, validation, sensitive flags.
Actions with optional confirm dialogs.
Checklists with required items + onComplete.
Sortable columns over structured rows.
Info / warning / error notices.
Role-based sign-off before proceeding.
Fire an outbound call on an event.
Line / bar visualisations from inline data.
Render the model's reasoning trace.
Your own component, registered by the host.
The tenth type is the escape hatch. A model cannot invent type: timer, but it can emit type: custom with name: timer once your host registers that variant — so your own components stay authorable by an LLM without ever changing the spec.
One document, three renderers
Parsing, state, bindings, policy and audit are headless — they live in the spec and runtime packages and never touch a view. So the same MDMA document renders in React, Vue 3 or React Native, and a theme object written for one works in the others.
React
The reference renderer. All ten component types, element overrides, custom variants and theming.
Vue 3
Same public API, ported to provide/inject and composables. Ships the same styles.css, so a theme is portable.
React Native
Native iOS and Android UI from the same document. Shares the MdmaTheme token shape with the web renderers.
Pass theme="light", "dark", "auto" to follow the OS preference, or a full token object. The web stylesheet is driven by --mdma-* variables, so you can also override it in your own CSS. Button hover and focus rings derive from your palette instead of the built-in purple.
Blocks render as they stream, and a half-written fence shows a skeleton rather than an error. mdma-agui carries documents over the AG-UI protocol and routes submits, approvals, completed checklists and webhook triggers back into the agent run — including interrupts, so a run can pause on an approval gate and resume from the answer.
Edit the markdown. Watch it render.
This is the real @mobile-reality/mdma-renderer-react running in your browser. Change the source on the left.
Talk to the MDMA Agent
Describe a component for your own use case: a contact form, a sortable table, an onboarding checklist, an approval gate. The agent renders it live in the panel on the right. Verify your email to start.
Same prompt. Different contract.
Ask an LLM to collect contact details. Without a spec you get prose you have to parse by hand. With MDMA you get a block you can render and validate.
Sure! To contact us, please provide the following information: 1. Your full name 2. Your email address 3. A message (at least a few sentences) Once you've gathered those, you can send them over and someone from the team will reply. Let me know if you'd like me to format this as a list or a table instead!
# Contact us
Fill in the form below and we'll get back to you.
```mdma
id: contact-form
type: form
fields:
- name: full_name
type: text
label: Full Name
required: true
- name: email
type: email
label: Email Address
required: true
- name: message
type: textarea
label: Message
required: true
validation:
min: 10
message: Please enter at least 10 characters.
onSubmit: submit-contact
```
```mdma
id: send-btn
type: button
text: Send Message
variant: primary
onAction: submit-contact
```It has to work on the cheap model too
Everything works on a flagship. The question is what happens on the small, open-weights model you actually want in production. We ran four open-source generative-UI formats — each from its own published prompt, each scored by its own validator, auto-repair off for everyone including MDMA — and published every raw generation.
Rendered every single time
share of scenarios where all 5 repeats rendered
| Format | Opus 5 | Gemma-4-26B | Drop |
|---|---|---|---|
| MDMA | 94.4% | 94.4% | 0.0pp |
| OpenUI Lang | 83.3% | 55.6% | 27.8pp |
| json-render | 83.3% | 38.9% | 44.4pp |
| A2UI (AGenUI) | 38.9%* | 77.8% | N/A |
* A2UI's flagship figure is depressed by verbosity, not unreliability — 52% of its Opus 5 generations ran past the 8k output ceiling, so no drop can be read from that row. The report also discloses where A2UI's own validator disagrees with the harness.
The prompt is part of the bill
You pay for the system prompt on every single request, before the model writes a token.
- OpenUI Lang5,172
- MDMA5,910
- json-render8,466
- A2UI (AGenUI)19,689
How it was kept fair
- Each format used its own published system prompt, unmodified.
- Each format was scored by its own validator, not ours.
- Auto-repair was switched off for every format — including MDMA's.
- Byte-identical user message, no format hints, 5 repeats per scenario at temperature 0.7.
- Every raw generation is committed, so you can re-score it yourself.
1107 generations · 0 API errors · 18 scenarios × 5 repeats × 3 model tiers, all through OpenRouter.
Built for the token bill
MDMA cuts token cost because it runs on small, cheap models. Strict JSON breaks on those models (one bad quote and the whole payload is unusable), so teams reach for the largest tier. MDMA uses forgiving Markdown that small models like Gemini Flash and Claude Haiku emit reliably, backed by a deterministic validator and an LLM fixer. See it live in the MDMA Agent demo.
Runs on small, cheap models
Markdown is forgiving where strict JSON is brittle. A small model that mangles a JSON quote sends the whole payload to the bin; the same model emits valid MDMA. That means fast, low-cost models like Gemini Flash and Claude Haiku, instead of always reaching for the largest tier.
Deterministic validator, free
MDMA ships a static validator — 17 lint rules and 6 auto-fix strategies — that runs without an LLM. Catching structural problems costs nothing per call, so you don't burn tokens re-asking the model to fix its own output.
LLM fixer for the rest
What the validator can't auto-fix goes to a fixer that repairs broken documents, and it works on the same small models, keeping the whole loop cheap.
What we eval
157 test cases · 11 suites · 36 tuned prompt variants
| Suite | Tests | What it asserts |
|---|---|---|
| Author | 33 | Correct component, exact field count, PII flags |
| Conversation | 30 | No regeneration on follow-up turns |
| Conversation flow | 6 | LLM-judged conversation quality |
| Custom prompt | 13 | Author + custom system prompt layering |
| Flows | 15 | Example flow custom prompts |
| Guidance | 15 | Calls the generate_mdma tool correctly |
| Guidance multiturn | 10 | Tool guidance held across turns |
| Guidance coexistence | 8 | MDMA alongside your own tools |
| Fixer | 16 | Repairs broken MDMA to valid output |
| Prompt builder | 10 | CLI prompt builder output |
| Isolated | 1 | Single failure-case iteration |
- OpenAI GPT-5.x / 4.1 (incl. mini, nano)
- Claude Opus / Sonnet / Haiku / Fable
- Gemini 3.x / 2.5 (incl. Flash, Flash-Lite)
- Google Gemma (open weights)
- xAI Grok 4.x
- Our own fine-tuned MDMA-IL model
The eval suites run across all of these models; the same suites pass on the small, cheap tiers, not only the large ones. Each model gets its own tuned author and fixer prompt — 36 variants across five vendors. Run them yourself with the PromptFoo configs in mdma/evals, or see how the format holds up against other generative-UI formats in the cross-format benchmark.
Far enough that we fine-tuned our own and published the weights. A 27B Gemma 4 fine-tune, served quantized, passes all 95 held-out cases in its gate. A model that size cannot hold a strict JSON UI contract together; it can emit MDMA. Read about the model.
Real use cases, shipped in the repo
Every example below is a working MDMA document in the open-source project, from a one-field form to a dual-approval compliance flow, built from the ten component types.
Examples
common use casesContact form
Collect a name, email and message, then submit. The simplest MDMA document.
Budget approval
Submit a budget request, complete prerequisites, and gate it behind manager sign-off.
Employee onboarding
Welcome a new hire through personal info, equipment selection and a manager checklist.
Bug report
Capture reproduction steps and severity, with a triage checklist before submission.
Customer survey
Structured post-support feedback with ratings, checkboxes and optional follow-up.
Order tracking
Order status, shipment details and delivery milestones at a glance.
Sprint retrospective
Team metrics, feedback and action items captured from the sprint retro.
Sales dashboard
Quarterly revenue trends, team breakdown and a sortable deals table.
Feature request
A product request with business justification and a product-manager review gate.
Job application
Apply with a resume and optional portfolio. Shows the file-upload field.
Open the live demo and pick any example flow to run.
Blueprints
industry-specific workflowsIncident triage
Critical OpsAssess severity, notify stakeholders, track resolution and gate closure behind sign-off.
Change management
Engineering / ComplianceSOX/ISO release approval: risk assessment, dual approval and a pre-deploy checklist.
Customer escalation
Customer OpsSLA-aware escalation with sentiment tracking and a dynamic escalation-history table.
Clinical procedure approval
HealthcareClinical + QA review and safety verification before a procedure is published.
KYC case review
Finance / ComplianceIdentity verification for KYC/AML: PII handling, document table and compliance approval.
Open the live demo and pick a blueprint flow to run.
Where MDMA fits
Between raw markdown and a hand-built JSON UI contract.
| Raw MD | Custom JSON | MDMA | |
|---|---|---|---|
| Renders as interactive UI | |||
| Readable as plain text | |||
| Schema-validated | partial | ||
| LLM emits it reliably | partial | ||
| Stateful (bindings, audit) | |||
| No front-end build needed |
Three ways in
Install the core once, then add the renderer for whatever you build in.
Developers
Parse and run MDMA documents, then render them with React, Vue or React Native.
AI authoring
Give an LLM the prompt pack — it carries a tuned variant per model — or build prompts with the CLI.
Agents
Stream documents over the AG-UI protocol and route submits, approvals and webhook triggers back into the run.
Frequently asked questions
- What is MDMA?
- MDMA (Markdown Documents with Mounted Applications) extends Markdown with interactive components defined in fenced mdma code blocks. A regular Markdown file becomes an interactive application with forms, tables, charts, approval gates and more.
- How is MDMA different from raw markdown or a JSON UI contract?
- Raw Markdown renders as text and a custom JSON UI contract is brittle on smaller models. MDMA is forgiving Markdown that small, cheap models emit reliably, and it is schema-validated so the output is renderable and safe. In a cross-format benchmark, MDMA rendered every time in 94.4% of scenarios on both a flagship model and an open-weights one, a 0.0pp drop between the two tiers.
- Why does MDMA save on tokens?
- Because MDMA works on small, cheap models such as Gemini Flash and Claude Haiku where strict JSON often breaks. A deterministic validator with 17 lint rules and 6 auto-fix strategies, plus an LLM fixer, keeps the loop cheap — so you don't burn tokens re-asking a large model to repair its own output.
- Which components can MDMA render?
- Ten types: form, button, tasklist, table, callout, approval-gate, webhook, chart, thinking, and custom. The custom type is a stable envelope your host fills in with its own components, so you can extend the catalog without changing the spec — and an LLM can still author them, because it emits type: custom with a registered name rather than inventing a new type.
- Which frameworks can render MDMA?
- React, Vue 3 and React Native, via @mobile-reality/mdma-renderer-react, @mobile-reality/mdma-renderer-vue and @mobile-reality/mdma-renderer-react-native. Parsing, state, bindings, policy and audit are headless, so all three share the same core and the same MdmaTheme token shape.
- Which packages does MDMA ship?
- Twelve packages under @mobile-reality/mdma-*: the spec, parser, validator, runtime and attachables-core, three renderers (React, Vue, React Native), an AG-UI bridge, a prompt-pack, a CLI and an MCP server.
- Can I use MDMA with an agent framework?
- Yes. @mobile-reality/mdma-agui bridges MDMA and the AG-UI protocol: documents stream in over inline text or a dedicated custom event, user actions (submit, approve, deny, completed checklists, webhook triggers) route back into the agent run, and interrupts let a run pause on an approval gate and resume from the answer.
- Is there a model fine-tuned for MDMA?
- Yes. MobileReality/mdma-gemma4-26b-dsl-unsloth-v1 is a 27B Gemma 4 fine-tune, published on Hugging Face under Apache 2.0, that reads a compact MDMA-IL DSL intent and returns a valid MDMA document. The LoRA is merged into the base weights, and the model passes all 95 cases in its held-out gate plus the standard author, flows, fixer, guidance and custom-prompt suites.
- Is MDMA open source?
- Yes. MDMA is MIT-licensed and maintained by Mobile Reality. The source is on GitHub at github.com/MobileReality/mdma.
- Does MDMA work with Claude, GPT and Gemini?
- Yes. MDMA is model-agnostic: any LLM that can write Markdown can emit MDMA. The prompt-pack ships 36 tuned author-prompt variants across OpenAI, Anthropic, Google, xAI and our own fine-tuned model, so the format works on small, cheap tiers rather than only the largest ones. An MCP server serves the spec, prompts and docs straight to an LLM.
- How do I render MDMA in React?
- Install @mobile-reality/mdma-renderer-react along with the parser and runtime, parse the markdown to an AST, create a document store, and pass them to the MdmaDocument component. It renders every component type as a live, stateful element. Add a theme prop for light, dark, auto or your own tokens.