Packages
An MDEx plugin supporting LMML (Language Model Markup Language) fenced blocks and file references with bundle-aware resolution and configurable HTML rendering.
Current section
Files
Jump to
Current section
Files
README.md
<img src="https://raw.githubusercontent.com/Oeditus/mdex_lmml/v0.1.0/priv/images/logo-128.png" alt="MDEx LMML Plugin" width="128" align="right">
# MDEx LMML
An [MDEx](https://hexdocs.pm/mdex) plugin providing first-class support for [LMML](https://hexdocs.pm/lmml) (Language Model Markup Language) fenced blocks, inline embeds, and file references.
<p align="center">
<a href="https://hex.pm/packages/mdex_lmml"><img src="https://img.shields.io/hexpm/v/mdex_lmml.svg" alt="Hex Version" /></a>
<a href="https://hexdocs.pm/mdex_lmml"><img src="https://img.shields.io/badge/hex-docs-blue.svg" alt="Hex Docs" /></a>
<a href="https://github.com/Oeditus/mdex_lmml/actions"><img src="https://github.com/Oeditus/mdex_lmml/workflows/CI/badge.svg" alt="CI Status" /></a>
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT" /></a>
</p>
---
## Overview
[LMML](https://hexdocs.pm/lmml) is a Markdown-superset markup language designed for LLM prompts and conversational narratives. It introduces file references (`@name.ext`) and named inline or external embeds (`@@@name.ext ... @@@`), stored as bare `.lmml` text narratives or packaged in `.lmmlz` zip archives.
**MDEx LMML** bridges LMML and [MDEx](https://hexdocs.pm/mdex), transforming LMML constructs in Markdown documents into rich, semantic, and highly configurable HTML output.
## Key Features
- **`lmml` Fenced Code Blocks**:
- ` ```lmml ... ``` ` blocks in Markdown are rendered as rich HTML narratives (or styled code blocks / conversation turn cards).
- **Inline Embed Blocks (`@@@name.ext ... @@@`)**:
- Block-level embed constructs are captured byte-for-byte and rendered into styled cards, collapsible `<details>`, or syntax-highlighted code blocks with language detection from file extensions.
- **File References (`@name.ext`)**:
- External file references in narrative prose (`@diagram.png`, `@config.yaml`) are transformed into links, spans, badges, or inline images.
- Automatically targets document anchors (`#embed-name`) when an inline embed with the matching name exists.
- Sentence punctuation (`.`, `,`, `!`, `?`, `)`) trailing the asset name is cleanly preserved as prose.
- Email addresses (e.g. `user@example.com`) and code spans (`` `@ref` ``) are safely ignored.
- **Bundle Integration (`Lmml.Bundle`)**:
- Seamlessly resolves asset entries from `.lmml` and `.lmmlz` archives.
- Directly renders referenced images in bundles as Base64 data URIs.
- **Conversation Turn Segmentation**:
- Automatically identifies role markers (`## Turn 1 -- user`, `<!-- assistant -->`) and renders distinct role cards when `render_turns: true` is enabled.
---
## Installation
Add `mdex_lmml` and `mdex` to your `mix.exs` dependencies:
```elixir
def deps do
[
{:mdex_lmml, "~> 0.1"},
{:mdex, "~> 0.13"},
{:lmml, "~> 0.2"}
]
end
```
---
## Usage
### 1. With `MDEx.to_html!/2`
```elixir
markdown = """
# Project Context
Please review @diagram.png before starting.
@@@settings.yaml
model: gpt-5
temperature: 0.2
@@@
"""
html = MDEx.to_html!(markdown, plugins: [MdexLmml])
```
### 2. With `MDEx.new/1` Pipeline
```elixir
MDEx.new(markdown: markdown, plugins: [{MdexLmml, render_as: :span}])
|> MDEx.to_html!()
```
### 3. Fenced ` ```lmml … ``` ` Blocks in Markdown
```elixir
markdown = """
Here is the interaction transcript:
```lmml
## Turn 1 -- user
Can you optimize @query.sql?
@@@settings.yaml
timeout: 5000
@@@
```
"""
html = MdexLmml.to_html!(markdown)
```
### 4. Working with `Lmml.Bundle` (.lmml / .lmmlz)
```elixir
# From an in-memory Lmml.Bundle struct:
{:ok, bundle} = Lmml.Bundle.new_zip("convo.lmml", "See @chart.png", %{"chart.png" => image_bytes})
html = MdexLmml.to_html!(bundle, render_as: :embed)
# Or directly from a file path:
html = MdexLmml.to_html!("session.lmmlz")
```
---
## Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
| `:render_reference` (alias `:render_as`) | `:link` \| `:span` \| `:badge` \| `:embed` \| `function/2` | `:link` | How `@name.ext` references in prose are rendered. `:embed` inlines `<img>` tags for images. |
| `:render_embed` | `:container` \| `:card` \| `:details` \| `:code` \| `:raw` \| `function/3` | `:container` | How `@@@name.ext ... @@@` blocks are rendered. `:details` creates collapsible accordions. |
| `:fenced_block_mode` | `:render` \| `:code` \| `:turns` | `:render` | How ` ```lmml ` code blocks are handled. `:render` parses and renders the inner LMML narrative. |
| `:render_turns` | `boolean` | `false` | Whether to transform turn headers (`## Turn N -- <role>`) and comments (`<!-- <role> -->`) into turn cards. |
| `:url_prefix` | `String.t() \| nil` | `nil` | Base URL prepended to external reference link `href` attributes (e.g. `"/assets"`). |
| `:anchor_embeds` | `boolean` | `true` | When true, references matching inline embeds in the same document link to `#embed-<name>`. |
| `:bundle` | `Lmml.Bundle.t() \| nil` | `nil` | An `Lmml.Bundle` instance to resolve entries against. |
| `:classes` | `keyword() \| map()` | `[]` | Custom CSS class overrides (`:ref`, `:embed`, `:block`, `:turn`, `:image`, `:badge`). |
---
## Testing
Run the test suite:
```sh
mix test
```
Run code formatting and quality checks:
```sh
mix format --check-formatted
mix credo --strict
```
---
## License
MIT License. Copyright (c) 2026 Oeditus.