11. Packages
A package is what gets published: a named, versioned set of facets, classes, rules, contracts, views and recipes, with the kinds they work on, the packages they build on, and the trust order that settles disagreements. Our catalog is a package; so is commerce; so will be anyone else's.
11.1 The package file #
package: me /2026-10-13
owner: mediaencyclopedia.com
label: Media Encyclopedia
crubal: 2
licence: CC-BY-4.0
extends: commerce /2026-10-01, media /2026-10-01
prefixes:
commerce: crubal.com/commerce
media: crubal.com/media
wd: https://www.wikidata.org/entity/
schema: https://schema.org/
ebay: ebay.com
units: crubal:units /2026-10-14
confirm: 2
split: 3
| Setting | Holds |
|---|---|
package |
the package's name and version |
owner |
the domain that owns the names and signs the package. The package's full identity is owner/name: mediaencyclopedia.com/me, globally unique because only the domain's owner can publish under it |
label · describe |
what people see |
crubal |
the language version it is written in |
licence |
an SPDX licence identifier |
extends |
the packages it builds on, each pinned to a version (11.4) |
prefixes |
nicknames its files use, each mapped to a full identity: a package (domain/name), a vocabulary's base URL, or a party's domain. The package's own name is its default nickname for itself |
units |
the units table it uses, pinned |
confirm · split · recur |
thresholds: independent observations to confirm a value (default 2), instances to propose a version split (default 3), distinct records before a recurring notable or unknown key is proposed as a facet (default 5) (chapter 9) |
trust · facet-trust |
the trust order (11.3) |
terms |
how each audience may use what it's shown: public: search yes, answer yes, train no (chapter 12.5.1) |
The rest of the package is its member files: facet:, class:, rule:, contract:, kind:, view: and
migration: blocks, in any number of files. A package MAY also publish reference records (data files in
the text form, chapter 2) that others read but don't own copies of: the units table is one.
Prefixes are nicknames. Identity is always the full domain/name; a prefix only abbreviates it inside a
package or a wrapper, and readers compare after resolving (chapter 1.3). Two packages may use different
nicknames for one identity, or one nickname for different identities, without clashing.
Reserved prefixes. crubal names the core, wherever its home turns out to be. A package MUST NOT map its
own name, or crubal, to anything else, and within one package two prefixes MUST NOT name the same identity.
11.2 Kinds #
Kinds are declared in packages (chapter 1.2):
kind: item
levels: group, product, unit
base: Item
schema:
group: schema:ProductGroup
product: schema:Product
unit: schema:Offer
vary:
product: edition, size, colour
unit: condition, price, sealed
follows:
label: edition
weight: size
| Setting | Holds |
|---|---|
levels |
the levels, top to bottom |
base |
the class every record of the kind wears |
schema |
the schema.org type, one for the kind or one per level |
vary |
for each level below the top, the facets that vary at the step into it (chapter 1.7). At the step into product, these are the group's forks (edition, size × colour), which shoppers pick along |
follows |
facets that follow a fork (Label follows Edition): they are dependent, so filters count them together |
Classes add vary steps for their wearers with level prefixes (chapter 5.3.3). A package that extends
another MAY add levels' vary steps to that package's kinds; it MUST NOT remove any.
11.3 The trust order #
When two sources disagree (a conflict, chapter 9.3), the trust order picks the current value.
trust:
person
me:unitizer
observed
declared
distributor.example
reported
facet-trust:
runtime: observed, person
weight: observed, person
- Each entry is
person(a person's write through any form), a contract name, a party's domain, or an origin (observed,declared,derived,reported). - A source's rank is its first matching entry: a person's write matches
person; a value from a contract matches the contract, then its origin; a value from another owner matches the domain, then its origin. - Of two sources, the one ranked earlier wins. Equal ranks keep the current value.
- A source matching no entry ranks last.
facet-trustgives a facet its own order, tried before the package's: a source matching an entry of the facet's order ranks by that entry; a source matching none of them ranks after all of them, by its place in the package's order.- The default order, when a package has none, is
person,observed,declared,reported,derived.
Adopted values (chapter 8.2) are outside the trust order: they don't change until they are given back.
11.4 Versions and extending #
- A package version is a frozen set of its members' versions. Publishing produces a members list naming every facet, class, rule, contract, kind, view and recipe with its version, and the package's version names that list.
- Inside a package, everything follows current. Its own members always refer to each other's current versions.
- Outside, adopters pin.
extends: commerce /2026-10-01uses exactly that version until the package moves its pin, which is itself a new version of the package. - Extending (UCP's word, kept for packages and contracts) lets a package add facets, classes, rules, contracts and views, add aliases and values to the extended package's facets, add vary steps, and narrow its classes in classes of its own. It MUST NOT change the extended package's definitions or widen them.
- A new package version that breaks its members (chapter 4.8) ships the recipes (chapter 10).
11.5 Publishing #
A package is published as a bundle: its files, in the text form or JSON, the members list, the recipes since the previous version, and the owner's signature over the bundle's hash.
Publishing MUST run, and the bundle MUST pass, every well-formedness check:
| Chapter | Checks |
|---|---|
| 4.7 | definitions |
| 5.10 | classes |
| 6.8 | rule sets: layering, contradictions, one spelling |
| 7.10 | contracts, including that no secret appears |
| 10.5 | recipes |
| 11.1–11.4 | prefixes, kinds, trust order entries name real contracts and origins, extends doesn't widen |
A published version MUST NOT change. A mistake is fixed by a new version.
11.6 The JSON form #
{
"package": "me",
"version": "2026-10-13",
"owner": "mediaencyclopedia.com",
"id": "mediaencyclopedia.com/me",
"crubal": "2",
"licence": "CC-BY-4.0",
"extends": [ { "package": "crubal.com/commerce", "version": "2026-10-01" } ],
"prefixes": { "commerce": "crubal.com/commerce", "wd": "https://www.wikidata.org/entity/" },
"units": { "package": "crubal:units", "version": "2026-10-14" },
"trust": ["person", "me:unitizer", "observed", "declared", "reported"],
"facet-trust": { "runtime": ["observed", "person"] },
"members": { "facet:videoCodec": "2026-10-13", "class:OpticalDisc": "2026-10-13" }
}
11.7 The home: crubal.com #
The core is the package crubal.com/core, and the prefix crubal always names it. Its names (envelope
lines, origins, audiences, the core facets crubal:notables, crubal:count and crubal:clonedFrom, the
shape crubal:portable) are fixed by this specification.
The standard packages are published by crubal.com for anyone to extend:
| Identity | Holds |
|---|---|
crubal.com/core |
the core's names |
crubal.com/units |
the units table: units by dimension, with conversion factors and accepted spellings, and ISO 4217 currencies |
crubal.com/product |
the item kind (group > product > unit) and the base product facets |
crubal.com/service |
the service kind (service > booking) and the base service facets |
crubal.com/commerce |
stock, offers, prices and shipping, attached to products and services |
crubal.com/media |
films, shows, music and games: formats, codecs, regions, contained works, cast |
Where a package is. A package's identity domain/name resolves through the domain's well-known file:
https://<domain>/.well-known/crubal.json
{
"crubal": "2",
"owner": "crubal.com",
"keys": { "crubal.com": { "alg": "Ed25519", "public": "…" } },
"packages": [
{ "package": "crubal.com/product", "latest": "2026-10-14",
"versions": { "2026-10-14": "https://crubal.com/product/2026-10-14/package.json" } }
]
}
keysholds the owner's published signing keys (chapter 8.5); a party with no published key has unsigned data, which readers MAY refuse.- Each package lists its versions and where each version's bundle is: the package's definitions in the JSON form, the same as its text files read through a Reader (chapters 4.6, 5.9, 6.10, 7.9, 10.6, 11.6).
- A domain MAY also serve its packages as text, beside the JSON (
…/package.crubal).
crubal.com serves the standard packages at https://crubal.com/<name>/, a page for people, with each version
at https://crubal.com/<name>/<version>/package.crubal and …/package.json.
The registry. https://crubal.com/registry/ lists known packages from any domain, and
https://crubal.com/registry/index.json lists the same as data. Listing is optional and never changes where a
package is or who owns it: the owner's well-known file is the truth. A package is listed by adding its
identity to the registry file in the CRUBAL repository.
11.8 Open #
- Language versions: what a
crubal: 3would break, and how a package moves. - The standard units table itself.