Skip to content
Format referenceCMMF 1.3.0-beta.1 · Experimental

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.

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

The format describes what the model means, not how a specific CMS stores or renders it.

References and composition must be described directly, including relationship intent where relevant.

The core schema defines structure and intent. CMS-specific choices belong in a translation layer.

The same CMMF input should produce the same structural interpretation every time.

/examples
manifest.yaml
/models
page.yaml
article.yaml
person.yaml

Example:

specVersion: "1.3.0-beta.1"
namespace: example.project
modelsPath: ./models
defaults:
required: false
localisation: false
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: 1 to indicate the original v1 release
  • semver-based manifests should use a quoted string such as "1.3.0-beta.1"
Field Type Description
required boolean Default field requiredness.
localisation boolean Default field localisation behaviour.

Example:

id: page
name: Page
kind: entry
fields: []
Field Description
id Unique identifier for the model.
name Human-readable model name.
kind Model kind.
fields Array of field definitions.
  • description
  • tags
  • localisation
  • singleton
  • editorial
  • governance
  • translationHints
  • validationHints — non-empty array of document-level validation hints (section 12).
Kind Meaning
entry Standalone content.
component Reusable composable block.
object Embedded structure.
taxonomy Classification model.
settings Singleton or global configuration.

Example:

- id: title
type: string
required: true
  • id
  • type
  • name
  • description
  • required
  • localisation
  • default
  • list
  • validations
  • editorial
  • relation
  • objectType
  • targets
  • values
  • richTextConfig
  • translationHints
  • string
  • text
  • number
  • boolean
  • date
  • datetime
  • slug
  • enum
  • richText
  • asset
  • json
  • object
  • reference

Object fields represent embedded structures.

type: object
objectType: seo-metadata

Requirements:

  • type must be object
  • objectType must be present

Reference fields represent links to one or more target models.

type: reference
targets: [article]
list: true
relation:
ownership: linked

Requirements:

  • type must be reference
  • targets must be present
  • list: true indicates a repeatable reference field
  • relation.cardinality is a legacy alias accepted for compatibility

Enum fields constrain values to a fixed set of allowed strings.

type: enum
values: [draft, review, published]

Requirements:

  • type must be enum
  • values must be present

Rich text fields represent formatted editorial content with optional capability constraints.

type: richText
richTextConfig:
marks: [bold, italic]
blocks: [paragraph, heading-1, quote]
embeds:
- kind: asset
- kind: reference
targets: [callout]

Requirements:

  • richTextConfig is only valid when type is richText
  • omitted richTextConfig means translator-defined default rich text capabilities
  • marks and blocks are optional allowlists of translator-recognised capability tokens
  • embeds is an optional allowlist of supported embed definitions
  • embed kind must be asset or reference
  • reference embeds must include targets

Example:

relation:
ordered: true
uniqueItems: true
ownership: contained
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.cardinality remains accepted on reference fields as a deprecated alias for repeatability
  • tooling should normalise relation.cardinality: many to list: true
  • tooling should treat relation.cardinality: one as singular when list is omitted
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

Example:

validations:
minLength: 5
maxLength: 100
  • minLength
  • maxLength
  • regex
  • min
  • max
  • integerOnly
  • minItems
  • maxItems
  • uniqueItems
  • mimeTypes
  • dimensions
  • fileSize

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.

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.

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 with when
  • expression: expression, with neither when nor then
  • prose: neither when, then, nor expression

Unknown properties in hints, predicates, combinators, actions, and expression wrappers are invalid. This closed vocabulary does not restrict dialect-specific properties inside expression.rule.

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-empty
  • anyOf: [condition, ...] — at least one condition holds; array must be non-empty
  • not: 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, and notIn apply only to singular string, text, slug, enum, number, boolean, date, and datetime fields. Non-null operands must match the field’s scalar type: number for number, boolean for boolean, string for the others. Null is allowed as a literal comparison value.
  • matches applies only to singular string, text, slug, and enum fields. 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 number fields. They do not compare date strings or coerce text to numbers.
  • Emptiness predicates and all actions support every field type, including lists.
  • Repeatability follows list and 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 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.

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.

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.

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.

Model-level example:

editorial:
labelField: title
preview:
title: title
description: summary
image: heroImage

Field-level example:

editorial:
helpText: Used in URLs

Editorial metadata is non-structural and supports authoring and presentation concerns.

Example:

governance:
owner: platform-team
status: active
maturity: stable

Governance metadata is optional and is intended for operational ownership and lifecycle signalling.

Example:

translationHints:
preferredRepresentation: embedded

Translation hints are non-authoritative. They inform downstream translators without changing the core meaning of the schema.

Model and field IDs:

  • must be unique within their scope
  • must be lowercase
  • must use only alphanumeric characters, _, or -
  • must include objectType
  • must include targets
  • should use list: true when repeatable
  • may include legacy relation.cardinality for compatibility
  • conflicting list and relation.cardinality values should be treated as invalid
  • must include values
  • richTextConfig must only appear on richText fields
  • richTextConfig.embeds[*].targets must be present when embed kind is reference
  • 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

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.

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.cardinality usage to list
  • applying strict versus optimised output strategies