← All reference docs

Licensing

Licensing in Oath is an evidence domain, not a metadata field. It follows the same split as every other verdict the registry produces:

| the publisher | the registry | |---|---| | ASSERTS terms, signed, immutable once published | DERIVES what a composition permits, reproducibly |

Nothing else about the system changes. A licence assertion is part of a signed publication envelope; a licensing verdict is a derived fact recomputed from the journal on demand, with an identity that lets you re-derive it rather than trust it.

What this is not

Asserting terms

A licence is asserted in the publication envelope (SPEC §8.6.1), so it is covered by the author's signature:

oath publish --remote https://registry.oath-lang.org \
             --key mykey.key \
             --license Apache-2.0 \
             mydef.oath

--dry-run prints the exact bytes that would be signed before signing anything:

EXACT BYTES TO BE SIGNED (this is the statement, not a summary of it):
  | oath-publish/2
  | op=put
  | name=pow
  | artifact=090cc5373e20…
  | parent=090cc5373e20…
  | parent_rev=1
  | author=65ea5701d92e…
  | license=Apache-2.0

Three consequences worth understanding before you publish:

Omitting --license asserts nothing, which is recorded as the explicit no-assertion sentinel - rather than as an empty field. "The publisher chose to say nothing" and "the format had no licence line" are different historical facts.

Reading the verdict

oath license <name>

or, over MCP, the license tool — which returns JSON because the consumer is usually an agent deciding whether it may ship something.

The verdict has five dimensions. Four are PERMISSIONS and one is an OBLIGATION, and they combine with opposite polarity:

| dimension | kind | combines | |---|---|---| | commercial use | permission | any NONO | | redistribution | permission | any NONO | | modification | permission | any NONO | | patent grant | permission | any NONO | | share-alike | obligation | any YESYES |

A prohibition anywhere defeats a permission; a reciprocal requirement anywhere binds the whole composition. Equivalently: permissions fold as MINIMUM and obligations as MAXIMUM over NO < UNSTATED < YES.

UNSTATED is not permission

This is the single most important thing to get right, and it is where Oath differs most from a licence scanner.

UNSTATED means no evidence, and it is contagious: one unknown or unmodelled dependency makes the entire composition unknown, however many others granted. Ignorance can establish neither a permission nor the absence of an obligation.

A consumer may adopt "treat UNSTATED as deny" or "require explicit grants". The registry will not choose that for you, and it will not quietly upgrade absence of a prohibition into a grant.

The evaluation identity

Every verdict carries a digest binding what was evaluated and by what:

{
  "engine": "oath-license/1",
  "model": "spdx-lattice/1",
  "model_digest": "a3aafb3713e3…",
  "policy": "composition",
  "evaluation_digest": "10a68f83e42f…"
}

Each input is a TRIPLE, and each component answers a question the others cannot:

| component | answers | |---|---| | artifact hash | which code was evaluated | | publication identity | whose grant was consumed | | asserted expression | what terms that grant stated |

Names are discovery paths and contribute nothing to identity. Renaming a definition does not change its evaluation; repointing a name to different code does, because the closure changed.

The model is published, not built in

The lattice mapping identifiers to grants lives in fixtures/license/model.json, incorporated by reference as NORMATIVE DATA (SPEC §13.1b). It is not frozen into the specification: a legal model is expected to be corrected, and §12.4 already makes each version distinguishable, so freezing it would make every correction a specification fork.

Two rules keep it honest:

Identifiers match by exact octet equality. mit, MIT and (MIT) are not MIT. A registry that helpfully normalised would turn an expression the publisher never wrote into a grant.

What a verdict does not tell you

Recorded in the output rather than left implicit:

The corpus asserts Apache-2.0

Since 2026-08-01 the live registry's corpus carries signed licence assertions: 184 names, Apache-2.0, each in a publication signed by the publisher's key. So a composition query returns a real verdict rather than the honest-but-empty UNSTATED a corpus with no assertions must produce.

Apache-2.0 was chosen against the model rather than by reputation. It is the only row granting all four permissions with no share-alike obligation — MIT, ISC, BSD and Unlicense all leave patent_grant UNSTATED, and because UNSTATED is contagious, a corpus published under any of them would make the patent dimension unknown for every downstream composition.

See also


Rendered verbatim from docs/licensing.md in the repository. The markdown is the single source; this page is a copy checked for drift in CI, so what you read here is what an implementer reads.