Appearance
Compatibility rules
The protocol's compatibility contract is short, stated in CLAUDE.md Rule 9 § "Coding standards":
Source:
CLAUDE.mdRule 9. Quoted: "Additive-only schema evolution — never remove fields, only add optional ones."
This rule applies to:
accepts.<op>.schemaand.returnsemits.<event>.schemastreams.<name>.schemastate.<key>.schema- The shape of
MxEnvelopeand the request/response/error payloads - HTTP gateway endpoint shapes (when added)
Why additive-only
A live network has many independent clients and providers running at different versions. Removing a field that an older caller still sets, or renaming an op, breaks them. With additive-only:
- New optional fields are ignored by old code.
- New ops are unused by old code, present for new code.
- Default values fill in missing fields when old code talks to new servers.
- The system never has a "flag day" upgrade requirement.
What you may do
- Add a new optional field to a schema. Old payloads without it still validate.
- Add a new op to
static accepts. Old callers don't know about it; new callers use it. - Add a new event name to
static emits. Old subscribers don't see it; new subscribers do. - Tighten internal validation AS LONG AS the wire shape doesn't change.
- Add a new error code to your actor's
errorSpecs.
What you may NOT do
- Remove a field from a schema. Old callers may still send it; old consumers may still read it. Removing breaks both directions.
- Rename a field. Equivalent to "remove old + add new".
- Change a field's type (e.g.,
string → number). - Make an optional field required. Old payloads will fail validation.
- Remove an op from
static accepts. Older callers may still invoke it. - Change an op's semantics so that an old payload now produces a different result.
If the field truly must go away, deprecate it: keep it in the schema, mark it deprecated: true in description, ignore it in the implementation, and wait for old callers to migrate. Plan a removal release with explicit version-skew testing.
Idempotency requirement
Every write op MUST accept an optional idempotencyKey:
Source:
CLAUDE.mdRule 9. "Every write op accepts optionalidempotencyKey."
This is a forward-compatibility hedge: if the actor adds dedup logic later, callers' retries become safe automatically. Today, most actors simply pass through; the field is there for the future.
Pagination requirement
Every list op MUST return cursor-based pagination:
"Every list op returns cursor-based pagination."
Today many list ops return { ok: true, count, items } without a cursor. The migration target is { ok: true, count, items, cursor } where cursor is opaque. The cursor field is additive — adding it does not break clients that ignore it.
Wire compatibility
The wire grammar ({root}.{mount}.$facet) is stable. Subject mapping in NatsTransport.semanticToNats does not change between releases without a major version bump. Adding a new facet (e.g., $stream.<name>) is additive at the transport layer.
Envelope compatibility
The MxEnvelope shape is stable. New optional fields may be added (traceId/spanId/parentSpanId were added without breaking older code that didn't carry them). Required fields are fixed: op and payload.
Reserved subjects
The reserved facet list (Reserved subjects) is the protocol's ABI. Adding a new reserved facet is allowed in minor versions if it is genuinely additive (the new facet has its own suffix and doesn't collide with existing ops). Removing a reserved facet requires a major version.
Discovery metadata compatibility
Per WORKSTREAMS/core-and-packaging/MATRIX-DISCOVERY-METADATA-SPEC.md:
appName,spacePath,spaceId,authorityRootfield names are stable.- New optional metadata fields (e.g., a new
tagsshape) are additive. - The v1 → vNext manifest migration (planned) carries existing fields through; no removal in v1.
Practical migration recipe
When you need to change an existing field:
- Add a new field with the new shape (
logicalMountV2next tologicalMount). - Have new code prefer the new field; old code keeps using the old one.
- Have the actor populate both for a few releases.
- Mark the old field deprecated.
- Eventually (next major), remove the old field — coordinated with client release notes.
This is the path the routeKey → spacePath migration is on (see Authority roots).
What is NOT additive-only
Some changes are intentionally not in scope of this rule:
- Capability tokens. These are short-lived; new caveats can be introduced and rejected by older actors that don't recognize them (the actor must reject unknown caveats, per the capability model).
- Trace context. New fields on the envelope (
traceId, etc.) are optional — old code ignores them. Within trace processing, the semantics may evolve.
See also
- Envelope schemas — what is being kept stable.
- Subject naming reference — field/name conventions.
- Reserved subjects — the protocol ABI.
CLAUDE.md— Rule 9.