The M21 Spec Format

A spec combines machine-readable data models and semantic interfaces with architectural prose and executable behavioral features.

Anatomy of a spec file

---
name: persistence
description: SQLite database layer for local storage
group: infrastructure
tags: [database, storage]
depends_on:
  - name: bootstrap
    uses: [project-scaffolding, health-endpoint]
features: features/persistence/
---

# Persistence

## Data model
```m21-model
entities:
  Record:
    identity: id
    fields:
      id: { type: string, required: true }
```

## Interfaces
```m21-interface
operations:
  store-record:
    input: Record
    output: Record
```

## Contract
Provides durable local storage without owning record content.

The ordered contract stack

  1. Data model — entities, fields, relationships, states, and structural constraints.
  2. Interfaces — operations, inputs, outputs, failures, effects, and events.
  3. Contract — responsibilities, non-goals, invariants, dependencies, and decisions.
  4. Features — executable examples of observable behavior.

Sections are optional when irrelevant, but present sections follow this order. Use fenced m21-model and m21-interface YAML blocks for declarations that M21 must enforce.

Supported structural field types

string, number, integer, boolean, object, array, enum, and reference. Local references use an entity name; cross-spec references use spec-name.Entity and require a declared dependency.

m21 validate ./spec checks block syntax, identifiers, field types, entity references, and cross-spec model dependencies. m21 model ./spec --json exports the normalized registry; m21 schema ./spec emits JSON Schema.

Frontmatter fields

Field Required Type Description
name Yes string Unique identifier. How other specs reference it in depends_on.
description No string Short summary. Shown in the graph info panel.
group No string Logical grouping. Specs in the same group are visually clustered.
tags No string[] Tags for filtering and categorization.
depends_on No array Dependencies. Supports plain strings or {name, uses} objects.
features No string Relative path to a directory of .feature files.

Dependencies

The depends_on field supports two formats that can be mixed freely:

Simple format

depends_on:
  - bootstrap
  - config

Rich format (with feature references)

depends_on:
  - name: bootstrap
    uses: [project-scaffolding, health-endpoint]
  - name: persistence
    uses: [data-storage, query-interface]

The uses array references Feature: names declared in the parent spec's .feature files. This creates a traceable contract — you know exactly which capabilities each module relies on.

Feature files

Features are defined in Gherkin .feature files. They provide executable examples of semantic interfaces and guarantees. Other specs use feature names as behavioral capability identifiers through uses.

Naming rules

Example feature file

Feature: data-storage
  CRUD operations for persistent entities.

  Scenario: Store and retrieve an entity
    Given an empty data store
    When I store entity "foo" with value "bar"
    Then retrieving "foo" returns "bar"

Groups

Specs with the same group value are visually clustered in the graph with a colored hull behind them. Use groups to organize by architectural layer or domain:

Composability

Specs are designed as composable modules. The dependency graph captures not just what depends on what, but which features each module needs from its dependencies.

  1. Provider spec owns models and semantic interfaces, then demonstrates behavior through .feature files
  2. Consumer spec declares which features it needs via uses
  3. The graph visualizes these contracts as labeled edges

This makes it clear when a dependency change might break downstream consumers — you can see exactly which features are in use.

Example project

# spec/bootstrap.md
name: bootstrap   group: foundation
features: features/bootstrap/

# spec/persistence.md
name: persistence   group: infrastructure
depends_on: [{name: bootstrap, uses: [project-scaffolding]}]
features: features/persistence/

# spec/auth.md
name: auth   group: infrastructure
depends_on: [{name: bootstrap, uses: [health-endpoint]}]
features: features/auth/

# spec/repos.md
name: repos   group: data
depends_on:
  - {name: persistence, uses: [data-storage, query-interface]}
  - {name: auth, uses: [user-login]}