Lmml

Lmml

CIHex.pmDocumentationLicense

lmml is a pure-Elixir markup language for talking to LLMs, designed as a strict superset of Markdown: any bare .md/text file already parses and means something sensible as an lmml narrative.

A narrative can be stored in one of two forms:

Both forms express the same underlying model -- an ordered narrative with zero or more named embeds -- differing only in whether each embed's content is carried inline (@@@name ... @@@) or externally (@name, resolved against the zip). See docs/LANGUAGE_REFERENCE.md for the full syntax and semantics.

Syntax at a glance

# Project context
Please review @diagram.png before the meeting.
@@@settings.yaml
model: gpt-5
temperature: 0.2
@@@

@diagram.png is an external reference (resolved from a .lmmlz archive's entries); @@@settings.yaml ... @@@ is an inline embed (carried directly in the text). Everything else is ordinary Markdown.

Installation

Add lmml to your list of dependencies in mix.exs:

def deps do
[
{:lmml, "~> 0.1.0"}
]
end

Usage

{:ok, bundle} = Lmml.Bundle.open("convo.lmmlz")
{:ok, resolved} = Lmml.Narrative.Resolver.resolve(bundle)
content_parts = Lmml.Narrative.Renderer.render(resolved)

content_parts is a list of %{"type" => ...} maps ready to hand to a multimodal chat completion API's content field ("text", "image_url", or "attachment" parts) -- see Lmml.Narrative.Renderer.

To build a bundle programmatically:

{:ok, bundle} = Lmml.Bundle.new_zip("convo", "See @a.png.", %{"a.png" => image_bytes})
:ok = Lmml.Bundle.write!(bundle, "convo.lmmlz")

See the examples/ directory in the repository for two complete worked examples: a settings-only bare .lmml narrative, and a multi-turn conversation with an embedded image packed as .lmmlz, resolved and rendered end to end.

Mix tasks

Documentation

Full API and syntax documentation can be generated locally with ExDoc:

mix docs

See docs/LANGUAGE_REFERENCE.md for the complete language reference, including several non-obvious findings about the underlying Md parser library that shaped the design (magnet vs. block category ordering, an HTML-entity-escaping quirk in fenced blocks, and Erlang's own zip path-traversal handling).

Status and possible future directions

Phases 0 through 6 of the implementation plan are complete: the narrative parser, the core Embed/Document/Bundle data model, an optional manifest.json convention, bundle-level validation, an LLM payload resolver/renderer, lossless .lmml <-> .lmmlz packing, and a handful of mix lmml.* CLI tasks.

As a stretch idea (not implemented, and out of this project's own scope): a tool like dsh's Brain.SessionStore could optionally persist and load its conversation sessions as .lmml/.lmmlz bundles instead of (or alongside) its own session format, using Lmml.Narrative.Resolver/Renderer directly to build the multimodal message payloads it already sends to an LLM API.