Skip to main content
This page is the complete specification. AI agents connected through the Disco MCP Connector receive the same document as the resource disco://docs/disco-xml-spec, so an agent and a person always work from one specification. Disco XML is the format the Disco API and MCP Connector use for rich content: lesson bodies, descriptions, and any other field authored in the Disco editor. When you read content you receive Disco XML. When you create or update content you send Disco XML. The format is a small, strict XML vocabulary. It is deliberately close to HTML for ordinary prose, with Disco-specific elements only where HTML has no name for something. Three things to know before anything else:
  1. It is strict. Anything not in this document is rejected with an error that says where the problem is and, where possible, what you probably meant. Nothing is silently dropped or guessed.
  2. It round-trips. Any content you can create in the Disco editor can be read as Disco XML and written back without loss.
  3. Output is deterministic. Reading the same content always produces the same text, so you can diff it and make find-and-replace edits safely.

Document structure

Every document is one disco_doc element. You may start the document with an XML declaration or a bare <!DOCTYPE disco_doc>; both are ignored, and Disco never writes them. A DOCTYPE that declares entities or points at an external DTD is rejected, as is any processing instruction. Comments are ignored. Content is a sequence of blocks. Most blocks hold rich text: ordinary text plus inline elements such as line breaks. Some blocks hold other blocks instead. No block holds both, so <p><p>x</p></p> is an error, and an inline element never appears directly under the root or inside a block that holds blocks. Every element belongs to one category, which fixes where it may appear and what it may contain:

disco_doc

The root of every document. Contains blocks. No attributes.
  • An empty document is <disco_doc><p/></disco_doc>. <disco_doc/> means the same thing.

Naming

  • Element names are lowercase and case-sensitive. HTML names are used where HTML has the same concept and Disco-specific names where it does not.
  • Attribute names are snake_case. Values of enumerated attributes are lowercase.
  • There are no aliases. Each element and attribute has exactly one spelling. Familiar alternatives such as paragraph are rejected, and the error names the Disco XML spelling to use instead.
  • HTML styling attributes are never accepted. style, class, id, and data-* are rejected on every element. Presentation comes only from the elements and attributes in this document.

Whitespace

In this section, whitespace means spaces, tabs, and newlines. Other Unicode spaces, such as a non-breaking space, are ordinary text. Between blocks, whitespace is ignored. Indent your document however you like. Disco indents two spaces per level when it produces XML. Inside a block, text is preserved exactly as written, with two exceptions that let you wrap long paragraphs across lines in your source:
  1. A run of whitespace that contains a newline is collapsed to a single space.
  2. Such a run is removed instead at the very start or very end of a block and on either side of a <br/>, so tags can sit on their own lines.
So this source:
is the same content as <p>A long paragraph can be wrapped across lines.<br/>Second line.</p>, which is how Disco writes it back. Everything else is significant: a single space and a double space between two words are different content. Disco writes each block’s text on a single line. A line break inside a block is <br/>; a newline in your source never becomes one. A tab is <tab/>. A literal tab character is kept as a tab unless it sits in a whitespace run that contains a newline, where it collapses with the run, so write <tab/> for a tab you mean as content.

Escaping

Only these need escaping: Everything else, including >, /, quotes in text, backticks, and braces, is written as is. Numeric character references such as &#9; are accepted. The only named entities are XML’s own five, &lt;, &gt;, &amp;, &quot;, and &apos;, so &nbsp; is an error. A bare &, a < that does not begin a tag, and control characters are errors too, each with a message saying what to write instead. If you are pasting text with many < or & characters, you may wrap it in a CDATA section: everything between <![CDATA[ and ]]> is taken literally, so the text itself cannot contain ]]>. Disco accepts CDATA anywhere text is allowed and never writes it; content you read back always uses &lt;, &amp;, and ]]&gt;.

Attributes

Every attribute in this document is one of three kinds: Any attribute not listed for an element is an error.

Text blocks

p

A paragraph. Contains rich text.
  • An empty paragraph is <p/>.

Line breaks and tabs

Empty inline elements that may appear anywhere in a block’s text.

br

A line break inside a block. Empty; Disco writes it as <br/>. No attributes.
  • A newline in your source is not a line break; see Whitespace.

tab

A tab inside a block. Empty; Disco writes it as <tab/>. No attributes.
  • A literal tab character is also accepted; see Whitespace.

Validation

Writing is all-or-nothing. If any part of a document is invalid, nothing is saved and you receive a list of at most 100 errors. Each error carries:
  • code, one of the codes below, and message, a sentence saying what to write instead.
  • line and column in your XML, when the error has a position.
  • path, the element at fault such as disco_doc/p[2].
  • attribute, the attribute at fault, when there is one.
  • allowed, the accepted values, when they are a fixed set.
  • suggestion, the name you probably meant, when there is a likely one.

What you get back

When you read content, Disco produces XML in a fixed, predictable form:
  • No XML declaration, DOCTYPE, or comments. The root is disco_doc.
  • One block per line, indented two spaces per level. Text within a block on a single line.
  • Attributes in the order listed in this document. Optional attributes omitted when they hold the default.
  • Empty elements written self-closing: <p/>, <br/>.
You are not required to write in this form. Disco accepts any layout and attribute order allowed by this document.

Full example

A complete document in the form Disco writes it back.