The easiest way to understand a modelling language is to see how progressively richer models are built.
These examples begin with simple standalone concepts and proceed toward reusable, versioned model ecosystems. Each links to the section of the specification that defines the mechanism it uses.
Fundamentals
A single class, then the type and constraint vocabulary used to describe what its values may be.
01
A minimal class
Every OOML artefact states the specification version it targets, its own fully qualified name, and a human-readable name. Everything else is optional.
{"ooml":"0.1.0","fqn":"com.example.crm/Customer@1.0.0","name":"Customer","description":"An organisation or person that buys goods or services.","attributes": {"customerNumber": {"kind":"primitive","type":"string","name":"Customer Number","required":true,"description":"The identifier this customer is known by commercially." } }}
02
Types and constraints
Constraints describe which values are valid. They are logical statements about the value set, not instructions about storage.
{"ooml":"0.1.0","fqn":"com.example.crm/Customer@1.1.0","name":"Customer","attributes": {"customerNumber": {"kind":"primitive", "type":"string","name":"Customer Number","required":true,"pattern":"^CUST-[0-9]{6}$" },"creditLimit": {"kind":"primitive", "type":"decimal","name":"Credit Limit","precision":12,"scale":2,"minimum":0 },"employeeCount": {"kind":"primitive", "type":"uint32","name":"Employee Count","description":"uint32 states the permitted numeric range, not a storage width." },"onboardedAt": {"kind":"primitive", "type":"datetime","name":"Onboarded At","required":true },"website": {"kind":"primitive", "type":"uri","name":"Website","nullable":true } }}
Structure and relationships
How one class relates to another — by reference, by embedded structure, or by collection.
03
References and embedded structures
An object attribute points at an instance of another class by identity. A nested attribute describes an ad hoc structure inline, for a shape that has no meaning outside this class.
{"ooml":"0.1.0","fqn":"com.example.hr/Employee@1.2.0","name":"Employee","attributes": {"department": {"kind":"object","type":"com.example.hr/Department@^1.0.0","name":"Department","required":true,"description":"A reference to a Department instance, by identity." },"manager": {"kind":"object","type":"self","name":"Manager","nullable":true,"description":"'self' means the declaring class; tooling expands it." },"homeAddress": {"kind":"nested","name":"Home Address","required":true,"description":"No independent identity; described inline.","attributes": {"streetName": {"kind":"primitive", "type":"string","name":"Street Name", "required":true },"houseNumber": {"kind":"primitive", "type":"string","name":"House Number", "required":true },"postalCode": {"kind":"primitive", "type":"string","name":"Postal Code", "required":true } } } }}
04
Collections
Lists are ordered and permit duplicates; sets do not permit duplicates; maps hold keyed entries. A collection's values may themselves be nested structures.
{"ooml":"0.1.0","fqn":"com.example.hr/Employee@1.2.0","name":"Employee","extends": ["com.example.hr/Person@^1.0.0","com.example.common/Auditable@^1.0.0" ]}/* Resolution order (depth-first, left to right): Employee -> Person -> Party -> Auditable Resolved attribute surface: Accessor From Identity ------------------------------------------------------------ createdAt Auditable common/Auditable@1.0.0#createdAt updatedAt Auditable common/Auditable@1.0.0#updatedAt id Party hr/Party@1.1.0#id firstName Person hr/Person@1.0.0#firstName lastName Person hr/Person@1.0.0#lastName employeeNumber Employee hr/Employee@1.2.0#employeeNumber startDate Employee hr/Employee@1.2.0#startDate (namespaces abbreviated for width) Attributes are identified by their fully qualified name, not by their local name, so two ancestors contributing the same local name are simply two different attributes rather than a conflict to arbitrate.*/
07
Enumerations as classes
OOML has no separate enumeration artefact. A class acts as the root of a category and its subtypes are the values — which means enum values can carry attributes and be versioned like anything else.
{"ooml":"0.1.0","fqn":"com.example.hr/EmploymentType@1.0.0","name":"Employment Type","description":"The nature of an employment relationship. Subtypes are the values.","abstract":true}{"ooml":"0.1.0","fqn":"com.example.hr/FullTime@1.0.0","name":"Full Time","extends": ["com.example.hr/EmploymentType@^1.0.0"],"attributes": {"weeklyHours": {"kind":"primitive", "type":"uint8","name":"Weekly Hours","required":true,"description":"Something a conventional enum value could not express." } }}/* Referenced from a class: */"employmentType": {"kind":"enum","type":"com.example.hr/EmploymentType@^1.0.0","name":"Employment Type","required":true,"description":"Valid values are subtypes of the root, excluding the root itself."}
Reuse across models
Definitions that should mean the same thing wherever they appear, and the adjustments a consuming model can make.
08
Reusable global attributes
A global attribute is a shared, independently versioned definition of one piece of information. Classes reference it instead of redefining an equivalent field.
{"ooml":"0.1.0","fqn":"com.example.finance/salary@1.0.0","name":"Annual Salary","description":"An annual gross salary in the organisation's base currency.","kind":"primitive","type":"decimal","precision":14,"scale":2,"minimum":0}/* Global attribute names are camelCase, distinguishing them from PascalCase class names: a global attribute is a reusable attribute, never a type that gets instantiated or extended. Referenced from a class:*/"annualSalary": {"kind":"attribute","type":"com.example.finance/salary@^1.0.0","name":"Annual Salary","nullable":true}
09
Renaming and overriding what you inherit
Inherited definitions cannot be silently redeclared. Where a subclass needs a clearer local name or a tighter constraint, it says so explicitly.
{"ooml":"0.1.0","fqn":"com.example.planets/CelestialBody@1.0.0","name":"Celestial Body","extends": ["com.example.planets/Surface@^1.0.0","com.example.planets/Core@^1.0.0" ],"use": {"com.example.physics/temperature@^1.0.0": {"as":"surfaceTemperature" },"com.example.geology/coreTemperature@^1.0.0": {"as":"coreTemperature" },"gravity": {"as":"surfaceGravity","override": {"description":"Surface gravity relative to Earth's (1.0 = Earth gravity)." } } }}/* Both superclasses contribute an attribute locally named 'temperature', backed by different definitions — so each is picked out by its fully qualified name. 'gravity' comes from only one place and is already unambiguous, so the bare name is enough. Renaming replaces the name rather than adding a second one: at any point in a hierarchy an attribute has exactly one current name. Overriding may only narrow, and only a fixed set of properties. An attribute's kind and type can never be changed by a subclass.*/
Evolution
How models change, and how those changes stay visible to consumers.
10
Independent versioning and dependencies
Each artefact carries its own version, and references it through a range. Those references are the dependencies — there is no separate manifest to keep in step.
/* MAJOR A breaking change. Consumers must migrate deliberately. Removing an attribute, narrowing a type, renaming. MINOR A non-breaking addition. Existing valid data stays valid. A new optional attribute, a widened type, a new enum subtype. TRIVIAL No structural change at all. Descriptions, names, tags. A reference states the range it accepts: "extends": ["com.example.hr/Person@^1.0.0"] ^1.0.0 accepts any 1.x at or above 1.0.0 — so a superclass can publish a MINOR change without every descendant being re-released, while a MAJOR change remains an explicit decision for each consumer. Because references live in the artefact itself, the dependency graph is derived rather than declared: 'what depends on this?' is answered by reading models, not by trusting a manifest.*/
Model metadata
Typed information about the model itself — and the profiles that can be built from it.
11
Attaching model metadata
Metadata keys name the OOML class that defines the metadata's shape, so what is attached here is typed and validatable rather than free-form.
{"ooml":"0.1.0","fqn":"com.example.hr/Employee@1.3.0","name":"Employee","metadata": {"com.example.governance/SchemaInfo@^1.0.0": {"status":"com.example.governance/Published@1.0.0","steward": {"value":"People Systems","cascade":true },"sourceStandard": {"value":"HR-REF-114","cascade":false },"retentionClass": {"value":null,"required":true } } }}/* cascade the value carries down to subclasses that set none of their own final subclasses may not override the value local the entry applies to this artefact only and is not inherited An entry whose value is null but which is required is a declaration that some class in the hierarchy must supply the value before the model is considered complete — which is how a governance requirement becomes a validation result rather than a review comment.*/
12
Governance metadata profile
Define governance once. Require, inherit, override, and lock metadata across a model hierarchy.
extends — inheritance: CustomerRecord is a GovernedDataAsset. metadata — dependency: GovernedDataAsset is governed by the profile, and cannot be resolved without it.
Naming a metadata schema's FQN range as a metadata key creates a dependency edge, exactly as extends does for inheritance.
1 · Define the metadata profile
A metadata schema is an ordinary OOML class. GovernanceProfile carries no marker distinguishing it from a domain class — what makes it a profile is that other artefacts name it as a metadata key. Its attributes are typed, so every governance value attached anywhere in the model is validatable.
com.example.governance/GovernanceProfile@1.0.0
{"ooml":"0.1.0","fqn":"com.example.governance/GovernanceProfile@1.0.0","name":"Governance Profile","description":"Governance annotations for data assets.","attributes": {"owner": {"kind":"primitive","type":"string","name":"Owner","required":true,"description":"Domain accountable for this model." },"steward": {"kind":"primitive","type":"string","name":"Steward","required":true,"description":"Team maintaining the definition." },"classification": {"kind":"enum","type":"com.example.governance/DataClassification@^1.0.0","name":"Classification","required":true,"description":"Sensitivity classification." },"retentionPeriod": {"kind":"primitive","type":"duration","name":"Retention Period","required":true,"description":"Retention duration, ISO 8601." },"governingPolicy": {"kind":"primitive","type":"uri","name":"Governing Policy","required":true,"description":"URI of the governing policy document." },"lastReviewDate": {"kind":"primitive","type":"date","name":"Last Review Date","description":"When the governance entry was last reviewed." },"criticalDataElement": {"kind":"primitive","type":"boolean","name":"Critical Data Element","description":"Whether the asset is a critical data element." } }}
1b · The classification enum
classification is an enum attribute, so its permitted values are the subtypes of an enum root — ordinary classes again, here kept in a sub-namespace of their own.
com.example.governance/DataClassification@1.0.0
{"ooml":"0.1.0","fqn":"com.example.governance/DataClassification@1.0.0","name":"Data Classification","description":"Enum root for sensitivity classifications.","abstract":true}
{"ooml":"0.1.0","fqn":"com.example.governance.classification/Internal@1.0.0","name":"Internal","description":"Disclosable within the organisation.","abstract":true,"extends": ["com.example.governance/DataClassification@^1.0.0"]}
{"ooml":"0.1.0","fqn":"com.example.governance.classification/Restricted@1.0.0","name":"Restricted","description":"Disclosable only to named roles.","abstract":true,"extends": ["com.example.governance/DataClassification@^1.0.0"]}
2 · Declare governance requirements on the base class
GovernedDataAsset applies the profile by naming its FQN range as a metadata key, which creates a metadata dependency edge from the asset to the profile. The controls do the governing: owner and steward are slot declarations — value: null with required: true — obliging some class in the chain to supply them. classification cascades a default that descendants may override. retentionPeriod and governingPolicy cascade and are final, so no descendant may change them. lastReviewDate is local and is not inherited at all.
com.example.governance/GovernedDataAsset@1.0.0
{"ooml":"0.1.0","fqn":"com.example.governance/GovernedDataAsset@1.0.0","name":"Governed Data Asset","description":"Base class for assets under data governance.","abstract":true,"metadata": {"com.example.governance/GovernanceProfile@^1.0.0": {"owner": { "value":null, "required":true },"steward": { "value":null, "required":true },"classification": {"value":"com.example.governance.classification/Internal@1.0.0","cascade":true },"retentionPeriod": { "value":"P7Y", "cascade":true, "final":true },"governingPolicy": {"value":"https://policy.example.org/data-governance/v3","cascade":true,"final":true },"lastReviewDate": { "value":"2026-02-01", "local":true } } }}
3 · Satisfy and specialize the profile
CustomerRecord fills both slot declarations and cascades them onward, narrows the classification from Internal to Restricted, and adds two entries of its own that stay local to it. It says nothing about retention or policy: those arrive already settled.
com.example.governance/CustomerRecord@1.0.0
{"ooml":"0.1.0","fqn":"com.example.governance/CustomerRecord@1.0.0","name":"Customer Record","description":"A customer as held by the customer domain.","extends": ["com.example.governance/GovernedDataAsset@^1.0.0"],"metadata": {"com.example.governance/GovernanceProfile@^1.0.0": {"owner": { "value":"Customer Domain", "cascade":true },"steward": { "value":"Customer Data Office", "cascade":true },"classification":"com.example.governance.classification/Restricted@1.0.0","lastReviewDate": { "value":"2026-08-15", "local":true },"criticalDataElement": { "value":true, "local":true } } },"attributes": {"customerId": {"kind":"primitive","type":"uuid","name":"Customer Identifier","required":true },"emailAddress": {"kind":"primitive","type":"string","name":"Email Address","required":true },"createdAt": {"kind":"primitive","type":"datetime","name":"Created At","required":true } }}
4 · Inspect the resolved metadata
Reading the chain from GovernedDataAsset down to CustomerRecord gives one effective value per attribute, each traceable to where it was set and why it applies.
Attribute
Effective value
How it got there
owner
Customer Domain
supplied by CustomerRecord
steward
Customer Data Office
supplied by CustomerRecord
classification
Restricted
overrides the cascaded Internal
retentionPeriod
P7Y
inherited · cascaded · final
governingPolicy
policy.example.org/…/v3
inherited · cascaded · final
lastReviewDate
2026-08-15
local to CustomerRecord
criticalDataElement
true
local to CustomerRecord
5 · A rejected override
A subclass of CustomerRecord tries to shorten the retention period. Everything else it needs arrives by cascade, so this is the only thing wrong with it.
{"ooml":"0.1.0","fqn":"com.example.governance/ArchivedCustomerRecord@1.0.0","name":"Archived Customer Record","description":"Attempts to shorten a final retention period.","extends": ["com.example.governance/CustomerRecord@^1.0.0"],"metadata": {"com.example.governance/GovernanceProfile@^1.0.0": {"retentionPeriod": { "value":"P1Y" } } }}
Rejected: retentionPeriod is final in GovernedDataAsset and cannot be overridden by a subclass (M02). Note that this document is structurally well-formed and passes the JSON Schema — final enforcement is a cross-artefact rule, checkable only once the inheritance chain is resolved.
Still to be written
Planned examples
The following examples are anticipated by this page’s structure but have not been authored yet. Those describing projections into other technologies depend on generators that do not exist today.
Namespaces and cross-model reuse
Composing a domain from artefacts owned by different teams and namespaces.
An external-standard mapping profile
Recording correspondence between a model and a definition in an external vocabulary.
A small multi-domain model
Several namespaces, shared global attributes and deliberate version boundaries.
OOML → JSON Schema
A projection into JSON Schema. Requires a generator, which does not yet exist.
OOML → UML visualization
Rendering an OOML model as a class diagram. Requires tooling that does not yet exist.
OOML → OWL with ontology metadata
Combining a model with an ontology profile to produce OWL. Requires a generator that does not yet exist.