← All posts
Deep dive

Inside the .oasr format: one file for weights, tokenizer, and metadata

Why an OpenASR model is a single GGUF-backed .oasr file with its descriptors embedded as metadata - and why that file is a portable pack, not a publisher-signed artifact.

A trained speech model usually arrives as a directory: a weights file or three, a tokenizer, a config, maybe a separate metadata JSON, all of which have to stay together and stay in sync. OpenASR ships a model as one file instead. The runtime pack format is .oasr, and a single .oasr carries the weights, the tokenizer, and the descriptors the loader needs, so a model is something you can cache, copy, and hash-pin as one object rather than a folder you hope nobody reshuffled.

It is standard GGUF bytes

There is no bespoke binary container here. A .oasr v1 payload is standard GGUF bytes; OpenASR does not define a custom outer container for v1. The four-byte OASR magic is reserved for a future real container and is rejected today, so “the format” right now is GGUF plus a contract about what lives inside it and what the file is called.

Two boundaries: bytes, then extension

OpenASR deliberately separates two checks that are easy to conflate. The low-level container probe identifies a package by its first four magic bytes, never by filename: GGUF is accepted, the reserved OASR magic is rejected today, and any other magic fails closed. That reader is intentionally extension-agnostic, which is how internal GGUF test fixtures keep loading regardless of what they are named.

The user-facing contract is stricter and keys off the extension. OPENASR_RUNTIME_PACK_EXTENSION = "oasr" is the sole runtime-pack extension: the CLI run input (--model-pack) and the import-*-local converter output both accept and produce only .oasr, and the legacy .gguf extension is no longer accepted at any public boundary. Inside the runtime it is still GGUF; at the edges it is .oasr.

Descriptors ride inside the file

Rather than sidecar files, the OpenASR descriptors live as GGUF key-value metadata in the same file: openasr.package.version (which must be the string "1"), openasr.model.family, openasr.model.architecture, openasr.runtime.min_version, openasr.audio.frontend, and openasr.decode.policy. The loader and runtime-selection layers read those keys straight out of the pack, so the file describes how to run itself.

A v1 .oasr is standard GGUF: weights, tokenizer, and OpenASR descriptors in one file. The header is GGUF's own, not a per-pack publisher signature.

Because the payload is GGUF, the runtime binds weights with zero-copy mmap and reuses graph buffers to bound peak RSS, so the single-file shape is also what keeps loading cheap.

bashrun a local pack
$ openasr transcribe --model-pack model.oasr clip.wav
# one file in, transcript out - no sidecars to keep in sync

Pinned and catalog-signed, not signed in place

It is tempting to describe a self-describing single file as “signed,” but that would be wrong. A .oasr bundles weights, tokenizer, and metadata and carries no in-pack publisher signature. Trust is established at pull time through two separate mechanisms: the pack is sha256/size pinned when it is fetched, and the catalog manifest that points to it is Ed25519-signed. The pack is the payload; the trust lives next to it. How the signed catalog and fail-closed pull chain work walks through that pull chain end to end.

i

Two mechanisms, not one signature

The pack itself is content-pinned (size plus sha256 must match before install). Separately, the catalog manifest is signed with the built-in OpenASR Ed25519 catalog key, with rollback rejected. Neither is a signature embedded in the .oasr file.

A .oasr is a portable pack, not a signed file: the bytes are GGUF, the trust is the pin and the signed catalog beside it.

from the v1 package contract

That is the whole design in one line. Standard bytes so the ecosystem’s tools still work, one file so a model is a single auditable object, descriptors inside so it runs itself, and trust kept where it belongs rather than stamped onto the payload.