Wit

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

Architecture

shows how these principles become a pipeline; How to add a node or renderer applies them in practice.