Python and JavaScript bindings
The openantares/ant repository ships two reference bindings alongside the spec. They are secondary to the canonical Rust implementation — the Rust crate wrote the golden files the bindings are verified against — but each is a complete, single-file implementation you can read top to bottom, and each doubles as a CLI with the same sysexits exit-code contract as the openantares tool.
Get them by cloning the repository (each binding is one file — copying it into your project works too):
git clone https://github.com/openantares/antPython — reader, writer, validator
Section titled “Python — reader, writer, validator”bindings/python/openantares.py needs the zstandard package and nothing else beyond the standard library:
pip install zstandardfrom openantares import AntReader, AntWriter, validate, decode_property
with open("world.ant", "rb") as f: reader = AntReader(f.read()) for record in reader: # dicts: {"kind": ..., "data": ...} ...assert reader.verified # trailer sha256 + counts checked
summary = validate("world.ant") # raises AntError on any violationAs a CLI, against a golden from the conformance suite:
$ python3 bindings/python/openantares.py validate conformance/golden/basic.antconformance/golden/basic.ant: OK version=0.3 records=7 skipped=0 counts={'schemaTypes': 0, 'vertices': 2, 'edges': 1, 'observations': 1, 'evidence': 1, 'beliefs': 1, 'vectors': 1, 'vertexTombstones': 0, 'edgeTombstones': 0}$ echo $?0JavaScript — reader, validator
Section titled “JavaScript — reader, validator”bindings/js/openantares.mjs needs Node ≥ 22.15 — the version where node:zlib gained native zstd — and no packages at all:
import { AntReader, validate, decodeProperty } from "./openantares.mjs";
const reader = new AntReader(fs.readFileSync("world.ant"));for (const record of reader) { ... } // {kind, data} objectsif (!reader.verified) throw new Error("unverified");As a CLI:
$ node bindings/js/openantares.mjs validate conformance/golden/basic.antconformance/golden/basic.ant: OK version=0.3 records=7 skipped=0 counts={"schemaTypes":0,"vertices":2,"edges":1,"observations":1,"evidence":1,"beliefs":1,"vectors":1,"vertexTombstones":0,"edgeTombstones":0}$ echo $?0Decoding typed values
Section titled “Decoding typed values”Both bindings expose a property decoder (decode_property / decodeProperty) for the v0.3 typed-value envelopes. Two rules they implement that a port must not lose:
- A decimal is never converted to a native number.
Number("12345678901234567.89")— andfloat(...)in Python — passes through an IEEE double and silently becomes a different value. The decoders return decimals as text; use a decimal type or BigInt for arithmetic. - A timestamp keeps its UTC offset. Normalizing
+02:00toZon read discards the one thing that distinguishes TIMESTAMPTZ from TIMESTAMP.
Both bindings pass the full conformance suite, including the negative fixtures, and both flag a file whose minor version is ahead of them rather than guessing.

