GitHub - dsemakin/onyx: A portable interchange format for a personal food and body weight diary, and the engine that reads, validates and migrates it.

GitHub

4 min read Original article ↗

A portable interchange format for a personal food and body-weight diary, and the engine that reads, validates and migrates it.

CI Spec License

Why

There is no interchange format for a personal food diary. Every consumer calorie tracker exports a proprietary CSV and none of them import each other's. Open mHealth and IEEE 1752 cover body weight, activity and sleep across roughly 113 schemas and have no food schema at all. HL7 FHIR NutritionIntake was modelled on inpatient tray monitoring and no consumer app implements it. Apple Health has no food name field, so item identity is lost on export.

The result is that a person's own multi-year eating history is the least portable data they own — and "I have years of data in there" is the single most common reason people do not move between trackers.

Read the specification →

Status

The specification is at 1.0.0. The reference engine is released at the same version: binaries on the releases page and the zero-install checker on npm. The first producer ships it — Burnin exports and imports Onyx documents since version 1.2.2 (September 2026). A second implementer is actively wanted — see GOVERNANCE.md.

Quick start

Validate a diary without installing anything:

npx @dsemakin/onyx validate diary.json

Or download the standalone onyx binary for your platform from the releases page — no runtime needed:

Use it as a library:

[dependencies]
onyx-core = { git = "https://github.com/dsemakin/onyx", tag = "v1.0.0" }

The crates are not on crates.io yet; that is a deliberate choice explained in docs/releasing.md.

Editor support

A document that carries the schema URL gets validation, autocomplete and hover documentation in VS Code and every JetBrains IDE with nothing installed:

{
  "$schema": "https://cdn.jsdelivr.net/gh/dsemakin/onyx@v1.0.0/spec/v1/log.schema.json",
  "format": "onyx",
  "specVersion": "1.0.0"
}

The reference engine writes that line into every document it produces. For files that lack it, VS Code can be told by file name, in settings.json:

"json.schemas": [
  { "fileMatch": ["*.onyx.json", "*.onx.json"],
    "url": "https://cdn.jsdelivr.net/gh/dsemakin/onyx@v1.0.0/spec/v1/log.schema.json" }
]

What is in here

Path Contents License
spec/ The specification and versioned JSON Schemas CC0-1.0
corpus/ Language-agnostic conformance suite CC0-1.0
migrations/ Declarative version-migration manifests CC0-1.0
crates/ Rust engine, CLI and wasm bindings MIT OR Apache-2.0
packages/npm/ The npx-able distribution MIT OR Apache-2.0
examples/ Small reference readers in other languages MIT OR Apache-2.0
docs/ Architecture, conformance, releasing CC0-1.0
scripts/ Repository checks; no build step MIT OR Apache-2.0
.github/ Contributing, security, governance, CI —
LICENSES/ Full licence texts, named by SPDX identifier —

The first three directories are deliberately data, not code. Anyone can implement Onyx from them without reading a line of Rust, and the conformance corpus will tell them whether they got it right. That is the point: a format only one program can read is a backup, not a standard.

Dependencies

None. onyx-core depends on nothing; the CLI and the WebAssembly bindings depend only on onyx-core. The npm package has no dependencies and the workflows use one first-party GitHub Action.

The JSON reader, the error types, the argument parser and the WebAssembly ABI are all written here. That is a deliberate trade, argued in full — including what it costs — in docs/dependencies.md.

Implementations

Implementation Role Since Conformance
Burnin Producer, consumer 1.2.2, September 2026 Runs the full corpus in its test suite as a consumer; export verified against the reference engine
examples/reader-py Consumer 1.0.0 Passes all four corpus groups

Burnin is a calorie counter for iPhone and Android with no account and no server: the diary lives on the phone, and "export the whole thing" produces an Onyx document. It is where this format started, and its import merges rather than overwrites, which is the behaviour §2 asks of a consumer restoring an older file.

The Python reader is a reference example rather than an independent implementer — it proves the corpus is passable and the specification complete, not that anyone else has adopted the format.

One producer is not a format. If you have built a reader or a writer in any language, run the conformance corpus against it and open a pull request adding it here — that is the contribution this project wants most. A consumer that only reads its own files has implemented a backup.

Contributing

See CONTRIBUTING.md. Adding a conformance case requires no Rust at all; it is a JSON file in corpus/. If you are a coding agent, start with AGENTS.md.

Licensing

Code is dual-licensed under MIT or Apache-2.0 at your option, the Rust ecosystem convention. The specification, schemas, conformance corpus and migration manifests are released under CC0-1.0 — implement them freely, fork them, rename them. A standard that constrains its own adoption is not a standard.