Design principles
These are the ideas that shape every decision in Wit. Read them before proposing a change or building on the AST — most questions about why Wit is the way it is are answered here.
Prose comes first
Structure is opt-in. The constraint that governs the whole language is that the source stays readable as prose: plain sentences render as plain paragraphs, and a writer never has to leave the writing to satisfy the format.
Content in bodies, parameters are metadata
A node's content goes in its body; anything that merely describes the node — a link's address, an image's size — rides in parameters. This one rule keeps documents clean as they grow, and it is elevated from an authoring tip to a project value.
A small reserved core
Wit ships a small core vocabulary that mirrors HTML's semantic shapes — headings,
lists, links, images, tables, sections. Renderers commit to handling these
faithfully. Everything beyond the core is either a writer's own definition
(written #name) or the opaque pass-through
(@node), which carries parameters straight to the renderer so it
can dispatch on a type convention.
#highlight ||content|| @node(type highlight) ::content:: node@ highlight# @highlight Some text highlight@
The core stays small on purpose. If a definition can express something, it does not become a core node.
Not Turing-complete
Wit is not a programming language. The script bridge, , is the
single explicit escape hatch for general computation — everything else is
declarative. That boundary is deliberate: it keeps documents analysable and
their output deterministic.
A file format, not a system
Wit is not a CMS, an editor, or a general templating engine. It is a file format — a way to write a document that many different programs can then consume. It is not an inline rich-text editor language, and it does not do arbitrary string interpolation in prose.
Engineering constraints as principles
The implementation constraints are principles too: zero runtime dependencies, deterministic output, source locations that survive every stage, small files and functions, and a corpus of fixtures that acts as the executable specification. Tests come first — a behaviour is not real until a fixture pins it.
Common contributor mistakes
- Reaching for a new core node. If a definition would do, add a definition, not a reserved name.
- Adding interpolation to prose. String interpolation in ordinary prose is a non-goal — data reaches prose through dotted access, not template holes.
See also
Architectureshows how these principles become a pipeline; How to add a node or renderer applies them in practice.