DevMatrixDocumentation
Back to Home
Language Reference

DMX Specification Language

The complete reference for writing DevMatrix specifications. From data types and annotations to flows, state machines, and infrastructure.

Overview

DMX (DevMatrix Specification Language) is a declarative language for defining full-stack microservices. A single .dmx file describes entities, APIs, business flows, state machines, security, infrastructure, and more — then compiles deterministically to production-ready code. DMX is not a template engine. It is a compiler IR: every construct maps to concrete backend code through deterministic passes. There is no interpolation, no scripting, and no runtime interpretation.

Lexical Structure

DMX source files use UTF-8 encoding. The language is whitespace-insensitive (indentation is conventional, not syntactic). Blocks are delimited by curly braces {}.

Comments

Line comments start with //. Block comments use /* ... */.
Comments
// This is a line comment

/* This is a
   block comment */

Strings

Strings are double-quoted only. Backslash escapes are supported: \", \\, \n.

Numbers

Integer literals: 42, 0. Float literals: 3.14. No hex/octal support.

Identifiers

PascalCase for entities and types (UserProfile). snake_case for fields and keywords (created_at). UPPER_SNAKE_CASE for enum values (ACTIVE, PENDING_REVIEW).

Operators

= — assignment. -> — state transition or mapping. * — wildcard/all.

Annotations

Annotations start with @ followed by an identifier. Some accept parenthesized arguments: @default("active"), @fk(User.id).

Dollar Tokens

Runtime references prefixed with $. Simple: $input, $context. Dotted: $computed.now, $input.email.

Data Types

DMX supports 18 data types that map to database column types and API schema types.

NameDescription
UUIDUniversally unique identifier (v4)
StringVariable-length text, up to 255 characters
TextUnlimited-length text (CLOB/TEXT)
IntegerWhole number (32-bit signed)
FloatIEEE 754 floating-point
DecimalArbitrary-precision decimal
Booleantrue or false
DateCalendar date without time (YYYY-MM-DD)
DateTimeDate and time with timezone (ISO 8601)
TimeTime of day without date
JSONArbitrary JSON object or array
BytesBinary data (BLOB)
ArrayOrdered collection of a single type
EnumEnumerated set of named values
CharFixed-length character string
PointGeographic point (latitude, longitude)
PolygonGeographic polygon boundary
GeometryArbitrary geometric shape

Every entity field has a name, a type, and optional annotations.

Field declarations with types
entity User {
  id          UUID     @pk @default($computed.uuid)
  email       String   @unique @not_null
  name        String   @not_null
  bio         Text     @nullable
  age         Integer  @check("age >= 0")
  balance     Decimal  @default(0)
  is_active   Boolean  @default(true)
  joined_at   DateTime @default($computed.now)
  metadata    JSON     @nullable
  role        Enum(ADMIN, MEMBER, GUEST) @default(MEMBER)
  location    Point    @nullable
}

Annotations

Annotations modify the behavior of fields, entities, APIs, state machines, and ClickHouse columns.

Field Annotations

NameDescriptionSyntax
@pkPrimary key@pk
@not_nullNOT NULL constraint@not_null
@uniqueUnique constraint@unique
@nullableAllows NULL values@nullable
@defaultDefault value@default("value") or @default($computed.now)
@fkForeign key reference@fk(Entity.field)
@checkCheck constraint expression@check("age >= 18")
@requiredRequired in API input@required
@sensitivePII / secrets — excluded from logs@sensitive
@computedServer-computed, not in API input@computed
@json_listStore as JSON array column@json_list
@immutableCannot be updated after creation@immutable
@indexedCreate a database index@indexed

Entity Annotations

NameDescriptionSyntax
@aggregate_rootDDD aggregate root — owns child entities@aggregate_root
@tenancyTenant isolation strategy@tenancy("row") or @tenancy("schema")
@descriptionHuman-readable description@description("User accounts")
@auditAuto-generate created_at / updated_at / deleted_at@audit
@soft_deleteSoft delete (set deleted_at) instead of hard delete@soft_delete
@platform_scopeNot tenant-scoped (platform-level entity)@platform_scope
@append_onlyInsert-only table (no UPDATE or DELETE)@append_only
@append_only_afterAppend-only after a condition is met@append_only_after("status = CLOSED")
@unique_togetherComposite unique constraint@unique_together(field_a, field_b)
@checkEntity-level check constraint@check("start_date < end_date")
@relationDefine relationship to another entity@relation("has_many", Target)

API Annotations

NameDescriptionSyntax
@entityBind API to an entity@entity(User)
@paginatedEnable pagination@paginated
@statusOverride HTTP status code@status(201)
@triggersEmit events on action@triggers(user_created)

State Machine Annotations

NameDescriptionSyntax
@rolesRestrict transition to roles@roles(ADMIN, MANAGER)
@guardGuard condition for transition@guard("amount > 0")

ClickHouse Annotations

NameDescriptionSyntax
@low_cardinalityClickHouse LowCardinality optimization@low_cardinality
@piiMark column as PII for compliance@pii

Dollar Tokens ($)

Runtime value references used in defaults, flow steps, and computed fields. The compiler resolves these to actual code.

NameDescriptionSyntax
$inputCurrent request/step input data$input.email, $input.password
$contextExecution context (authenticated user, tenant, request metadata)$context.user_id, $context.tenant_id
$instanceCurrent entity instance (in flows and state machines)$instance.status, $instance.id
$resultResult from the previous flow step$result.id, $result.token
$computed.nowServer timestamp (UTC) — 0 args@default($computed.now)
$computed.now_plus_minutesTimestamp + N minutes — 1 arg$computed.now_plus_minutes(15)
$computed.now_minus_minutesTimestamp − N minutes — 1 arg$computed.now_minus_minutes(5)
$computed.now_plus_hoursTimestamp + N hours — 1 arg$computed.now_plus_hours(24)
$computed.now_minus_hoursTimestamp − N hours — 1 arg$computed.now_minus_hours(72)
$computed.now_plus_daysTimestamp + N days — 1 arg$computed.now_plus_days(7)
$computed.now_minus_daysTimestamp − N days — 1 arg$computed.now_minus_days(30)
$computed.token_expiryDefault 24-hour expiry — 0 argsexpires_at = $computed.token_expiry
$computed.uuidGenerate UUID v4 — 0 args@default($computed.uuid)
$computed.random_token32-byte URL-safe random token — 0 argsreset_token = $computed.random_token
$computed.recovery_codesList of N 8-byte recovery codes — 1 arg$computed.recovery_codes(10)
$computed.token_hashSHA-256 hex digest of token — 1 argrefresh_hash = $computed.token_hash($result.refresh_plaintext)
$computed.hashAlias of token_hash; SHA-256 hex digest — 1 arg$computed.hash($input.payload)
$computed.verify_hashReturns bool — sha256(value) == hash — 2 args$computed.verify_hash($instance.token_hash, $input.token)
$computed.hash_passwordBCrypt hash via pwd_context — 1 argpassword_hash = $computed.hash_password($input.password)
$computed.bcryptAlias of hash_password; BCrypt hash — 1 argpassword_hash = $computed.bcrypt($input.password)
$computed.bcrypt_verifyReturns bool — pwd_context.verify — 2 args (crypto-safe for passwords)$computed.bcrypt_verify($input.password, $instance.password_hash)
$computed.totp_secretGenerate base-32 TOTP secret — 0 argsmfa_secret = $computed.totp_secret
$computed.verify_totpReturns bool — verify TOTP code — 2 args$computed.verify_totp($instance.mfa_secret, $input.code)
$computed.decode_jwtDecode and validate JWT — 1 argclaims = $computed.decode_jwt($input.token)
$computed.jwt_signIssue JWT access token — 3 args (subject, tenant_id, role). Delegates to create_access_token(); claims declared explicitly in the spec, no implicit context-pickup.access_token = $computed.jwt_sign($instance.id, $context.tenant_id, "PATIENT_PORTAL_ACCOUNT")
$computed.system_admin_role_idTenant-scoped SYSTEM_ADMIN role UUID lookup — 1 arg (tenant_id). Companion gate G_TENANT_ROLE_ONBOARDING_PROVIDED enforces the seed flow.role_id = $computed.system_admin_role_id($context.tenant_id)
$computed.nc_sequenceTenant-scoped monotonic NC number — 1 arg (tenant_id). Each tenant's counter increments independently via _sequence_state UPSERT.nc_number = $computed.nc_sequence($context.tenant_id)
$computed.protocol_sequenceTenant-scoped monotonic admission/protocol number — 1 arg (tenant_id). Each tenant's counter increments independently via _sequence_state UPSERT.protocol_number = $computed.protocol_sequence($context.tenant_id)

Top-Level Blocks

DMX specs are composed of top-level blocks. Each block defines a different concern of the service.

service

The root block that defines a microservice. Contains all other blocks.
Service definition
service UserService {
  version = "1.0.0"
  port = 8000
  api_prefix = "/api/v1"
  database = "postgresql"

  // ... entities, api, flows, etc.
}

identity

Optional nested sub-block inside service { ... } that lets the spec author override canonical-derived service-identity fields. Mirrors the MicroservicesIR sub-IR hierarchy (ServiceIdentityIR / GatewayIR / ArchitectureIR). Each attribute is closed-taxonomy parse-time enforced. When the block is absent the producer derives every field canonically (service_id from the service block name, service_slug + internal_hostname from the canonical lowercase slug, internal_port from the infrastructure block, etc.). When present, every set attribute lands on the corresponding sub-IR overridden_fields frozenset sentinel for cross-build provenance.

All 12 spec-declarable attrs in a single block. Each sub-block keeps the canonical-strict closed taxonomy enforcement (GATEWAY_MODE = passthrough | auth_precheck; ARCHITECTURE_MODE = standalone | microservices | mixed; ARCHITECTURE_MODE_SOURCE = explicit | inferred | default).

Identity overrides — full surface
service AuthService {
  version    = "1.0.0"
  port       = 8000
  api_prefix = "/api"

  identity {
    service_name      = "Auth Service"
    service_version   = "2.4.1"
    service_slug      = "auth-svc"
    internal_hostname = "auth-svc.svc.cluster.local"
    internal_port     = 8081
    description       = "identity overrides"

    gateway {
      enabled          = true
      public_port      = 8443
      public_base_path = "/v2"
      mode             = auth_precheck
    }

    architecture {
      mode        = microservices
      mode_source = explicit
    }
  }
}

Spec authors only pin the attributes they want to override; the rest canonical-derive. Here the platform pins a service version explicitly, leaving every other identity field on its canonical default.

Identity overrides — single attribute
service AuthService {
  version    = "1.0.0"
  port       = 8000
  api_prefix = "/api"

  identity {
    service_version = "2.4.1"
  }
}

entity

Defines a data model. Fields have a name, type, and optional annotations. Entities compile to database tables, ORM models, and Pydantic schemas.
Entity with annotations
entity Order @audit @soft_delete {
  id          UUID      @pk @default($computed.uuid)
  customer_id UUID      @fk(Customer.id) @not_null
  total       Decimal   @not_null @check("total >= 0")
  status      Enum(DRAFT, PENDING, PAID, SHIPPED, CANCELLED) @default(DRAFT)
  notes       Text      @nullable
}

api

Defines REST, GraphQL, or WebSocket endpoints for an entity.
REST API
api REST @entity(Order) @paginated {
  // Standard CRUD endpoints are generated automatically
  // Custom endpoints:
  POST   "/orders/{id}/cancel"  @status(200) @triggers(order_cancelled)
  GET    "/orders/summary"      @roles(ADMIN)
}

flow

Multi-step business process. Each step has an action, target entity, and field mappings. Flows compile to service-layer functions with transaction management.
Registration flow
flow RegisterUser {
  step validate_input {
    action = validate
    target = User
    mapping {
      email = $input.email
      password = $input.password
    }
  }

  step create_user {
    action = create
    target = User
    mapping {
      id = $computed.uuid
      email = $input.email
      password = $computed.hash_password($input.password)
      created_at = $computed.now
    }
  }

  step generate_token {
    action = calculate
    expression = $computed.sign_jwt($result.id, $result.role)
    result_capture = "token"
  }
}

state_machine

Defines valid state transitions with guards and role restrictions. Compiles to a state machine implementation with validation.
Order state machine
state_machine OrderStatus {
  initial = DRAFT

  DRAFT -> PENDING @roles(MEMBER, ADMIN)
  PENDING -> PAID @guard("payment_confirmed == true")
  PAID -> SHIPPED @roles(ADMIN)
  SHIPPED -> DELIVERED
  PENDING -> CANCELLED @roles(MEMBER, ADMIN)
  DRAFT -> CANCELLED
}

validations

Validation rules applied to entity fields. Compile to both database constraints and API-level validation.
Validation rules
validations {
  email {
    format = "email"
    uniqueness = true
  }
  age {
    range = "0..150"
    presence = true
  }
  username {
    format = "^[a-zA-Z0-9_]{3,30}$"
    uniqueness = true
  }
}

security

Authentication, authorization, rate limiting, and password policies.
Security configuration
security {
  auth_scheme = "jwt"
  jwt_algorithm = "HS256"
  token_expiry_minutes = 60
  refresh_token_enabled = true
  password_hashing = "bcrypt"

  rate_limit {
    policy = "sliding_window"
    allow = 100
    for = "1m"
  }

  roles = [ADMIN, MEMBER, GUEST]
}

errors

Custom error definitions with HTTP status codes, categories, and messages.
Error definitions
errors {
  USER_NOT_FOUND {
    status = 404
    category = "not_found"
    message = "User not found"
  }
  INVALID_CREDENTIALS {
    status = 401
    category = "auth"
    message = "Invalid email or password"
  }
}

jobs

Background job definitions with scheduling, retry policies, and queue configuration.
Job definitions
jobs {
  cleanup_expired_tokens {
    schedule = "0 */6 * * *"
    timeout = "5m"
    retry {
      max_attempts = 3
      backoff = "exponential"
    }
  }
  send_daily_digest {
    schedule = "0 8 * * *"
    queue = "low_priority"
  }
}

notifications

Multi-channel notification configuration (email, SMS, WhatsApp, push).
Notification setup
notifications {
  providers {
    email { adapter = "smtp" }
    sms   { adapter = "twilio" }
    push  { adapter = "firebase" }
  }
  order_confirmed {
    channels = [email, push]
    recipient = $instance.customer.email
    template = "order_confirmed"
    locale = $context.locale
  }
}

file_storage

File upload configuration with size limits, type restrictions, and CDN.
File storage
file_storage {
  provider = "s3"
  bucket = "my-app-uploads"
  max_size = "10MB"
  allowed_types = ["image/png", "image/jpeg", "application/pdf"]
  virus_scan = true
  cdn_enabled = true
}

infrastructure

Docker, Redis, RabbitMQ, Celery, API gateway, CORS, and deployment configuration.
Infrastructure config
infrastructure {
  docker {
    compose_version = "3.8"
    base_image = "python:3.12-slim"
  }
  redis {
    broker = true
    cache = true
    pool_size = 10
  }
  celery {
    concurrency = 4
    queue = "default"
  }
  cors {
    allow = ["https://app.example.com"]
  }
}

Canonical message broker block — AMQP 0.9.1 with vhost isolation, env-bound credentials, optional TLS, declared exchanges + queues with DLQ + quorum-queue HA replication, management plugin, cluster discovery, publisher confirms + mandatory routing.

RabbitMQ broker (Wave 1 + Wave 2 capabilities)
infrastructure {
  rabbitmq {
    vhost = "/tenant_a"
    user_env = "RABBITMQ_USER"
    password_env = "RABBITMQ_PASSWORD"
    use_tls = true
    tls_ca_path_env = "RABBITMQ_CA_PATH"
    pool_size = 10
    max_overflow = 5
    heartbeat_seconds = 60
    prefetch_count = 50
    quorum_replication_factor = 3
    publisher_confirms = true
    mandatory_routing = true
    management {
      port = 15672
      user_env = "RABBITMQ_MGMT_USER"
      password_env = "RABBITMQ_MGMT_PASSWORD"
    }
    cluster {
      discovery_mode = "dns"
      static_peers = ["rmq-0", "rmq-1", "rmq-2"]
    }
    exchange "events" {
      type = "topic"
      durable = true
    }
    queue "events.q" {
      durable = true
      dead_letter_exchange = "events.dlx"
      dead_letter_routing_key = "events.dlq"
      max_length = 100000
      quorum = true
    }
  }
}

Canonical Kafka event-streaming block — SASL/SSL + env-bound credentials, optional TLS keystore/truststore, per-topic partitions + replication + min-in-sync + ACLs + retention, idempotent producer + canonical consumer group, optional Confluent Schema Registry binding. Compiler emits Docker Compose with KRaft mode (Zookeeper-less) + K8s StatefulSet broker cluster + optional Schema Registry sidecar.

Kafka event streaming (Wave 1 + Wave 2 capabilities)
infrastructure {
  kafka {
    bootstrap_servers_env = "KAFKA_BOOTSTRAP_SERVERS"
    security_protocol = "SASL_SSL"
    sasl_mechanism = "SCRAM-SHA-512"
    sasl_user_env = "KAFKA_SASL_USER"
    sasl_password_env = "KAFKA_SASL_PASSWORD"
    tls_truststore_path_env = "KAFKA_TLS_TRUSTSTORE_PATH"
    tls_truststore_password_env = "KAFKA_TLS_TRUSTSTORE_PASSWORD"
    consumer_group_id = "svc_a.consumer"
    auto_offset_reset = "earliest"
    producer_acks = "all"
    producer_idempotence = true
    compression_type = "zstd"
    schema_registry {
      url_env = "KAFKA_SCHEMA_REGISTRY_URL"
      auth_user_env = "SR_USER"
      auth_password_env = "SR_PASSWORD"
    }
    topic "events" {
      partitions = 6
      replication_factor = 3
      min_insync_replicas = 2
      retention_ms = 604800000
      cleanup_policy = "compact"
      acl_read_principals = ["User:svc_a"]
      acl_write_principals = ["User:svc_publisher"]
    }
  }
}

Canonical Elasticsearch block — cluster hosts env binding, HTTPS + cert verification + CA bundle, auth method (basic_auth / api_key / bearer_token) with secret_env binding, per-index tenant_prefix + shards/replicas + ILM lifecycle + ingest pipeline + mappings, ILM phases (hot/warm/cold/delete), snapshot repository, bulk batch + timeout, optional Watcher alerting. Compiler emits Python elasticsearch-py client + Docker Compose service + K8s StatefulSet + put_index_template / put_lifecycle installers.

Elasticsearch search/analytics (Wave 1 + Wave 2 capabilities)
infrastructure {
  elasticsearch {
    hosts_env = "ELASTICSEARCH_HOSTS"
    use_https = true
    verify_certs = true
    ca_bundle_path_env = "ELASTICSEARCH_CA_BUNDLE"
    rbac_roles = ["search_user", "index_admin"]
    bulk_batch_size = 1000
    bulk_timeout_seconds = 60
    watcher_enabled = false
    auth {
      method = "api_key"
      api_key_env = "ELASTICSEARCH_API_KEY"
    }
    index "logs" {
      tenant_prefix = "tenant_a"
      number_of_shards = 3
      number_of_replicas = 2
      min_insync_replicas = 2
      refresh_interval = "30s"
      lifecycle_policy = "logs-policy"
      ingest_pipeline = "enrich-logs"
    }
    ilm_policy "logs-policy" {
      phase "hot" { min_age = "0ms" }
      phase "warm" { min_age = "7d" }
      phase "delete" { min_age = "90d" }
    }
    snapshot_repository "primary" { type = "s3" }
    ingest_pipeline "enrich-logs" { description = "Add tenant tag" }
  }
}

platform

Multi-service platform orchestration. Declares modules with their compile-time dependencies; the compiler derives topological build order automatically.
Platform definition
platform "MyPlatform" {
  version = "1.0.0"

  modules {
    UserService         { spec = "user.dmx";         dependencies = [] }
    OrderService        { spec = "order.dmx";        dependencies = [UserService] }
    NotificationService { spec = "notification.dmx"; dependencies = [OrderService] }
  }

  shared_kernel { modules = [tenant_context, jwt_utils, event_bus, audit_decorator, observability] }

  interactions {
    "order-confirmed-notifies" {
      tier     = 1
      producer = OrderService
      consumer = NotificationService
      trigger  = event("order.confirmed")
      task     = "send_confirmation"
      queue    = "notifications"
    }
  }
}

events

Domain event definitions for event-driven communication between services.

tenant_config

Multi-tenancy configuration: isolation strategy, tenant resolution, and feature flags per tier.

workers (platform-scope, ADR-260)

Platform-scope worker topology: tiers, queue routing patterns, retry + dead-letter policies, concurrency, scaling hints. Declared inside platform { workers { ... } }. Superseded the per-service task_queue block (ADR-211).

row_level_isolation

Row-level security policies for data isolation.

sequences

Ordered sequence generators (e.g., invoice numbers).

service_observability

Metrics, distributed tracing, structured logging, and health endpoints.

object_storage

Platform-scope object storage topology — declares the cloud provider, credentials, and per-bucket configuration. Five providers are supported (closed taxonomy enforced parse-time): s3 / gcs / azure-blob / minio / cloudflare-r2. Each bucket carries name, region, owning_service, access_pattern (read/write/admin/shared), encryption_kind (SSE-S3/SSE-KMS/SSE-C), optional encryption_secret_ref (required for SSE-KMS+SSE-C), presigned_url_ttl_s, and lifecycle_rule blocks (transition/expiration with after_days). Cloudflare R2 rejects SSE-KMS at IR construction (R2 has no KMS integration).

permissions

Role-based and attribute-based access control definitions.

sagas

Distributed transaction orchestration with compensating actions. Each `saga declares a sequence of step definitions; on failure of any step, prior completed steps run their compensation action in reverse order. Two patterns supported: orchestration (default — central coordinator drives steps) and choreography (event-driven — each step subscribes to the previous step's completion event). Persistence: outbox (default — DB-backed state machine + transactional outbox table for event publishing in the same TX as business state) or in_memory_only (opt-in for non-critical sagas where crash recovery is not required). Brokers: none (in-process — orchestration only), redis (redis-streams), kafka (aiokafka). Choreography requires a non-none broker. Per-step action_handler and compensation_handler are fully-qualified Python references (e.g. src.services.payment.charge); when omitted the compiler defaults to src.services.sagas... idempotency_key_field is the request-payload field used as the unique key for retry / replay safety. max_retries per step overrides the saga-level default. DLQ topic + retention (integer + days|hours` unit) configure the dead-letter queue for failed events that exceed retries. Provided by ADR-319 Distributed Sagas Productive Closure.

Flow Actions

Actions available in flow steps. Each action maps to a specific operation on the target entity or system.

NameDescriptionSyntax
createCreate a new entity instanceaction = create
updateUpdate an existing entityaction = update
deleteDelete an entity instanceaction = delete
queryQuery entities with filtersaction = query
validateRun validation rulesaction = validate
extractExtract fields from dataaction = extract
calculateCompute derived valuesaction = calculate
state_changeTrigger a state machine transitionaction = state_change
external_callCall an external serviceaction = external_call
batchBatch multiple operationsaction = batch
exportExport data to a formataction = export

Trigger Functions

Functions used in @triggers annotations and event routing.

NameDescriptionSyntax
event()Emit a domain event@triggers(event("user_created"))
job()Enqueue a background job@triggers(job("send_welcome_email"))
state_change()Trigger a state machine transition@triggers(state_change("activate"))

Platform Spec

A platform spec declares the architecture of a multi-service application. It lives in a separate platform.dmx file and is never compiled directly — it provides context when compiling individual service specs.

Two file types in DMX: - Platform spec (platform.dmx): Declares shared infrastructure, lists all services/modules, defines compilation order, cross-service interactions, Celery workers, event bus, and infrastructure config. ONE per application. - Service spec (service_name.dmx): Defines ONE microservice — its entities, APIs, flows, security, state machines. The service "name" must match the module key in the platform's modules {} block. The compiler compiles service specs one at a time, using the platform spec as infrastructure context.

Platform-Level Blocks

NameDescriptionSyntax
versionPlatform version stringversion = "1.0.0"
platform_roles { }Compile-time RBAC role definitions (optional)
modules { }REQUIRED: service/module declarations. Each module's dependencies = [...] drive the compilation order — no explicit ordering block
interactions { }Cross-service communication: async event(...) and/or sync http(method=, path=) (optional)
celery { }Task queue configuration with named workers (optional)
event_bus { }Event streaming configuration (optional)
shared_kernel { }Shared kernel module selection (ADR-317 INV-317-1.b closed taxonomy 2026-05-15). modules accepts the 22 canonical productive plugin names: audit_decorator, base_repository, compliance_policy, encryption_policy, errors, event_bus, event_envelope, jwt_utils, module_gate, observability, protocol_counter, response_envelope, rls_policies, s2s_client, secrets, soft_delete, soft_delete_policy, sqlalchemy_ext, tenant_context, test_fixtures, traceability, trinity_policy. Non-canonical values rejected at parse time
feature_flags { }Platform-wide feature toggles (optional)
output { }Output directory configuration (optional)
validation { }Compilation validation rules (optional)
infrastructure { }API gateway, JWT, Redis, databases, ports (optional)
compliance { }Spec-declared compliance profiles per platform jurisdictional scope. Canonical registry (ADR-317 INV-317-1.b Op α Phase 1.B 2026-05-15): CCPA / FEDRAMP / GDPR / HIPAA / HITRUST / ISO-27001 / NIST-800-53 / OWASP-API / OWASP-WEB / PCI-DSS / SOC2 / SOX + enterprise jurisdictional extensions ISO_15189 / AFIP_ARCA / FABA_AOL / LEY_25_326 / LEY_17_132. Non-canonical framework names rejected at validate-time (COMPLIANCE_PROFILE_UNKNOWN) via registry-loader lookup. Each profile carries retention, encryption, audit, residency, subject-rights and 17 framework-detail attrs (ADR-255 / ADR-257 / ADR-317 E.2)
platform_scope_entitiesEntities shared across all tenants (no tenant_id)platform_scope_entities = [Currency, Country]
append_only_entitiesImmutable audit/log entitiesappend_only_entities = [AuditEvent, SecurityLog]

Module Attributes

Every module declared in modules {} supports these fields.

NameDescriptionSyntax
specREQUIRED. Path to the service spec filespec = "filename.dmx"
nameHuman-readable display name for UI/reportsname = "Billing Service"
layerDependency layer: 0 = foundation, higher depends on lowerlayer = 0
entitiesEntity count (informational, for validation/UI)entities = 10
dependenciesCompile-time deps: these must compile before this moduledependencies = [mod_a, mod_b]
service_typestandard | consumer | reader | stateless | aggregatorservice_type = standard
database_engineDatabase backend: postgresql (default) | clickhousedatabase_engine = postgresql
clickhouse_tablesClickHouse table names (when database_engine = clickhouse)clickhouse_tables = [fact_orders, dim_tenants]
runtime_dependenciesRuntime services beyond default postgresruntime_dependencies = [redis, clickhouse]
websocket_enabledService needs WebSocket supportwebsocket_enabled = true
token_also_issuesAdditional JWT token types this service issuestoken_also_issues = [patient_token, provider_token]
module_categoryDDD Strategic Design classification (closed taxonomy). Industry-agnostic. See module_category Values section for the 6 canonical keywords.module_category = core_domain

module_category Values (DDD Strategic Design)

Closed taxonomy from Domain-Driven Design Strategic Design (Eric Evans, Domain-Driven Design, 2003; Vaughn Vernon, Implementing Domain-Driven Design, 2013). Industry-agnostic — applies to any platform regardless of business vertical. Validated parse-time by the grammar; non-canonical keywords surface a parse error inline.

NameDescription
core_domainThe strategic differentiator. Where the business invests the most because it provides competitive advantage. Custom-built, evolves with strategy.
supporting_subdomainNecessary for the business but not differentiating. Usually built in-house when no off-the-shelf option fits; can sometimes be outsourced.
generic_subdomainSolved problem with widely available solutions (auth, notifications, audit, document storage). Buy / adopt / standardise rather than build.
integration_layerBridges to external systems / third-party adapters / gateway concerns. Maps the bounded contexts of partners to the platform's ubiquitous language.
presentation_layerUser-facing surfaces (web UI, portals, dashboards, BFFs that exist only to serve the UX). Composes responses from other modules; usually no own entities.
infrastructure_layerPlatform plumbing: control planes, deploy automation, observability scaffolding, secrets / cert / identity management at the platform level (not business-domain auth).

service_type Values

NameDescription
standardDefault. Normal microservice with entities, APIs, business logic
consumerEvent consumer with no REST API (e.g., data lake ingestor)
readerRead-only service querying external data (e.g., analytics API over ClickHouse)
statelessNo database, real-time processing (e.g., WebSocket dashboard)
aggregatorPortal API that composes responses from multiple services (no own entities)

Compilation Order

Derived automatically from each module's dependencies. There is no explicit ordering keyword — the compiler builds a topological DAG and rejects any legacy phase/ordering block.

control_plane has no deps so compiles first; identity depends on control_plane; registry and catalog depend on identity and compile in parallel; lab waits for both connectivity and preanalytic.

Dependency-driven order
modules {
  control_plane { spec = "control_plane.dmx"; dependencies = [] }
  identity      { spec = "identity.dmx";      dependencies = [control_plane] }
  registry      { spec = "registry.dmx";      dependencies = [identity] }
  catalog       { spec = "catalog.dmx";       dependencies = [identity] }
  connectivity  { spec = "connectivity.dmx";  dependencies = [registry] }
  preanalytic   { spec = "preanalytic.dmx";   dependencies = [connectivity] }
  lab           { spec = "lab.dmx";           dependencies = [connectivity, preanalytic] }
}

Celery Workers

Named worker definitions — each gets its own process with dedicated queues.

Define multiple workers with dedicated queue assignments.

Named workers
celery {
  broker_url      = "redis://redis:6379/0"
  result_backend  = "redis://redis:6379/1"
  task_serializer = "json"
  concurrency     = 2

  worker worker_fast {
    queues = ["fast", "ocr", "notifications"]
  }
  worker worker_standard {
    queues = ["default", "pdf", "billing"]
  }
  worker worker_beat {
    role = scheduler    // Celery Beat scheduler
  }
}

Interactions

Cross-service event-driven communication with tiered guarantees.

NameDescription
tier1 = always generated, 2 = generated if both modules compiled, 3 = optional/audit
patternfire_and_forget (default) or request_reply (bidirectional)
producer = *Wildcard: any module can produce this event (broadcast)

Standard one-way event between two modules.

Fire-and-forget event
interactions {
  "order-created" {
    tier     = 1
    producer = billing
    consumer = fulfillment
    trigger  = event("billing.order.created")
    task     = "process_order"
    queue    = "fulfillment-queue"
    payload {
      order_id UUID @required
      status   String
    }
  }
}

Infrastructure

API gateway, JWT, Redis, databases, pagination, and service ports.

Platform-wide infrastructure configuration.

Full infrastructure block
infrastructure {
  api_gateway {
    enabled = true
    type    = kong
    rate_limiting { enabled = true; requests_per_minute = 100 }
  }
  service_ports {
    control_plane = 8010
    identity      = 8001
  }
  jwt {
    algorithm              = "HS256"
    token_lifetime_minutes = 30
    issuer                 = "platform-name"
  }
  redis { host = "redis"; port = 6379 }
  databases {
    control_plane = "postgresql"
    datalake      = "clickhouse"
  }
  pagination {
    default_limit = 100
    max_limit     = 1000
  }
}

Canonical list-response pagination defaults. Drives the wrapper class, route Query() ge/le constraints, service signature, and BaseRepository.list defaults end-to-end (α-PAGINATION program / ADR-329). When omitted, the compiler falls back to default_limit = 100 + max_limit = 1000.

Pagination block
infrastructure {
  pagination {
    default_limit = 50    // default page size when client omits ?limit
    max_limit     = 500   // hard cap enforced via Query(le=...)
  }
}

Compliance

Platform-scope compliance profiles (ADR-255 / ADR-257 / ADR-317 INV-317-1.b Op α Phase 1.B 2026-05-15). Each profile is a registered framework identifier the spec author binds to the platform per its jurisdictional scope; the compiler treats the name as opaque taxonomy and reads concrete obligations from the canonical compliance_frameworks registry + the attributes declared inside the block. The Workshop validator queries `registry_loader.is_supported_compliance_framework`; non-canonical names are rejected at validate-time as COMPLIANCE_PROFILE_UNKNOWN. The full canonical set as of 2026-05-15: CCPA / FEDRAMP / GDPR / HIPAA / HITRUST / ISO-27001 / NIST-800-53 / OWASP-API / OWASP-WEB / PCI-DSS / SOC2 / SOX + enterprise jurisdictional extensions ISO_15189 / AFIP_ARCA / FABA_AOL / LEY_25_326 / LEY_17_132 (5 entries Op α Phase 1.B added). ADR-317 E.2 extends the per-profile attribute surface so the spec is the source of truth for the full ComplianceFrameworkIR shape — when an attribute is omitted the compiler falls back to the canonical default registry shipped under `src/dsl/compliance_framework_default_registry.py`.

NameDescriptionSyntax
scopeFree-form scope description (e.g. data residency rule).scope = "protected_health_information"
data_classesData classes governed by the profile.data_classes = ["PHI", "PII"]
retention_daysHard retention floor (days).retention_days = 2190
encryption_at_restMandate encryption-at-rest.encryption_at_rest = true
encryption_in_transitMandate TLS-everywhere.encryption_in_transit = true
audit_requiredMandate audit-trail emission.audit_required = true
access_review_daysPeriodic access-review interval (days).access_review_days = 90
subject_rightsSubject rights honoured (access / rectification / erasure / portability / restriction / objection).subject_rights = ["access", "rectification", "erasure"]
breach_notification_hoursBreach notification SLA (hours).breach_notification_hours = 72
residencyData residency jurisdiction code.residency = "US"
validation_controlsRequired control families (e.g. technical_safeguards, administrative).validation_controls = ["technical_safeguards", "administrative"]
legal_basisCitable regulatory anchor.legal_basis = "HIPAA-45-CFR-164"
full_nameHuman-readable framework name.full_name = "Health Insurance Portability and Accountability Act"
mode_aliasCompatibility alias for legacy SaaS payload modes.mode_alias = "covered-entity"
phi_keywordsPHI keyword set used by data-classification gates.phi_keywords = ["diagnosis", "patient_id", "mrn"]
phi_segmentsPath-segment patterns hinting PHI (e.g. URL or table fragments).phi_segments = ["/medical_records/", "/clinical/"]
pii_keywordsPII keyword set used by data-classification gates.pii_keywords = ["ssn", "passport", "drivers_license"]
pii_segmentsPath-segment patterns hinting PII.pii_segments = ["/profile/", "/identity/"]
financial_keywordsFinancial keyword set used by data-classification gates.financial_keywords = ["card_number", "iban", "swift"]
financial_segmentsPath-segment patterns hinting financial data.financial_segments = ["/payment/", "/wallet/"]
min_retention_daysMinimum retention floor when distinct from retention_days.min_retention_days = 365
requires_read_auditMandate read-side audit logging.requires_read_audit = true
requires_pii_maskingMandate PII masking in non-production environments.requires_pii_masking = true
requires_extended_retentionMandate retention beyond the platform default.requires_extended_retention = true
requires_immutable_auditMandate append-only audit storage (no UPDATE/DELETE).requires_immutable_audit = true
requires_encrypted_auditMandate encryption of the audit-trail at rest.requires_encrypted_audit = true
requires_actor_infoMandate actor identity capture in audit records.requires_actor_info = true
requires_digital_signatureMandate digital signature on audit records.requires_digital_signature = true
requires_request_metadataMandate request-metadata capture (IP, UA, correlation_id).requires_request_metadata = true
test_frameworksRequired compliance test framework labels (informational).test_frameworks = ["hipaa-test-suite", "gdpr-rights"]

Spec-driven profile declaration; compiler reads every attribute below and stops consulting the default registry when the value is present.

Compliance profile (full feature-set)
compliance {
  profile "covered-entity" {
    scope                     = "protected_health_information"
    data_classes              = ["PHI", "PII"]
    retention_days            = 2190
    encryption_at_rest        = true
    encryption_in_transit     = true
    audit_required            = true
    access_review_days        = 90
    subject_rights            = ["access", "rectification", "erasure"]
    breach_notification_hours = 72
    residency                 = "US"
    validation_controls       = ["technical_safeguards", "administrative"]
    legal_basis               = "HIPAA-45-CFR-164"
    full_name                 = "Health Insurance Portability and Accountability Act"
    mode_alias                = "covered-entity"
    phi_keywords              = ["diagnosis", "patient_id", "mrn"]
    pii_keywords              = ["ssn", "passport"]
    min_retention_days        = 2190
    requires_read_audit       = true
    requires_pii_masking      = true
    requires_extended_retention = true
    requires_immutable_audit  = true
    requires_encrypted_audit  = true
    requires_actor_info       = true
    requires_digital_signature = false
    requires_request_metadata = true
    test_frameworks           = ["hipaa-test-suite"]
  }
}

Complete Examples

Full spec examples from simple to complex.

A minimal spec: one entity, REST API, basic security.

Day 1 — Simple User Service
service UserService {
  version = "1.0.0"
  port = 8000
  api_prefix = "/api/v1"
  database = "postgresql"

  entity User @audit @soft_delete {
    id       UUID     @pk @default($computed.uuid)
    email    String   @unique @not_null
    name     String   @not_null
    role     Enum(ADMIN, MEMBER) @default(MEMBER)
    is_active Boolean @default(true)
  }

  api REST @entity(User) @paginated {
    POST   "/users"       @status(201)
    GET    "/users"
    GET    "/users/{id}"
    PUT    "/users/{id}"
    DELETE "/users/{id}"  @roles(ADMIN)
  }

  security {
    auth_scheme = "jwt"
    jwt_algorithm = "HS256"
    token_expiry_minutes = 60
    password_hashing = "bcrypt"
    roles = [ADMIN, MEMBER]
  }
}

A more complex spec with flows, state machines, jobs, and notifications.

Day 5 — E-commerce with Flows and State Machines
service OrderService {
  version = "2.0.0"
  port = 8001
  api_prefix = "/api/v1"
  database = "postgresql"

  entity Order @audit @soft_delete @aggregate_root {
    id          UUID     @pk @default($computed.uuid)
    customer_id UUID     @fk(Customer.id) @not_null @indexed
    total       Decimal  @not_null @check("total >= 0")
    currency    String   @default("USD")
    status      Enum(DRAFT, PENDING, PAID, SHIPPED, DELIVERED, CANCELLED) @default(DRAFT)
    notes       Text     @nullable
  }

  entity OrderItem @audit {
    id         UUID    @pk @default($computed.uuid)
    order_id   UUID    @fk(Order.id) @not_null
    product_id UUID    @not_null
    quantity   Integer @not_null @check("quantity > 0")
    unit_price Decimal @not_null
  }

  state_machine OrderStatus {
    initial = DRAFT

    DRAFT -> PENDING       @roles(MEMBER, ADMIN)
    PENDING -> PAID        @guard("payment_confirmed == true")
    PAID -> SHIPPED        @roles(ADMIN)
    SHIPPED -> DELIVERED
    PENDING -> CANCELLED   @roles(MEMBER, ADMIN)
    DRAFT -> CANCELLED
  }

  flow PlaceOrder {
    step validate {
      action = validate
      target = Order
    }
    step create_order {
      action = create
      target = Order
      mapping {
        id = $computed.uuid
        customer_id = $context.user_id
        status = DRAFT
        total = $input.total
        created_at = $computed.now
      }
    }
    step submit {
      action = state_change
      target = Order
      condition = "$result.id != null"
      mapping {
        status = PENDING
      }
    }
  }

  api REST @entity(Order) @paginated {
    POST   "/orders"          @status(201) @triggers(order_created)
    GET    "/orders"
    GET    "/orders/{id}"
    POST   "/orders/{id}/pay" @triggers(order_paid)
  }

  jobs {
    cancel_stale_orders {
      schedule = "0 * * * *"
      timeout = "2m"
      retry { max_attempts = 3, backoff = "exponential" }
    }
  }

  notifications {
    providers {
      email { adapter = "smtp" }
    }
    order_confirmed {
      channels = [email]
      recipient = $instance.customer.email
      template = "order_confirmed"
    }
  }

  errors {
    ORDER_NOT_FOUND   { status = 404, category = "not_found", message = "Order not found" }
    INSUFFICIENT_STOCK { status = 409, category = "conflict", message = "Insufficient stock" }
  }

  security {
    auth_scheme = "jwt"
    jwt_algorithm = "HS256"
    token_expiry_minutes = 60
    roles = [ADMIN, MEMBER]
    rate_limit { policy = "sliding_window", allow = 100, for = "1m" }
  }

  infrastructure {
    docker { compose_version = "3.8", base_image = "python:3.12-slim" }
    redis { broker = true, cache = true }
    celery { concurrency = 4 }
  }
}
DevMatrix DMX Language Reference. Built for developers who compile, not configure.