A small embeddable data language with schemas, helpful diagnostics, units, comments, and clean JSON interop, ready to drop in
  • Zig 78%
  • TypeScript 17.7%
  • Rust 2.7%
  • JavaScript 0.5%
  • Shell 0.4%
  • Other 0.7%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Hugo Daniel 665c2242e1 SJON 1.4.1
SJON is a schema-constrained data language for domain tools and the agents that operate them: deterministic S-expression data plus a pure, bounded expression layer, one front-end, a stable binary wire format, append-only diagnostic codes, and parity hosts in Zig, Node, Rust, and TypeScript.

## 1.4.1 — 2026-09-11

The npm packages move to the `@sjon-lang` scope: `@sjon-lang/schema`,
`@sjon-lang/web` and `@sjon-lang/highlight`. The `@sjon` scope on npm
belongs to an account this project does not control, so 1.4.0 could not
be published under the names its documentation gave, and no `@sjon/*`
package exists on npm at any version. Nothing else changed: no
wire-format change (still v5), no new diagnostic codes, and the
conformance corpus still at 393 cases.

### Changed

- **`@sjon/*` is now `@sjon-lang/*`.** The package names, the workspace
  dependencies between them, every import specifier, the READMEs and
  `scripts/publish-npm.sh` follow. A consumer that depends on these
  packages by path replaces `@sjon/` with `@sjon-lang/` in its
  `package.json` and its imports; the code is otherwise the code 1.4.0
  shipped.
2026-09-11 11:26:25 +01:00
conformance SJON 1.4.0 2026-09-11 10:28:07 +01:00
docs SJON 1.4.1 2026-09-11 11:26:25 +01:00
editors/vscode SJON 1.4.1 2026-09-11 11:26:25 +01:00
examples SJON 1.4.0 2026-09-11 10:28:07 +01:00
fixtures SJON 1.0 2026-06-09 22:58:55 +01:00
hosts SJON 1.4.1 2026-09-11 11:26:25 +01:00
landing-page SJON 1.4.1 2026-09-11 11:26:25 +01:00
manifests SJON 1.3.0 2026-08-27 14:57:32 +01:00
scripts SJON 1.4.1 2026-09-11 11:26:25 +01:00
src SJON 1.4.1 2026-09-11 11:26:25 +01:00
tools SJON 1.4.1 2026-09-11 11:26:25 +01:00
.editorconfig SJON 1.0 2026-06-09 22:58:55 +01:00
.gitignore SJON 1.1.0 2026-08-15 12:23:29 +01:00
biome.json SJON 1.3.0 2026-08-27 14:57:32 +01:00
build.zig SJON 1.4.0 2026-09-11 10:28:07 +01:00
build.zig.zon SJON 1.4.1 2026-09-11 11:26:25 +01:00
CHANGELOG.md SJON 1.4.1 2026-09-11 11:26:25 +01:00
coverage-baseline.txt SJON 1.1.0 2026-08-15 12:23:29 +01:00
LICENSE SJON 1.0 2026-06-09 22:58:55 +01:00
llms.txt SJON 1.4.0 2026-09-11 10:28:07 +01:00
package.json SJON 1.4.1 2026-09-11 11:26:25 +01:00
pnpm-lock.yaml SJON 1.4.1 2026-09-11 11:26:25 +01:00
pnpm-workspace.yaml SJON 1.1.0 2026-08-15 12:23:29 +01:00
README.md SJON 1.4.1 2026-09-11 11:26:25 +01:00
SJON.svg SJON 1.0 2026-06-09 22:58:55 +01:00

SJON

SJON is a schema-constrained data language for domain tools and the agents that operate them.

Domain tools grow config languages; agents write a growing share of the config. SJON gives both a shared substrate: an S-expression AST with the schema as data, validated identically in Zig, JS, and Rust.

Two layers, parsed by one front-end: deterministic S-expression data, plus a pure, bounded, closed-vocabulary expression layer evaluated by the consumer.

(scene :bpm 130
  (canvas :name "main"
    (camera :ortho :zoom (* 2 (b 1)))
    (stack :mode :mask
      (shape :sdf :radius 0.5
        :delay (delay :p+s (b 4))
        :lifespan (b 16))
      (shape :path :points [[0 0] [1 0] [1 1]]))))

Guarantees

Every claim below is machine-enforced, not asserted — each links the gate that checks it.

  • Totality — a tree always exists after parse; collection over abort. No parse can crash the caller.
  • Determinism — bit-identical eval native vs. WASM (vendored exp64/log64/pow64), checked by byte-diffed goldens.
  • Boundedness — no host-stack recursion anywhere in the Parser, Validator, or Expr evaluator; depth, step, and memory-budget ceilings, each with a test that trips it (oom_tests.zig).
  • Wire stability — Binary IR is versioned and diagnostic codes are append-only, both gated by the conformance corpus. Full layout in docs/DESIGN.md.
  • Diagnostics as product — every error carries (code, severity, span, path), a 119-entry explanations catalogue, and LSP quick-fixes. See it below.
Field Size Value
version 1 B 0x05

393 fixtures replayed bit-identically across the Zig, Node, Rust, and TypeScript hosts. 18 never-panic fuzz harnesses. 119 explained diagnostic codes. Zero dependencies in the core library. Every number here is drift-gated by zig build audit-docs; run zig build verify to check all of it yourself.

See it catch a mistake

$ printf '(scene :w 800)\n' | sjon validate -
<stdin>:1:2: error: unknown_form: unknown form `scene`
  at scene (phase: validation)
1 error

$ sjon explain unknown_form
unknown_form
  A form's head name is not declared by any loaded plugin.
...
https://hugodaniel.com/pages/sjon/errors/unknown_form

Every diagnostic is a real error page, not a string — same code in the CLI, the LSP's Problems panel, and --format=github CI annotations. See docs/TOOLING.md for the full CLI and LSP capability list.

Consuming

Every host shares the diagnostic vocabulary, the binary wire format, and the conformance corpus — behavior is byte-identical across all four. Full comparison table and quickstarts: docs/INTEGRATION.md.

Zig — the reference path, zero runtime dependencies:

// build.zig.zon
.dependencies = .{
    .sjon = .{ .path = "../sjon" },
},
// build.zig
const sjon_dep = b.dependency("sjon", .{ .target = target, .optimize = optimize });
exe.root_module.addImport("sjon", sjon_dep.module("sjon"));
const sjon = @import("sjon");

var tree = try sjon.parse(gpa, source);
defer tree.deinit();

const text = try sjon.print(gpa, tree, .{ .mode = .canonical });
defer text.deinit();

Node / Web (WASM)zig build wasm-all, then:

import { SjonEncoder, SjonReader } from "hosts/web/sjon-reader.ts";

const encoder = await SjonEncoder.load("sjon.wasm");
const reader = await SjonReader.load("sjon-binary.wasm");
const binary = encoder.toBinary('(scene :bpm 130)');
const result = reader.validateBinary(binary);

See examples/quickstart-web.mjs and hosts/web/README.md.

Rust — wraps sjon.wasm via wasmtime:

let host = SjonHost::load("sjon.wasm")?;
let result = host.validate_document(source, options)?;

See examples/quickstart-rust.rs and hosts/rust/README.md.

TypeScripthosts/typescript-parity/ is a hand-ported reference for conformance verification, not for production; @sjon-lang/schema (hosts/schema/) is the typed schema builder for TS-first projects. See hosts/schema/README.md.

Docs

Building

zig build test      # all test suites (all in-source)
zig build verify    # every local gate: tests, fuzz, audits, all hosts, biome, clippy
zig build wasm-all  # both WASM artifacts
zig build lsp       # native sjon-lsp

Requires Zig 0.16.x.

Versioning & releases

The stable surfaces are the binary wire format and the diagnostic-code enum — versioned, and gated by the conformance corpus plus zig build verify. A change to either is deliberate and version-gated: the wire bumps its format integer, diagnostic codes only append, and the corpus lands updated in the same change.

Every package in this repo carries the one version declared in src/version.zig; zig build audit-format-versions names any manifest that falls out of step. The @sjon-lang/* packages carry full registry metadata and pack cleanly with npm pack; today they are consumed as path or workspace dependencies. What each release changed is in CHANGELOG.md.

License

CC0 — public domain. See LICENSE for the legal text.