DMS Dialects

This directory holds dialect specs for DMS tier 1. Each dialect is a published contract — families, sigil bindings, param signatures, content-slot rules, version-match strategy — that any tier-1-capable port can register and validate against.

The tier-1 framework itself (decorator grammar, sidecar shape, hoisting, decoder/encoder split, mutate-API contract, multi-line flow layout) is defined in TIER1.md. Dialects plug into that framework; they don't redefine it.

Published dialects

Dialect Brand File ext Spec Status
HTML dms+html .dms.html dms+html.md 0.1 (draft)
HCL/Terraform dms+hcl .dms.hcl dms+hcl.md 0.1 (draft)
KDL v2 dms+kdl .dms.kdl dms+kdl.md 0.1 (draft)
RON dms+ron .dms.ron dms+ron.md 0.1 (draft)
Kubernetes dms+k8s .dms.k8s dms+k8s.md 0.1 (draft)

What kinds of formats fit a DMS dialect

The dialect framework targets data with metadata about that data. It does not target programs, constraint languages, or expression-heavy formats. The split matters because the framework's value comes from a clean separation between the value tree (data) and the decoration sidecar (metadata) — when source is mostly computation or constraints, there's no natural "data half" to put in the value-column, and the dialect ends up pushing everything into the sidecar as opaque strings.

The rule, stated cleanly:

A format fits when most of the source is data and the decoration is metadata about that data. It doesn't fit when most of the source is computation, constraints, or references.

Formats checked so far

Format Verdict Why
HTML / SVG ✓ fits Element-shaped data; tag + attrs are metadata about the element
HCL / Terraform ✓ fits Block-shaped data; expressions confined to @expr opaque strings
KDL v2 ✓ fits Node-shaped data with positional + named + children
RON ✓ fits Tagged ADT data; tags ARE the metadata, payload is data
ZON ✓ fits Anonymous structs/lists with tagged literals; mostly tier-0 plus tags
JSON Schema ✓ fits Schema-shaped — types and constraints structured, no general-purpose computation
Jsonnet ✗ rejects Programming language; lambdas, conditionals, imports dominate
Dhall ✗ rejects Typed lambda calculus; computation-first by design
CUE ✗ rejects Constraint language; unification, references, computation everywhere
KCL ✗ rejects Constraint language with schemas; same shape as CUE structurally

What "data with metadata" looks like in practice

The fits all share a structural property: a reader scanning for values lands on a stable column. The metadata sits in decoration calls (|tag(...), @type ...) that the reader can either focus on or skip. Compare:

+ |resource("aws_instance", "web")(   ← metadata: kind + labels + attrs
    ami:           "ami-...",          ← data: in the value-column
    instance_type: "t2.micro",
  )
+ |player(name: "Alice", score: |some 42)   ← metadata: variant + struct

In both cases, the data values ("ami-...", "t2.micro", "Alice", 42) occupy a predictable column on every line. Tools that strip the decoration in lite mode get back a clean value tree.

What rejected formats look like

The rejected formats don't have a clean "values" column to begin with — every position is potentially an expression that needs evaluation. A faithful dialect representation would put a decoration on every value:

# Hypothetical dms+jsonnet — most lines are decorations
+ |local(name: "x", value: 5)
+ |local(name: "y", value: 10)
+ |body
  + sum: |add(|ref "x", |ref "y")        ← every value is a decorator call

The value-tree is mostly empty defaults; the data lives entirely in the decoration sidecar's params. Lite mode produces an unhelpful "all empty" tree. Generic tooling can't operate on the value tree because there's no usable data there. The dialect delivers no benefit over storing the original source as a string in a single DMS field.

Before proposing a new dialect

Ask: "If I strip every decoration from the source, is what's left valid, useful data, or is it gibberish empty maps and lists?"

Templating on DMS

DMS is a data format. It deliberately doesn't include expressions, variables, conditionals, imports, or computation — that's the Goal and applies at every tier. For cases where you genuinely need computation to produce a config, run a templating language on top of DMS. The templating layer handles the computation; DMS is the output format that consumers actually load.

This is a clean separation of concerns:

template source (jsonnet / Jinja / Helm / KCL / CUE / your tool)
        ↓ evaluation
DMS document (.dms / .dms.html / .dms.hcl)
        ↓ tier-0 or tier-1 decode
Document (Map / List / Scalar [+ decoration sidecar])

The templating layer can be:

Why this separation works:

Examples of this pattern in the wild (analogous):

A dms+jsonnet or dms+cue dialect would invert this — try to move the templating layer itself into DMS — and that's where the model breaks. Keep templating outside; let DMS be the output target.

If you build such a tool, the dms-<lang> ports (Rust, Python, Lua, etc.) provide encoder APIs that accept Map / List / Scalar value trees plus an optional decoration sidecar and emit canonical DMS. That's typically all the templating layer needs to bind against.

Conventions

Adding a new dialect

A new dialect spec is a markdown file alongside the existing ones. The structure that has settled across dms+html and dms+hcl:

  1. Header — brand, extension, version, parent spec links
  2. What this is — one paragraph framing
  3. Quick comparison — same content in source format vs dms+X form, side by side
  4. Dialect canonical spec — the formal contract written in DMS itself (families, sigils, content_slot, params)
  5. Content semantics — how source forms map to value tree + sidecar
  6. Inventory — representative names the dialect handles
  7. Versioning — what counts as breaking / additive / patch
  8. File extension
  9. What's not in scope — explicit non-goals
  10. Open questions for v0.2+

Dialects don't need a bench / conformance corpus per se — tier-1 conformance is matrixed (port × dialect → pass count) in TIER1.md §"Conformance", and corpus fixtures live in dms-tests under per-dialect subdirectories (planned).

Governance (parked)

Allocation of short brand names (html, hcl, markdown, etc.) is currently first-come-first-served via PRs to this directory. A formal registry is a parked open question; see TIER1.md §"Branding & file naming" → "Open: dialect registry governance."

For unofficial / experimental work: prefix with x- (x-mybrand) or use reverse-DNS namespacing (io.flolabs.html).