Overview and Cheat Sheet

Leed Markdown is what a page is once it leaves the editor. It is the storage and interchange format: the text a published page is committed to your site repository as, the text an AI client reads and writes over MCP, and the text an import produces.

You do not type it. The Leed editor has no markdown input rules — typing ## in the body leaves two hash characters and a space sitting in your paragraph. Every feature on this page is produced by a toolbar control or a keyboard shortcut instead, and Editor Toolbar Reference lists them one by one.

The Leed page editor toolbar at full width, showing the block-type selector and the complete strip of formatting controls

So the readers who need this reference are the ones working with the format directly rather than through the editor: AI clients, importers, and template authors. Block, mark, attribute, fence and directive are the vocabulary the whole category is written in, and each is defined in the Glossary.

Because these documentation pages are themselves Leed pages, rendered by the same markdown-it instance your own site uses, every How it renders block below is live output rather than a picture of one.

Where this format comes from and where it goes

The working copy of a page is not markdown. While you edit, the body is a Yjs Y.Doc owned by the collab-provider Durable Object — that is what makes two people editing the same paragraph work. Markdown is generated from it, never stored as the live document.

Generation happens in two situations. When you publish, buildPageContent calls serializeBodyToMarkdown and writes ---, the JSON front matter, ---, and then the body, into your site repository. When an AI client calls get_page_markdown, the same serializer runs against the live document, so what the client reads is current to the keystroke.

Markdown also flows the other way. An MCP write is parsed by parseMarkdownToProseMirror and applied to the document; an import runs its converters and lands in the same place. Both directions are covered on Authoring Pages Over MCP.

flowchart LR
  YDOC["Live document<br/>Y.Doc in collab-provider"]
  SER["serializeBodyToMarkdown"]
  LM["Leed Markdown"]
  PUB["Publish to site repository"]
  MDIT["markdown-it, 26 plugins"]
  HTML["HTML on your site"]
  GPM["get_page_markdown"]
  CLIENT["MCP client"]
  FLAT["flattenMarkdown to /index.md"]
  DOCSMCP["Docs MCP and AI readers"]
  WRITE["MCP write<br/>parseMarkdownToProseMirror"]
  IMPORT["Import converters"]

  YDOC --> SER --> LM
  LM --> PUB --> MDIT --> HTML
  PUB --> FLAT --> DOCSMCP
  LM --> GPM --> CLIENT
  WRITE --> YDOC
  IMPORT --> YDOC

Publishing is the step that turns the right-hand side of that diagram into a live site; How Publishing Works traces what happens after the commit.

Three layers, one format

Three separate pieces of code read or write Leed Markdown, and they do not agree in every corner.

LayerWhat it isWhat it does
Site renderermarkdown-it with 26 plugins in total, about half of them Leed’s ownturns published markdown into the HTML your readers see
Editora ProseMirror schema with its own markdown-it parser and serializerturns markdown into editable blocks, and blocks back into markdown
Interchangethe import and export convertersturns external HTML and markdown into Leed Markdown, and Leed Markdown into plain CommonMark

One rule follows from that, and it is worth carrying into everything below: the site renderer is the more permissive of the two main layers. It accepts raw HTML, heading classes, table cell spans and inline-code attributes that the editor’s parser either rejects or silently drops. Markdown that renders perfectly on your site can still fail to import. Every place the layers disagree is collected on Fidelity and Unsupported Syntax.

Feature index

FeatureMarkerPage
Headings, emphasis, quotes, rules** * ~~ == ~x~ ^x^ [[…]]Basic Formatting
Classes, ids and other attributes{…}Attributes
Links and cross-page links[text](url), pageid:Links and Internal Links
Images, sizes and captions![alt](url "caption")Images and Figures
Bullets, numbers and checkboxes-, 1., - [ ]Lists and Task Lists
Tables, alignment and cell spanspipe-delimited rowsTables
Code and syntax highlightinga fenced block with a languageCode Blocks
LaTeX, rendered with KaTeXa math fence, or the double-backtick inline formMath
Mermaid diagramsa mermaid fenceDiagrams
Callouts:::note through :::dangerAlerts
Expandable sections+++ and ++>Collapsible Sections
Tabbed content===tabs-container and @tabTabs
Video, audio, iframes, forms, icons{% … %}Embeds and Icons
What a save changes, what is missing—Fidelity and Unsupported Syntax
Block anchors, page-type gates, exportsdata-idMarkdown for AI, MCP and Import

Text formatting

The right-hand column of this table is rendered live — it is the actual output of the syntax beside it.

You typeYou get
**bold**bold
*italic*italic
~~strikethrough~~strikethrough
==highlighted==highlighted
H~2~OH2O
E=mc^2^E=mc2
`inline code`inline code
[[Ctrl]] + [[C]]Ctrl + C
[text](https://example.com)text
[label](pageid:<pageId>)a link to another page on your site, like Basic Formatting
[label](pageid:<pageId>#section-slug)a link to a heading on another page, like heading anchors

Details, with the keyboard shortcut for each mark: Basic Formatting.

Structure

## Heading (anchored, and linkable by its generated id)

- Bullet list
- [ ] Task list item

1. Numbered list

> Blockquote

| Column | Column |
| ------ | ------ |
| data   | data   |

---

How it renders

Headings are left out of this live block so they do not join the page outline on the right.

  1. Numbered list

Blockquote

ColumnColumn
datadata

Details: Lists and Task Lists and Tables.

Attributes

Curly braces after an element attach an id, a class or an arbitrary HTML attribute to it.

## Heading {#custom-id .my-class}

[link](https://example.com){target="_blank"}

Attributes mostly have invisible effects, so there is no live example here. There is one thing to know before you write any: the accepted syntax differs by element. Headings, paragraphs, links, images, fences and alerts take the .class and #id shorthand; tables, lists, blockquotes and collapsible blocks do not, and silently discard it. Attributes gives the working form for each.

Images

![Alt text =600x400](/image.jpg "Optional caption")

Size with =WxH, giving either dimension or both. A quoted title turns the image into a <figure> with a <figcaption> — which is a visible design element, not free metadata, so write one only where it says something the surrounding prose does not. Details: Images and Figures.

Code blocks

```python
squares = [x * x for x in range(10)]

### How it renders {data-id="ij2axxe3"}

```python {data-id="yxiflbg1"}
squares = [x * x for x in range(10)]

Details, including how to add a language Leed does not ship: Code Blocks.

Math

```math
E = mc^2

### How it renders {data-id="bb3kgc2j"}

```math {data-id="w0q43zm0"}
E = mc^2

Inline math uses double backticks and a math prefix. Note that dollar-sign delimiters are not supported. Details: Math.

Diagrams

```mermaid
graph TD
    A[Start] --> B[Finish]

The produce-and-consume flowchart near the top of this page is a live one — click it to zoom. Every diagram type the bundled Mermaid supports, with a copy-pasteable example of each, is on [Diagrams](pageid:2b8f2a8c-ec69-443b-a05a-2ea8601c49b7). {data-id="b8ih0tze"}

## Alerts {data-id="4bgnhlr1"}

```markdown {data-id="2pfv7mbr"}
:::tip Custom title
Callout content here.
:::

How it renders

Five types: note, tip, info, warning, danger. Write the fence with no space after the colons — :::tip, not ::: tip — because the editor’s parser requires the tight form even though the site renderer forgives the loose one. Details: Alerts.

Collapsible sections

+++ Click to expand
Hidden content
+++

How it renders

Click to expand

Hidden content

Use ++> in place of +++ to start the block open. Details: Collapsible Sections.

Tabs

===tabs-container {data-tabs-groupId="cheat-sheet-demo"}

@tab First tab
Content for the first tab.

@tab Second tab
Content for the second tab.

===

How it renders

Content for the first tab.

Always give a container a data-tabs-groupId, and note the capital I — a lower-case groupid still renders but loses every tab’s configured title and icon. Details: Tabs.

Embeds and icons

{% youtube videoId="dQw4w9WgXcQ" %}
{% iframe src="https://example.com/embed" %}
{% audio path="/audio.mp3" controls %}
{% icon fa-brands fa-markdown %}

Video, audio, iframes, forms and Font Awesome icons. The other four need real media, so only the icon renders live here, inline in a sentence: . Details, with a full parameter table for each: Embeds and Icons.

What Leed Markdown does not have

Four things people reach for out of habit are absent, and each fails quietly rather than loudly.

  • Footnotes. [^1] is not a footnote. On the site it renders as a reference-link accident; in the editor it is escaped to literal text.
  • Definition lists. A term followed by a : line renders as an ordinary paragraph.
  • Dollar-sign math. Neither $…$ nor $$…$$ is a delimiter. Use the math fence or the double-backtick inline form.
  • Bare-URL autolinking. The site renderer has linkify switched off, so a URL typed into a paragraph stays text. Write the link.

Front matter is a fifth near-miss: it is JSON generated at publish time, not something you write into the body. The complete list, and what each one does instead, is on Fidelity and Unsupported Syntax.

Keeping this page and the AI guide in step

The same reference exists in three places. services/cms/.claude/leed-markdown-format.md is the canonical spec; LEED_MARKDOWN_GUIDE in the backend is generated from it by bun scripts/genMarkdownGuide.ts; and a byte-identical copy is installed onto your machine by the Leed CLI as part of the site-builder skill. That generated guide is what the editor’s AI assistant, the markdown field descriptions on the Operator MCP page tools, and describe_schema with target leed_markdown all serve.

The practical consequence: if you find an error on one of these pages, fixing the page alone is not enough — the spec has to be corrected and the guide regenerated, or an AI client will keep asserting something the published documentation denies. If you are emitting this format from a Handlebars template rather than from page content, the escaping rules are on Template Formatting Reference.

Which of these features a given page type will accept is a per-page-type setting rather than a plan question — What Each Page Type Lets You Format covers it.

ESC