Your first document
A ThoughtML document is a plain-text file (.thml) describing a piece of
reasoning. Let’s write the smallest complete one and run it.
Write it
Create hello.thml:
observation flat-loaf
The Sunday sourdough came out of the oven flat.
hypothesis dead-starter
The starter had lost its lift after three weeks unfed in the fridge.
link dead-starter causes flat-loaf
baker holds dead-starter
confidence 0.8 estimated
Three things are happening:
- Two foci. A focus is a thing you’re reasoning about. The header word
states what sort it is — an
observationyou made, ahypothesisabout why — and the indented line under each is its prose body. - A link.
dead-starter causes flat-loafrecords a typed, directed relationship between them. - A stance.
baker holds dead-startersays who believes what, theconfidence 0.8says how strongly, andestimatedsays on what footing.
The bundled why-the-loaf-failed.thml is where this
goes next: three explanations proposed, one of them settled by evidence.
Run it
thoughtml hello.thml
You’ll get canonical JSON on stdout — the normalized object model, the interchange form every implementation emits. Abbreviated:
{
"objects": [
{ "type": "focus", "id": "flat-loaf", "kind": "observation",
"body": "The Sunday sourdough came out of the oven flat." },
{ "type": "focus", "id": "dead-starter", "kind": "hypothesis",
"body": "The starter had lost its lift after three weeks unfed in the fridge." },
{ "type": "link", "id": "dead-starter-causes-flat-loaf",
"from": "dead-starter", "relation": "causes", "to": "flat-loaf" },
{ "type": "stance", "id": "baker-holds-dead-starter",
"agent": "baker", "posture": "holds", "target": "dead-starter",
"confidence": { "kind": "number", "value": 0.8 }, "basis": "estimated" }
]
}
Notice the parser gave every record an id (flat-loaf,
dead-starter-causes-flat-loaf, …). Ids are how records reference each other.
Check it
The document above is clean — no diagnostics. Break it on purpose: change the link’s target to a focus that doesn’t exist.
link dead-starter causes flat-laof
Run it again and the parser warns on stderr:
warning: link.to of `dead-starter-causes-flat-laof` is an unresolved reference `flat-laof`
warning: focus `flat-loaf` is not connected to anything
Two warnings, not one: the typo also left the real flat-loaf with nothing
pointing at it. That second line is the parser noticing an orphan — a node that
earns no place in the argument.
This is the everyday loop: write reasoning, run it, fix what the parser flags. Diagnostics catch the structural mistakes — dangling references, contradictions, cycles, orphans.
See it as a graph
Open the same file in the playground and it renders as a graph: foci as nodes (shaped by kind), links as labeled arrows, stances attached to their targets. The whole point of ThoughtML is that you can read the argument straight from the picture.
Next
Start the tutorial, which builds one real document up from a single focus to a full argument the mirror can audit.