1.What is xlli?

xlli is a JSON format for spreadsheet data. One file extension (.xlli), one MIME type (application/vnd.xlli+json), one canonical form readable in any language with a JSON parser.

The first public dictionary is MicroTable — a simple grid kind for the cases where a spreadsheet would be overkill but a CSV is too plain. Headers, styled cells, sparklines and badges as cell types, sparse overrides for hand-edited content. About thirty lines of JSON for a real table.

xlli is designed to round-trip cleanly with Excel via .NET (EPPlus), and to be implementable in a weekend by a competent engineer in any language. The reference engines are C# and Rust. The Rust engine compiles to WASM for the browser and Node, and exposes a native binding for Python via PyO3. Two engines in lockstep, multiple language runtimes, one canonical JSON.

xlli round-trip architecture Excel xlsx files round-trip with the xlli JSON format via EPPlus. Two reference engines — one in C#, one in Rust — produce byte-identical canonical JSON. The Rust engine compiles to WASM for the JavaScript runtime (browser and Node) and exposes a native binding for Python via PyO3. Excel .xlsx workbook EPPlus xlli .xlli canonical JSON shared WIT C# engine .NET 6, 8, 10 · NuGet Rust engine crates.io reference wasm-bindgen PyO3 JavaScript browser, Node, edge Python native, NumPy-friendly Two reference engines maintained in lockstep, validated by golden-file tests. JavaScript and Python are language bindings over the Rust engine.
Excel ⇄ xlli ⇄ engines. Two reference engines (C#, Rust) produce byte-identical canonical JSON. Rust additionally hosts the JavaScript and Python bindings.

2.Why xlli?

Four things motivate the format. Take any one of them and a thoughtful engineer would build something like xlli. We hit all four in actual use, which is why we're building it now.

2.1128-bit decimal

JSON numbers are IEEE 754 doubles. That's fine for charts and dashboards. It's not fine for finance. 0.1 + 0.2 != 0.3 is the canonical example — amusing in a tutorial, catastrophic in a P&L.

xlli encodes high-precision values as tagged objects:

{ "value": "1234567890.123456789",
  "type": "decimal" }

The string carries the exact decimal. The tag tells consumers it isn't a display string. C#'s System.Decimal, Rust's decimal crate, and IBM's libdecnumber all round-trip through this encoding losslessly. v0.2 ships this; v0.1 sticks to JSON-native numbers.

2.2JSON sheet persistence

Spreadsheet files have always been binary or zipped-XML — a black box between sessions. xlli is plain JSON. You can cat it, grep it, diff it, version-control it cleanly, edit it with any text editor, transform it with jq.

A row added becomes one line of git diff, not a binary churn. Same JSON in C# as in Rust as in JS. Same bytes on disk as on the wire. Stable canonical ordering, byte-identical round-trip, explicit precision, no hidden state.

2.3Excel ⇄ xlli ⇄ HTML

Three formats that should talk to each other and rarely do. xlli sits in the middle as the canonical structured form:

  • Excel → xlli: read .xlsx via EPPlus. v0.2.
  • xlli → Excel: write .xlli to .xlsx. v0.2.
  • xlli → HTML: render to a styled HTML table. v0.1.
  • HTML → xlli: parse a structured HTML table back. Future.

xlli's contribution isn't a fifth format — it's the explicit lossless intermediate that lets the existing formats talk.

2.4Two engines, native everywhere

xlli has two reference engines: one in C#, one in Rust. They're maintained in lockstep, validated by golden-file tests that produce byte-identical canonical JSON.

The Rust engine compiles to WASM and ships as the JavaScript package — a thin wrapper that gives you ergonomic JS APIs over the canonical engine. Same engine reaches Python via PyO3, with NumPy-friendly interop. C# stays its own native engine because the .NET ecosystem and EPPlus integration both deserve a first-class library, not a wrapper.

Two engines, multiple language runtimes, one canonical JSON. Adding a fifth language (Java, Go, Swift) is a mechanical binding over the Rust engine rather than a redesign.

3.The shared WIT interface

WIT (WASM Interface Type) is the IDL we use to describe what every xlli engine must implement. The two engines and every binding speak through these types, so the parity story isn't aspirational — it's a contract that fails CI when broken.

// xlli.wit — the shared interface (excerpt)

package xlli:core@0.1.0;

interface engine {
  /// Parse canonical xlli JSON into a typed model.
  parse: func(json: string) -> result<document, parse-error>;

  /// Serialise a model back to canonical xlli JSON,
  /// byte-identical across implementations.
  serialise: func(doc: document) -> string;

  /// Canonicalise input that may be valid but non-canonical
  /// (whitespace, key order). Returns canonical bytes.
  canonicalise: func(json: string) -> result<string, parse-error>;

  /// Validate a document against the v0.1 schema.
  validate: func(doc: document) -> result<_, list<validation-error>>;
}

interface document {
  resource document {
    constructor();
    xlli-version: func() -> string;
    document-kind: func() -> string;
    microtables: func() -> list<microtable>;
    add-microtable: func(id: string, table: microtable);
  }
}

world xlli-engine {
  export engine;
  export document;
}

The Rust engine implements this directly. The C# engine implements an equivalent interface generated from the same WIT source, so the surface area in both languages is provably the same. The JavaScript and Python bindings are thin generated wrappers — when WIT changes, the bindings regenerate.

WIT also makes adding a fourth or fifth language a mechanical exercise. Java via JNI, Go via cgo, Swift via WIT-direct bindings — same contract, mechanical port, no redesign.

4.What MicroTable looks like

A real example. Three products, Q1 revenue, a sparkline:

{
  "xlliVersion": "0.1.0",
  "documentKind": "container",
  "meta": {
    "id": "01HXM3V4F8Q2WK9C6YNBZPRS71",
    "title": "Q1 Revenue Review",
    "author": "Steve Dickson"
  },
  "microtables": {
    "summary": {
      "caption": "Q1 by Product",
      "styles": {
        "header": { "fontWeight": "bold", "backgroundColor": "#f5f5f5" },
        "money":  { "textAlign": "right", "fontVariantNumeric": "tabular-nums" }
      },
      "columns": [
        { "id": "product", "label": "Product",    "styleName": "header" },
        { "id": "q1",      "label": "Q1 Revenue", "styleName": "money"  },
        { "id": "trend",   "label": "Trend" }
      ],
      "values": [
        ["Widget A", 42500, null],
        ["Widget B", 38100, null],
        ["Widget C", 29700, null]
      ],
      "presentation": [
        [null, null, null],
        [null, null, null],
        [null, null, { "type": "sparkline", "values": [10,12,15,14,18] }]
      ]
    }
  }
}

The data lives in matrices. values is a 3 × 3 grid. presentation is the same shape, with cell content overrides where a richer cell type is wanted. Styles are named once and referenced by string. Sparse overrides are available for tables where most positions are empty.

The shape is rectangular, the parsing is JSON, the rendering is one HTML table with one stylesheet. Implementations that go further — multi-sheet workbooks, the worksheets and workbooks dictionaries arriving in v0.2 — extend the same root container.

5.Roadmap

ReleaseTimelineAdds
v0.1 ~2 months microtables dictionary, canonical form, two reference engines (C# and Rust) plus JS and Python bindings, JSON Schema, HTML render
v0.2 ~6 months worksheets and workbooks dictionaries, EPPlus addin (Excel round-trip), 128-bit decimal encoding
v1.0 ~12 months Production-grade table engine, composition dictionaries (sections, cards, pages), full document story

Public spec at xlli.org. Reference implementations open-source. Conformance test suite shared.

6.Get involved

xlli is a coordination format. It works best when more than one implementation exists and more than one ecosystem uses it. We are particularly interested in talking to:

Status
The format is private to its early collaborators today and will graduate to fully public as v0.1 freezes. Get in touch if you want early access to drafts and reference implementations.

7.More