Cartridge blueprints
A blueprint is everything needed to build a cartridge except what has to be downloaded to do it. It lets a cartridge be open source when its weights cannot, or should not, live in a source repository — and it makes the build loop of Developing a cartridge machine-readable.
Why blueprints exist
[drafted]
A cartridge is self-contained: it bundles its runtime and its model artifacts, pinned by digest in a signed manifest (Integrity). That is the right shape for something an application loads. It is the wrong shape for a public source repository:
-
Weights are large and not ours to host. They have a publisher, a license, and often terms that must be accepted before download. Re-hosting them in a repository copies the bytes and silently drops the terms.
-
Compiled artifacts are target-specific. A
.vmfbfor one GPU architecture is useless for another; committing every combination does not scale, committing one hides the others. -
The build loop was prose. Until v0.4 the spec described how a cartridge is produced in eight numbered lines of text. Where the weights come from, which exact revision, how they are converted and quantized, with which tool versions — none of it was recorded anywhere a machine or a reviewer could check.
A blueprint fixes all three by separating what is open from what is fetched and built.
Terms
[drafted]
| Term | Meaning |
|---|---|
Blueprint |
The open part of a cartridge: API and runtime source, a descriptor template, and a recipe —
pinned sources, a pinned toolchain, targets, ordered steps. Described by one |
Materialization |
Executing a blueprint’s recipe for one target: fetch, convert, quantize, export, compile, build the runtime, measure, pack, sign. Its result is a cartridge. |
Materialization profile |
What the materializing party supplies: target, flavors, the cartridge’s version, license acceptances, mirrors, declared inputs, measurements, signing identity. |
Materializer |
The tool that executes a blueprint against a profile. The reference implementation is the
Gradle plugin |
Materialized cartridge |
The result. A cartridge in every sense of the concept page — same
|
A blueprint is to a cartridge what a source package with a lockfile is to a binary: not a lesser cartridge, and not loadable. A host never sees a blueprint.
The blueprint contract
[drafted]
A blueprint MUST
-
Pin every source by an immutable revision at its publisher and by the SHA-256 of every file taken from it. A branch name is not a revision; a URL without a digest is not a pin.
-
State every source’s license and redistribution class —
allowed,restricted, oracceptance-required— so that what a materializer may do with the result is known before anything is downloaded (Licensing). -
Pin its toolchain: every tool a step names, at an exact version. Version ranges are not pins.
-
Carry a descriptor template from which, together with the fields materialization resolves, a schema-valid capability descriptor results (Resolving the descriptor).
-
Declare its inputs: anything it needs that is host- or organization-specific — a tool catalog, a vocabulary, a calibration set — is declared as a named input with a schema, and supplied by the profile. This is how the app-agnosticism rule of the cartridge contract carries over: product content never enters a blueprint, not even as an example.
-
Map every product to a manifest artifact: role,
pack_dirpath, and the sources and inputs it isderived_from. License obligations trace through builds along exactly these edges (ADR-004). -
Ship the source of everything it builds — including the native runtime that implements the Runtime ABI. The runtime is built at materialization; it is not downloaded.
A blueprint MUST NOT
-
Contain artifacts of role
weights,model, or a builtruntime— no checkpoints, no compiled modules (.vmfb,.ort, NPU blobs), no parameter archives, no prebuilt native libraries. Small test fixtures (a golden input and its expected output) are not model artifacts and are allowed. -
Contain measured numbers as descriptor content.
performanceandqualityare properties of materialized artifacts on a device (Resolving the descriptor). -
Encode license acceptance. A blueprint can say acceptance is required; only a profile can record that someone accepted.
-
Name a device, a fleet, a registry, or a customer. Targets are described by hardware class and ABI. Anything more specific belongs to a profile.
Anatomy of blueprint.json
[drafted] — schema: examples/cartridge-blueprint.schema.json.
spec_version, kind : "0.4", "blueprint"
id, version : <task>-<model>-<runtime> (no target) + semver of the RECIPE
license : license of the blueprint's own code and recipe — not of any cartridge
descriptor_template : descriptor minus what materialization resolves (see below)
sources[] : name, role, uri (hf://… | https://…), revision, files[{path, digest}],
license, license_url, redistribution
toolchain{} : tool name → exact version (+ coordinates or container image)
targets[] : id, target{hardware, abi, accelerator}, requirements, params
flavors[] : optional — id, sources[], descriptor_overrides (ADR-014)
inputs[] : name, role, required, schema — supplied by the profile
steps[] : id, kind, tool, uses[], produces[], per_target, params — in order
outputs[] : from (a step product), role, pack_dir path, derived_from[]
verification[] : parity | golden | task-metric | conformance checks that gate packing
reference_measurements[] : what the authors measured — an expectation, never descriptor content
Step kinds are a closed vocabulary so that a reader — and a license or security reviewer — can tell what a recipe does without running it:
kind |
What it may do |
|---|---|
|
Download sources and verify their digests. Nothing else touches the network. |
|
Change format or layout. Numerics change only by an explicit dtype cast. |
|
Change numeric precision. What is and is not quantized is stated in |
|
Turn a model into a compiler input (StableHLO, ONNX). |
|
Turn a compiler input into a target artifact. |
|
Build the native runtime library from the blueprint’s source. |
|
Produce |
|
Assemble the |
|
Sign the manifest with the materializing party’s key. |
Materialization
[drafted] — profile schema: examples/materialization-profile.schema.json.
Given a blueprint and a profile, a materializer:
-
Validates both against their schemas, and checks that the profile’s
blueprint.version(anddigest, when given) match the blueprint in hand. -
Checks licenses before fetching. For every source the chosen target and flavors need: if its
redistributionisacceptance-requiredand the profile has no matchinglicense_acceptanceentry, it MUST stop. It MUST NOT offer to accept on anyone’s behalf. -
Fetches each source from its
uri, or from the profile’s mirror for that source, and verifies every file’s digest. A mirror changes where bytes come from, never which bytes. A digest mismatch is fatal, not a warning. -
Validates inputs against the schema the blueprint declares for them.
-
Runs the steps in order, with exactly the pinned tool versions. A materializer that substitutes a tool version MUST record the substitution in provenance and MUST NOT claim the blueprint’s
verificationresults. -
Runs the blueprint’s
verificationchecks. A failed check stops materialization before anything is packed. -
Resolves the descriptor (Resolving the descriptor).
-
Computes the effective license from the licenses of every source and input that an output is
derived_from(Licensing). -
Packs the
pack_dirand writes a manifest ofkind: cartridgewhoseprovenancenames the blueprint (Provenance). -
Signs the manifest with the key the profile names.
The result MUST be indistinguishable, to a host, from a cartridge produced any other way: same
pack_dir layout, same schemas, same ABI. Everything in
Integrity and the threat model applies
unchanged. Blueprints add no new runtime surface.
Resolving the descriptor
A descriptor template leaves out exactly the fields a blueprint cannot know:
| Field | Resolved from |
|---|---|
|
the spec version the materializer implements |
|
|
|
the profile’s |
|
the chosen blueprint target |
|
computed (Licensing) |
|
measured — a |
|
the blueprint flavors the profile selected, each with its own measurements |
The honesty rule of the descriptor is not relaxed by a build recipe:
performance and quality in a materialized descriptor MUST come from a run of those
materialized artifacts on the device measured_on names. A blueprint MAY publish
reference_measurements; they tell a materializer what to expect and MUST NOT be copied into a
descriptor. Two parties materializing the same blueprint for the same target will usually report
different numbers, and both are true.
Licensing
Rule 2 of Licensing — the effective license must fulfill every upstream license — is evaluated at materialization, because that is the first moment the full set of upstreams is known: the sources actually used (a flavor may bring a differently licensed checkpoint), plus every supplied input.
-
The blueprint’s own
licensecovers its code and recipe. It says nothing about any cartridge. An MIT blueprint routinely materializes into a cartridge whose effective license is a model publisher’s terms, orproprietaryonce a private input is added. -
redistributiontells the materializing party what it may do with the result:allowed— the cartridge may be passed on under the computed license;restricted— only under conditions the materializer must check for itself (a revenue cap, a display duty, a field of use);acceptance-required— access itself is conditional, and the result inherits the terms. -
Licenses are facts about a specific checkpoint at a specific revision, stated by its publisher — never inferred from the model family. Moonshine is the worked case: its streaming checkpoints are MIT in every language (a German streaming flavor’s source is
allowed), while its legacy non-streaming models for languages other than English stay under a non-commercial community license (a blueprint using one marks that sourcerestricted, and a materialization selecting it carries the obligation into its manifest — visibly, instead of nowhere). A blueprint author checks the publisher’s statement for the pinned revision and recordslicense_url; a materializer re-checks it.
Provenance
The manifest of a materialized cartridge carries two additional, optional provenance members
(manifest schema v2, additive):
provenance.blueprint : id, version, digest (sha256 of blueprint.json),
source { repo, commit | coordinates }
provenance.materialization : profile_digest, target, flavors[],
toolchain { name → version actually used }, materializer
provenance.inputs keeps its existing meaning and now has an obvious content: one entry per
fetched source file and per supplied input, by digest. Together these make the lineage
source bytes → recipe → artifact bytes auditable from the manifest alone.
Who signs. The materializing party, with its own key. A blueprint’s authors vouch for a recipe; only whoever ran it can vouch for the bytes that came out. A host’s trust store is therefore keyed by who materialized, exactly as it is today by who published.
Distributing and consuming blueprints
[drafted]
A blueprint is source, and travels like source:
-
As a repository —
git clone, then materialize. This is consumption Mode B with its recipe made explicit. -
As a published artifact — the blueprint’s code as a library plus its
blueprint.json, consumed by version from a package repository together with the materializer plugin. No fork and no submodule: a consumer’s repository contains a profile and its inputs, nothing else.
Either way the materialized cartridges are distributed by the existing modes — a hub (A) or an internal artifact store ©.
Downstream and private materialization
[drafted]
The common case for an organization shipping products: the blueprint is public, the cartridge is not. The organization’s repository holds
-
a profile — its target, the flavors it ships, its cartridge version line;
-
mirrors for the sources, so builds do not depend on a public endpoint;
-
license acceptances made by its legal entity;
-
inputs — its tool catalog, its vocabulary, its calibration recordings;
-
its signing identity, and the publishing configuration for its own artifact store.
It materializes in its own CI and distributes by Mode C. Nothing flows back into the blueprint, and nothing needs to: every one of those items is declared by the blueprint as something a profile supplies. If a private materialization needs a change to the recipe — a new target, a different quantization — that change is public by nature and belongs upstream, as a new blueprint version.
The effective license of such a cartridge follows from its private inputs like from any other
upstream: typically proprietary, with the public sources' obligations still carried in the
manifest.
Reproducibility
[direction]
A blueprint is the precondition for OQ11, not its answer. With sources and toolchain pinned, two materializations for the same target can be compared byte for byte; whether today’s exporters and compilers are deterministic end to end is still open. When they are, a blueprint MAY publish expected artifact digests per target, and the Mode B trust path — rebuild and compare, instead of trusting a signature — becomes real. Until then, a materialized cartridge is trusted because of who signed it.
What a blueprint is not
[drafted]
-
Not a cartridge. It cannot be loaded, has no manifest, and makes no performance claim.
-
Not a model card. It describes how artifacts are produced, not how a model was trained.
-
Not a build service. Cartridge as a service is a place to run materializations; a blueprint is what it would run.
-
Not a weights-update mechanism. A
weights-updatemanifest still pins a base cartridge by digest. A blueprint whose source revision moves is a new blueprint version, and materializing it yields a new base.
Open questions
[drafted]
-
OQ-B1 — Step vocabulary. Closed today. Whether backends need an extension mechanism, or new kinds are added by spec revision only.
-
OQ-B2 — Expected digests. The shape of per-target reproducibility claims, once OQ11 allows them.
-
OQ-B3 — Signed blueprints. A blueprint is pinned by digest in the profile; whether blueprint releases also need publisher signatures, and how that composes with the trust roles of OQ6.
-
OQ-B4 — Measurement on hardware the materializer does not own. Whether a third party’s measurement can be referenced from a descriptor, and with what attribution.