CMMF 1.3.0-beta.1 specification
CMMF 1.3.0-beta.1 specification for experimental CMMF 1.3.0-beta.1.
Status: experimental prerelease. This branch and its default schema, documentation, and examples describe 1.3.0-beta.1. The canonical stable release remains 1.2.0. Use the exact prerelease version in manifests; selecting this beta must never fall back to 1.2.0. No stable 1.3.0 release exists yet.
1. Overview
Section titled “1. Overview”The Content Model Master Format (CMMF) is a CMS-agnostic schema definition language designed to:
- define content models in a portable, human-readable format
- capture modelling intent, not just implementation structure
- support translation into multiple CMS platforms
- enable tooling such as generators, validators, and diagram builders
2. Core Principles
Section titled “2. Core Principles”Intent over implementation
Section titled “Intent over implementation”The format describes what the model means, not how a specific CMS stores or renders it.
Explicit relationships
Section titled “Explicit relationships”References and composition must be described directly, including relationship intent where relevant.
Separation of concerns
Section titled “Separation of concerns”The core schema defines structure and intent. CMS-specific choices belong in a translation layer.
Deterministic structure
Section titled “Deterministic structure”The same CMMF input should produce the same structural interpretation every time.
3. Recommended File Structure
Section titled “3. Recommended File Structure”/examples manifest.yaml /models page.yaml article.yaml person.yaml4. Manifest Specification
Section titled “4. Manifest Specification”Example:
specVersion: "1.3.0-beta.1"namespace: example.projectmodelsPath: ./modelsdefaults: required: false localisation: falseManifest Fields
Section titled “Manifest Fields”| Field | Type | Required | Description |
|---|---|---|---|
specVersion |
string | yes | Semver spec version. In CMMF 1.3.0-beta.1 this must be "1.3.0-beta.1". |
namespace |
string | yes | Unique namespace for the model set. |
modelsPath |
string | no | Relative path to model files. |
defaults |
object | no | Default values applied by tooling when omitted in model files. |
Legacy compatibility note:
- pre-semver manifests may use
specVersion: 1to indicate the original v1 release - semver-based manifests should use a quoted string such as
"1.3.0-beta.1"
Supported Defaults in 1.3.0-beta.1
Section titled “Supported Defaults in 1.3.0-beta.1”| Field | Type | Description |
|---|---|---|
required |
boolean | Default field requiredness. |
localisation |
boolean | Default field localisation behaviour. |
5. Model Specification
Section titled “5. Model Specification”Example:
id: pagename: Pagekind: entryfields: []Required Model Fields
Section titled “Required Model Fields”| Field | Description |
|---|---|
id |
Unique identifier for the model. |
name |
Human-readable model name. |
kind |
Model kind. |
fields |
Array of field definitions. |
Optional Model Fields
Section titled “Optional Model Fields”descriptiontagslocalisationsingletoneditorialgovernancetranslationHintsvalidationHints— non-empty array of document-level validation hints (section 12).
6. Model Kinds
Section titled “6. Model Kinds”| Kind | Meaning |
|---|---|
entry |
Standalone content. |
component |
Reusable composable block. |
object |
Embedded structure. |
taxonomy |
Classification model. |
settings |
Singleton or global configuration. |
7. Field Specification
Section titled “7. Field Specification”Example:
- id: title type: string required: trueRequired Field Properties
Section titled “Required Field Properties”idtype
Optional Field Properties
Section titled “Optional Field Properties”namedescriptionrequiredlocalisationdefaultlistvalidationseditorialrelationobjectTypetargetsvaluesrichTextConfigtranslationHints
8. Canonical Types
Section titled “8. Canonical Types”stringtextnumberbooleandatedatetimeslugenumrichTextassetjsonobjectreference
9. Type Rules
Section titled “9. Type Rules”Object Fields
Section titled “Object Fields”Object fields represent embedded structures.
type: objectobjectType: seo-metadataRequirements:
typemust beobjectobjectTypemust be present
Reference Fields
Section titled “Reference Fields”Reference fields represent links to one or more target models.
type: referencetargets: [article]list: truerelation: ownership: linkedRequirements:
typemust bereferencetargetsmust be presentlist: trueindicates a repeatable reference fieldrelation.cardinalityis a legacy alias accepted for compatibility
Enum Fields
Section titled “Enum Fields”Enum fields constrain values to a fixed set of allowed strings.
type: enumvalues: [draft, review, published]Requirements:
typemust beenumvaluesmust be present
Rich Text Fields
Section titled “Rich Text Fields”Rich text fields represent formatted editorial content with optional capability constraints.
type: richTextrichTextConfig: marks: [bold, italic] blocks: [paragraph, heading-1, quote] embeds: - kind: asset - kind: reference targets: [callout]Requirements:
richTextConfigis only valid whentypeisrichText- omitted
richTextConfigmeans translator-defined default rich text capabilities marksandblocksare optional allowlists of translator-recognised capability tokensembedsis an optional allowlist of supported embed definitions- embed
kindmust beassetorreference referenceembeds must includetargets
10. Relationship Specification
Section titled “10. Relationship Specification”Example:
relation: ordered: true uniqueItems: true ownership: containedRelationship Fields
Section titled “Relationship Fields”| Field | Type | Description |
|---|---|---|
ordered |
boolean | Whether item order matters. |
uniqueItems |
boolean | Whether duplicates are allowed. |
minItems |
number | Minimum allowed items. |
maxItems |
number | Maximum allowed items. |
ownership |
enum | linked or contained. |
Legacy compatibility note:
relation.cardinalityremains accepted onreferencefields as a deprecated alias for repeatability- tooling should normalise
relation.cardinality: manytolist: true - tooling should treat
relation.cardinality: oneas singular whenlistis omitted
11. List Handling
Section titled “11. List Handling”| Scenario | Approach |
|---|---|
| Primitive lists | list: true |
| Object lists | list: true |
| Reference lists | list: true |
Legacy cardinality mapping:
| Legacy Input | Canonical Interpretation |
|---|---|
relation.cardinality: one |
singular field |
relation.cardinality: many |
list: true |
12. Validation Specification
Section titled “12. Validation Specification”Example:
validations: minLength: 5 maxLength: 100Supported Validation Keys in 1.3.0-beta.1
Section titled “Supported Validation Keys in 1.3.0-beta.1”minLengthmaxLengthregexminmaxintegerOnlyminItemsmaxItemsuniqueItemsmimeTypesdimensionsfileSize
Validation semantics are intentionally lightweight in 1.3.0-beta.1. CMS translators may need to map these into platform-specific constraints. See the deeper discussion in docs/validations.md.
Document-Level Validation Hints
Section titled “Document-Level Validation Hints”An optional model-level validationHints array declares conditional and cross-field
validation intent. It is non-authoritative: a valid hint does not itself enforce
content constraints. CMMF defines its declaration and meaning, not an evaluation
engine. Malformed declarations are invalid CMMF; content that fails a well-formed
hint does not invalidate the model definition. Field-level constraints continue
to belong in field-level validations.
validationHints: - id: external-requires-source description: External articles must provide a source URL. when: field: article_type equals: external then: require: [source_url]The referenced fields must be declared in the same model’s fields array.
Hint Properties
Section titled “Hint Properties”| Property | Type | Required | Meaning |
|---|---|---|---|
id |
string | yes | Unique within the model; uses the model/field ID syntax. |
description |
string | yes | Human-readable intent, containing at least one non-whitespace character. |
severity |
enum | no | error (default), warning, or info; intended severity of a content violation, not translation failure. |
when |
condition | no | Trigger for a structured consequence. Omission means unconditional. |
then |
action object | when when is present |
Structured assertions. |
expression |
expression object | no | A complete rule in an explicitly named dialect. |
Exactly one representation is permitted per hint:
- structured:
then, optionally withwhen - expression:
expression, with neitherwhennorthen - prose: neither
when,then, norexpression
Unknown properties in hints, predicates, combinators, actions, and expression
wrappers are invalid. This closed vocabulary does not restrict dialect-specific
properties inside expression.rule.
Conditions
Section titled “Conditions”A predicate contains field (a direct field ID) and exactly one operator:
| Operator | Operand | Meaning |
|---|---|---|
equals, notEquals |
string, number, boolean, or null | Type-sensitive scalar equality or inequality; no coercion. |
in, notIn |
non-empty array of unique scalars | Scalar value belongs, or does not belong, to the set; type-sensitive. |
isEmpty, isNotEmpty |
literal true |
Value is empty or non-empty. |
matches |
regex string | Plain-text value matches an ECMAScript pattern, without delimiters or flags; substring matching unless anchored. |
gt, gte, lt, lte |
number | Numeric comparison with a constant. |
Alternatively a condition is exactly one combinator, without field or other keys:
allOf: [condition, ...]— every condition holds; array must be non-emptyanyOf: [condition, ...]— at least one condition holds; array must be non-emptynot: condition— logical negation
Combinators may nest recursively; no fixed nesting depth is imposed by the format.
Operator compatibility is a semantic requirement:
equals,notEquals,in, andnotInapply only to singularstring,text,slug,enum,number,boolean,date, anddatetimefields. Non-null operands must match the field’s scalar type: number fornumber, boolean forboolean, string for the others. Null is allowed as a literal comparison value.matchesapplies only to singularstring,text,slug, andenumfields. Patterns must be syntactically valid. A translator unable to preserve pattern behaviour must record the loss rather than silently substituting a pattern.- Numeric comparisons apply only to singular
numberfields. They do not compare date strings or coerce text to numbers. - Emptiness predicates and all actions support every field type, including lists.
- Repeatability follows
listand the legacy reference cardinality rules in section 11. Scalar operators are not list-membership operators.
Only direct field IDs in this model may be referenced. Nested paths, inspecting list elements, field-to-field comparisons, and cross-document lookups are outside the structured vocabulary in this beta.
Empty and Missing Values
Section titled “Empty and Missing Values”Empty means: the field is absent, or its value is null, the empty string "",
or an empty list []. false, 0, whitespace-only strings, and objects (including
{}) count as non-empty. This is a presence test, not a test of content validity.
An absent field makes every comparison predicate false, including notEquals
and notIn. Use isEmpty explicitly when absence should trigger a condition.
An explicit null can match a null literal; it differs from an absent field for
comparisons. A present value with an incompatible type makes a comparison false,
including negative comparisons. Other empty values are compared normally where
the operator supports their type. not always negates the inner condition,
including a false condition caused by an absent field.
Actions
Section titled “Actions”then is a non-empty object containing one or more of these actions. Every action
contains a non-empty array of unique direct field IDs. All actions in the object
apply together when when holds, or unconditionally if when is omitted.
| Action | Meaning |
|---|---|
require |
Every listed field must be non-empty, not merely have a key. |
forbid |
Every listed field must be empty. |
atLeastOneOf |
At least one listed field must be non-empty. |
atMostOneOf |
At most one listed field may be non-empty. |
exactlyOneOf |
Exactly one listed field must be non-empty. |
These are advisory assertions, not mutations: forbid must not delete content.
Hints never weaken field-level required or validations. Tools may diagnose
contradictory intent; this beta does not require a satisfiability solver.
Expressions
Section titled “Expressions”validationHints: - id: quarterly-price-bound description: Quarterly price must exceed three times the monthly price. expression: dialect: jsonlogic rule: {">": [{"var": "quarterly_price"}, {"*": [3, {"var": "monthly_price"}]}]}expression requires dialect and rule. Dialect names use lower-kebab-case
matching ^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$; the vocabulary is open. rule may be
any JSON value allowed by that dialect. jsonlogic is an example of an existing
language, not a preferred language or a core CMMF dependency.
An expression is a complete assertion under its dialect’s semantics, rather than
a trigger for a separate then. CMMF defines no coercion, truthiness, or emptiness
overrides for expression languages. No evaluator or dialect support is required.
Expressions are explicitly non-portable and best-effort; no core CMMF tool may
assume they are arbitrary executable scripts. Tools must not execute unknown
dialects. Their scope is still one document: cross-document queries and external
side effects are out of scope. Dialect-aware tools own deeper rule validation.
Declaration Checks and Translation
Section titled “Declaration Checks and Translation”JSON Schema checks declaration shape, including required IDs, closed vocabularies, and exclusive representations. Semantic checks must additionally verify unique hint IDs, existing field references, operator/type compatibility, operand types, and regex syntax. Neither check evaluates content. Prose and expressions cannot be checked for arbitrary field references by the core schema or semantic checker.
Every hint, including prose-only hints and unknown expression dialects, must receive
a translation disposition: mapped, degraded, or unmapped, identifying both
model ID and hint ID and giving a reason. Editorial guidance without preservation
of the declared checks is degraded, not mapped. See the
beta translation contract.
13. Editorial Metadata
Section titled “13. Editorial Metadata”Model-level example:
editorial: labelField: title preview: title: title description: summary image: heroImageField-level example:
editorial: helpText: Used in URLsEditorial metadata is non-structural and supports authoring and presentation concerns.
14. Governance Metadata
Section titled “14. Governance Metadata”Example:
governance: owner: platform-team status: active maturity: stableGovernance metadata is optional and is intended for operational ownership and lifecycle signalling.
15. Translation Hints
Section titled “15. Translation Hints”Example:
translationHints: preferredRepresentation: embeddedTranslation hints are non-authoritative. They inform downstream translators without changing the core meaning of the schema.
16. Rules and Constraints
Section titled “16. Rules and Constraints”Model and field IDs:
- must be unique within their scope
- must be lowercase
- must use only alphanumeric characters,
_, or-
Object Fields
Section titled “Object Fields”- must include
objectType
Reference Fields
Section titled “Reference Fields”- must include
targets - should use
list: truewhen repeatable - may include legacy
relation.cardinalityfor compatibility - conflicting
listandrelation.cardinalityvalues should be treated as invalid
Enum Fields
Section titled “Enum Fields”- must include
values
Rich Text Fields
Section titled “Rich Text Fields”richTextConfigmust only appear onrichTextfieldsrichTextConfig.embeds[*].targetsmust be present when embedkindisreference
Document-Level Validation Hints
Section titled “Document-Level Validation Hints”validationHints, when present, must be non-empty- every hint must have an ID unique within its model and a meaningful description
- structured conditions and actions must reference fields in the same model
- operator and operand types must follow section 12
- structured, expression, and prose representations must not be mixed in one hint
- a malformed declaration is invalid regardless of its intended content severity
17. Non-Goals for 1.3.0-beta.1
Section titled “17. Non-Goals for 1.3.0-beta.1”The following are explicitly out of scope in 1.3.0-beta.1:
- permissions
- workflows
- environments
- CMS UI configuration
- custom logic
- computed fields
Document-level validation hints are declarative only. This beta does not define an evaluation engine, run arbitrary scripts, or support rules spanning documents. Named expression dialects are non-portable escape hatches, not core custom logic.
18. Translation Contract Guidance
Section titled “18. Translation Contract Guidance”Translation is intentionally separate from the core specification because it is not fully deterministic across CMS platforms.
At minimum, a translation contract should define:
- the CMMF input shape
- the target platform schema output
- a decisions log describing translator choices
- which translation decisions are fixed versus configurable
Examples of translator variation include:
- translating contained references into embedded objects
- translating contained references into separate content types
- normalising legacy
relation.cardinalityusage tolist - applying strict versus optimised output strategies