documentation
Markdown prose, inside the file.
You write the model once. Read it as documentation, edit it with an LLM, derive any companion from it, or produce a view only when someone asks.
A Markdown file can say that a lamp’s brightness is 80. The Block says the same thing in prose, and also as an Integer, with a reference a tool can follow. Documentation stays Markdown. It is a member of the Block, next to the model.
documentation
Markdown prose, inside the file.
properties
Brightness is an Integer.
references
SeeAlso names another Block.
# Lamp
A lamp with a brightness of 80.
See also: the shade.
<ex:Lamp xmlns="http://blockml.org/bml"
xmlns:core="org.blockml.bml.core"
xmlns:ex="com.example.bml">
<baseType>
core:Block
</baseType>
<is>
A lamp with a brightness
</is>
<documentation>
# Lamp
Brightness runs from 0 to 100.
The value below is the same fact, typed.
</documentation>
<properties>
<brightness type="Integer">
<value>80</value>
</brightness>
</properties>
<references>
<see type="ex:Shade" relation="SeeAlso" />
</references>
</ex:Lamp>
The workspace is the Blocks. People and models search, inspect, extend, and validate them. Intermediate states stay in the files. A renderer publishes the current state.
A DocSet is the document. ValidatePublishReady checks that it can be published. AssembleSite renders each page, wraps the layout and the theme, and writes HTML. Those files are the manifestation of that run.
A multi-stage change is a ModelTransformation. transform apply runs one execution against the model, and that execution is itself a Block. One transform runs at a time, on a clean worktree.
npx blockml transform apply com.example.bml._meta.transform.AddProduct
A catalog is ordinary Blocks: compositions, types, references. An LLM finds them with search and inspect, edits the file, then validate checks the result. The file is the record.
<ex:Catalog xmlns="http://blockml.org/bml"
xmlns:core="org.blockml.bml.core"
xmlns:ex="com.example.bml">
<baseType>
core:Block
</baseType>
<is>
The products an assistant may answer from
</is>
<aggregations>
<products type="ex:Product">
<composition>
<ex:Lamp />
<ex:Shade />
</composition>
</products>
</aggregations>
<references>
<see type="ex:Lamp" relation="SeeAlso" />
</references>
</ex:Catalog>
The Block stays the source of truth. A renderer writes a companion in the form the target needs: a document, a schema, application code, a CAD model, a service, or any other native form. There is no fixed companion language. A fix belongs in the Block. Rendering writes the companion again.
HTML
Pages and documents
XSD
Schemas
TypeScript
Libraries and services
OpenSCAD
Parts you can print
InboxScreen.bml names the title and the two actions. One renderer writes a React function. Another writes an Angular component. Both are companions of this Block. A different target writes a different artifact from the same file.
<app:InboxScreen xmlns="http://blockml.org/bml"
xmlns:core="org.blockml.bml.core"
xmlns:app="com.example.bml">
<baseType>
core:Block
</baseType>
<is>
The inbox screen
</is>
<properties>
<title type="Text">
<value>Inbox</value>
</title>
</properties>
<aggregations>
<actions type="app:Action">
<composition>
<app:Compose />
<app:Archive />
</composition>
</actions>
</aggregations>
</app:InboxScreen>
export function InboxScreen() {
return (
<section>
<h1>Inbox</h1>
<Compose />
<Archive />
</section>
);
}
@Component({
selector: "app-inbox",
template: `
<section>
<h1>Inbox</h1>
<app-compose />
<app-archive />
</section>
`
})
export class InboxComponent {}
A companion can be written into the repository and kept. Just-in-time software runs that render when a request arrives. OpenOrders.bml stays. The HTML below exists for the response.
<ex:OpenOrders xmlns="http://blockml.org/bml"
xmlns:core="org.blockml.bml.core"
xmlns:ex="com.example.bml">
<baseType>
core:Block
</baseType>
<is>
A report of orders that are still open
</is>
<properties>
<title type="Text">
<value>Open orders</value>
</title>
</properties>
<aggregations>
<columns type="ex:Column">
<composition>
<ex:OrderId />
<ex:Customer />
<ex:DueDate />
</composition>
</columns>
</aggregations>
</ex:OpenOrders>
<article>
<h1>Open orders</h1>
<table>
<thead>
<tr>
<th>Order</th>
<th>Customer</th>
<th>Due</th>
</tr>
</thead>
</table>
</article>
Produced for the request. The repository keeps OpenOrders.bml.
Init a package, then open the folder in Cursor or Claude Code. The same file can be documentation, a workspace, a companion source, or a view rendered on demand.