Kimo
Docs
v1.0
Changeloggetkimo.design
Docs
v1.0
File format spec
§15

Canonical serialization

On this page3 sections
  1. 15.1 Layout
  2. 15.2 Key order
  3. 15.3 Parsing
Status
Stable (format version 1.0.0, frozen 2026-10). Backward compatible within 1.x (§16.4). Supersedes the draft v0.1, kept as a historical record; 0.1 files open through the 0.1 → 1.0 migration (§16.2).
Schema
https://getkimo.design/schema/kimo-1.0.json (JSON Schema draft 2020-12), generated into packages/core-schema/schema/kimo-1.0.schema.json. The 0.1 schema stays published at …/kimo-0.1.json (schema/kimo-0.1.schema.json, frozen).
Reference
@kimo/core-schema (packages/core-schema). Where this document and the implementation disagree, that is a bug in one of them; file an issue.
Plan of record
docs/teardown.md §10. Every place where this spec resolves an ambiguity in, or deviates from, that section is listed in §20.
License
MIT

The canonical serialization is a pure function of the document's data. Writers MUST produce it; for every canonical text s, serialize(parse(s)) === s.

15.1 Layout

Text
{
"$schema": "https://getkimo.design/schema/kimo-1.0.json",
"format": "1.0.0",
"features": ["layout/wrap"],
"meta": {"name":"Kimo landing"},
"variables": {
"ink": {"type":"color","value":"#111111"}
, "space-m": {"type":"number","value":16}
},
"nodes": {
"A1hero0001": {"type":"frame","parent":null,"order":"a0","name":"Hero"}
, "B2title001": {"type":"text","parent":"A1hero0001","order":"a0","content":"Hi"}
}
}
  1. The first line is {; the file ends with } and one LF.
  2. Each root member is written on its own line as "key": <value> — one space after the colon — followed by , except for the last member. Members appear in canonical order (§15.2); nodes is always last; unknown root members follow the known ones (sorted by code unit) and precede nodes. Only the members defined in §4 are ranked at the root; an unknown root member is not ranked even when its name appears in Appendix A, and its value is opaque (§15.2).
  3. Tables — nodes, variables, assets and conflicts (§21) — are written as "key": {, then one line per entry, then }. Entries are sorted by key (code unit). Each entry is "<key>": <value> on a single line; the separating comma is written at the start of every entry line after the first (, "<key>": …), and one blank line separates consecutive entries. An empty table is written {} on the member's line. (Appending or removing the last entry never edits a neighbouring line; the blank line keeps unrelated neighbours out of one conflict hunk in a line-based merge.)
  4. Every other value (root members, table entries) is written as compact JSON: no insignificant whitespace.
  5. Strings are written as by ECMAScript JSON.stringify (minimal escaping; non-ASCII as UTF-8; U+2028/U+2029 unescaped). A value never spans lines.
  6. Numbers are written in the shortest form that round-trips (ECMAScript Number.prototype.toString), e.g. 0.30000000000000004, 1e+21. Negative zero is written 0. NaN and infinities cannot be written.
  7. Properties equal to their default are omitted (§14). Top-level features is sorted by code unit. Arrays otherwise keep their order. Properties whose value is undefined do not exist.
Keywords:
MUST
MUST NOT
SHOULD
MAY
set in small mono caps wherever they are normative

15.2 Key order

  • Structs (schema-defined objects: the root, nodes, paints, layout, …): keys listed in Appendix A come first, in that order; all other keys follow, sorted by code unit. The order is a single global ranking that does not depend on the object's kind.
  • Records (keys are data): keys sorted by code unit. Record-valued properties are listed in Appendix B. Their values are structs, except where Appendix B says opaque.
  • Opaque values — anything below an unknown key, and the values of the opaque records — are ordered purely by code unit at every depth.

This rule is part of the versioning contract (§16.4): because keys introduced by later versions sort after all 1.0 keys and their subtrees are ordered purely by code unit, a 1.0 reader re-serializes a newer document byte-identically.

15.3 Parsing

Readers MUST reject: malformed JSON; duplicate keys in any object (a duplicated node id would otherwise be silently dropped); a root that is not an object. A __proto__ key is ordinary data. Parsing does not validate (§17).