CRUBAL

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-trust gives 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-01 uses 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" } }
  ]
}
  • keys holds 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: 3 would break, and how a package moves.
  • The standard units table itself.

Edit on GitHub · Markdown