Metaltura — The Core Metamodel¶
This document explains the most fundamental concept in @platform/metaltura: the Core metamodel, which is the bootstrap that makes the entire MDA/MDD system work.
What Is a Metamodel?¶
In Model-Driven Architecture (MDA), a metamodel defines what a model can contain. In Metaltura, every element in any model has an instanceOf property that points to a Class — and those Classes live in a model too.
That model is the Core model: it is the parent of all other models, and it is its own parent. core.Class is an instance of core.Class. core.Model is an instance of core.Class. Every element in every user-defined model ultimately traces its instanceOf back to a class defined inside Core.
This self-referential structure is not a paradox — it is the standard Meta-Object Facility (MOF) pattern for metamodelling.
Why the Core Model Is Hardcoded¶
Loading a model from YAML or the database requires the loader to resolve instanceOf paths — which means the Core model must already exist in memory before loading can begin. The Core model cannot load itself.
For this reason, the Core model is bootstrapped in TypeScript code rather than stored as a YAML file:
This file runs as a module side-effect (an IIFE at the bottom calls initCache()). It creates all core class instances by hand and wires their properties with direct object references. Every other model — whether loaded from YAML or the database — is loaded on top of this already-live foundation.
The Workspace constructor reflects this: this.models is always pre-initialised with [CoreCache['Core']] before any user models are loaded.
The model structure:
Core (Model)
└── core (Package)
├── Element (abstract Class)
├── RootElement (abstract Class)
├── Container (abstract Class)
├── Model (Class)
├── Package (Class)
├── Type (abstract Class)
├── PrimitiveType (abstract Class)
├── StringType (PrimitiveType instance)
├── NumberType (PrimitiveType instance)
├── BooleanType (PrimitiveType instance)
├── Class (Class)
├── Feature (abstract Class)
├── Property (abstract Class)
├── Relation (Class)
├── PrimitiveProperty (Class)
├── TypedFeature (abstract Class)
├── Parameter (Class)
├── ReturnType (Class)
├── Function (Class)
└── Validation (Class)
Class Inheritance Hierarchy¶
Element (abstract)
│ name: string
│ instanceOf: Class
│
├── Feature (abstract)
│ │ required?: boolean
│ │ multiple?: boolean
│ │
│ ├── Property (abstract) owner: Class
│ │ ├── Relation to: Class, composite?: boolean, opposite?: Relation
│ │ ├── PrimitiveProperty type: PrimitiveType
│ │ └── Function async?: boolean, code: string, parameters[], returnType?
│ │
│ └── TypedFeature (abstract) type: Type
│ ├── Parameter owner: Function
│ └── ReturnType owner: Function
│
├── RootElement (abstract) container: Container
│ ├── Container (abstract) elements[]: RootElement (composite)
│ │ ├── Model depends[]: Model
│ │ └── Package
│ └── Type (abstract)
│ └── PrimitiveType (abstract)
│ ├── StringType
│ ├── NumberType
│ └── BooleanType
│ Class abstract?, extends[], properties[], validations[], icon?
│
└── Validation owner: Class, execute: Function
Key composite relations (ownership):
| Relation | Owner | Owned | Opposite |
|---|---|---|---|
| Container.elements | Container | RootElement | RootElement.container |
| Class.properties | Class | Property | Property.owner |
| Class.validations | Class | Validation | Validation.owner |
| Function.parameters | Function | Parameter | Parameter.owner |
| Function.returnType | Function | ReturnType | ReturnType.owner |
CoreCache¶
CoreCache is a typed, pre-materialized map of all elements in the Core model, keyed by element path:
// modules/platform/metaltura/src/common/context/CoreCache.ts
export type CoreCacheProps = {
Core: Model
core: Package
'core.Class': Class
'core.Element': Class
'core.Element.instanceOf': Relation
'core.Relation': Class
// ... all core elements
}
export const CoreCache: CoreCacheProps = {} as CoreCacheProps
It is populated at module load time when CoreModel.ts runs and calls init(props).
When to use CoreCache:
import { CoreCache } from '@platform/metaltura/common'
// Type check — is this element a Class?
element.is(CoreCache['core.Class'])
// Type check in inherits()
clazz.inherits(CoreCache['core.Container'])
// Resolving instance type in rawToElement
if (clazz.inherits(CoreCache['core.Relation'])) return Relation
Using CoreCache instead of workspace.get('core.Class') is important because:
1. It avoids a traversal on every check
2. CoreCache entries are available before any user model is loaded
3. They are typed — CoreCache['core.Class'] returns Class, not Element
The @metaltura/core Ambient Module¶
The interfaces IClass, IElement, IRelation, IPrimitiveProperty, etc. are declared in a TypeScript ambient module file:
This file uses declare module '@metaltura/core' { ... } to make the interfaces available under that module name throughout the codebase. The package @metaltura/core does not exist in node_modules — it is purely a local TypeScript type declaration. TypeScript finds it because the file is included via tsconfig.json's include: ["modules/**/*"] glob, and the path alias "@metaltura/core" in tsconfig.json points to it directly.
// This import is resolved locally — no npm package involved
import { IClass, IRelation, IElement } from '@metaltura/core'
If you add a new interface for a new metamodel class, add it to core.d.ts.
The Self-Referential Bootstrap¶
The hardest part to grasp is how CoreModel.ts constructs objects that reference each other before they are fully configured. It works in two passes:
Pass 1 — create bare instances (constructor called with minimal data, typed coercion via as):
const e_Class = new Class({ name: 'Class' } as Class)
const e_Class_abstract = new PrimitiveProperty({ name: 'abstract' } as PrimitiveProperty)
Pass 2 — wire all properties (direct assignment):
e_Class.instanceOf = e_Class // A Class is an instance of Class (self-referential)
e_Class.properties = [e_Class_abstract, e_Class_extends, ...]
e_Class_abstract.owner = e_Class
e_Class_abstract.type = e_BooleanType
This two-pass approach avoids circular dependency problems at construction time.
How User Models Relate to the Metamodel¶
A user-defined model (loaded from YAML or the database) must reference Core classes for its instanceOf values:
name: MyModel
instanceOf: core.Model # ← this element is an instance of core.Model
elements:
- name: Person
instanceOf: core.Class # ← Person is an instance of core.Class
extends:
- core.RootElement # ← Person inherits from core.RootElement
properties:
- name: firstName
instanceOf: core.PrimitiveProperty
type: core.StringType
When this model is loaded, rawToElement resolves 'core.Class' to CoreCache['core.Class'] via workspace.get('core.Class'), which searches this.models — and CoreCache.Core is always the first model in workspace.models.