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:
- 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.
- It round-trips. Any content you can create in the Disco editor can be read as Disco XML and written back without loss.
- 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 onedisco_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
paragraphare rejected, and the error names the Disco XML spelling to use instead. - HTML styling attributes are never accepted.
style,class,id, anddata-*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:- A run of whitespace that contains a newline is collapsed to a single space.
- 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.
<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 	 are accepted. The only named entities are XML’s
own five, <, >, &, ", and ', so 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 <, &, and ]]>.
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, andmessage, a sentence saying what to write instead.lineandcolumnin your XML, when the error has a position.path, the element at fault such asdisco_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/>.