Appearance
SDK vs protocol
Matrix has two layers that authors confuse, and the confusion produces fragile code. The protocol is a wire-format and addressing contract that any client could implement. The SDK is one TypeScript implementation of that protocol — the implementation that ships in this repo.
This page draws the line.
The protocol — what is on the wire
The Matrix protocol is the contract every actor and every transport must obey, regardless of language or runtime. It is defined by spec, not by code:
- Address grammar.
{authorityRoot}.{mount}.$facet— dot-delimited NATS subjects, where$facetis one of$inbox,$events,$reply.{correlationId},$activity, etc. Authority roots derive from email or Space identity (e.g.COM.NIMBLETEC.RICHARD-SANTOMAURO). - Six declarations. Every actor declares
accepts,emits,streams,state,subscribes,blackboard. Every op and field has adescription. SeeWORKSTREAMS/core-and-packaging/ACTOR-COMMUNICATION-CONTRACT.md. - Wire envelope. Messages are JSON
MxEnveloperecords withop,payload, optionalfrom,lamport,correlationId,replyTo. The envelope shape is fixed; the payload schema is per-op. - System ops.
$introspect,$ping,$join/$join_ack/$leave,$getState,$getHistory,$prompt,$activity,$membrane,$cognitive.set,$skill. Reserved names; every actor handles them. - Identity from transport metadata. Authenticated identity comes from the NATS connection's user credentials, never from the message payload.
A Python client, a Go bridge, or a hand-rolled WebSocket client can all participate in Matrix as long as they obey this protocol. None of them need to depend on @open-matrix/core.
The SDK — what is in this repo
The Matrix SDK is @open-matrix/core plus a small handful of supporting workspace packages. It is the canonical TypeScript implementation of the protocol, and it is what every Matrix package, every webapp, and the Host Service runner are built on. The SDK provides:
| Concern | SDK class / function |
|---|---|
| Headless actor base class | MatrixActor (src/core/MatrixActor.ts) |
| Browser custom-element wrapper | MatrixActorHtmlElement (src/framework/MatrixActorHtmlElement.ts) |
| Runtime container | MatrixRuntime (src/runtime/MatrixRuntime.ts) |
| In-process transport | InMemoryTransport, InMemoryBroker (src/transport/InMemory*.ts) |
| NATS transport (Node) | NatsTransport, createTransport (src/transport/{NatsTransport,createTransport}.ts) |
| NATS transport (browser, JWT or token) | createBrowserNatsTransport (src/transport/createBrowserNatsTransport.ts) |
| Activity-stream contract | ActivityFrame, ActivityPhase, isTerminalPhase (src/framework/ActivityFrame.ts) |
| Package config resolution | resolveConfiguredPackageConfig, deepMergeConfig (src/runtime/PackageConfigResolver.ts) |
| Wire types | MxEnvelope, IMatrixContext, ITransportAdapter (engine layer) |
The SDK does NOT contain protocol-level identity policy, authority-root derivation, JWT issuance, or HiveCast pairing. Those live elsewhere:
- Authority-root derivation lives in
@open-matrix/system-authand the host service flow (not incore). - JWT issuance for browser NATS is a host-service / system-auth concern. The SDK only consumes JWTs via
createBrowserNatsTransport({ jwtProvider }). - HiveCast pairing and Device-Link approval is
system-authplus thehivecastwrapper, nevercore.
What lives where, side by side
| Concern | Protocol (spec) | SDK (@open-matrix/core) |
|---|---|---|
Subject grammar {root}.{mount}.$facet | defined | implemented in TopicRouter and NatsTransport |
MxEnvelope { op, payload, ... } | defined | exported as a TS type |
accepts / emits / streams / state / subscribes / blackboard | defined | static fields on MatrixActor |
System ops ($introspect, $ping, $join, ...) | reserved | auto-subscribed by MatrixActor |
| Authority-root derivation rules | defined in MATRIX-AUTHORITY-MODEL.md | not implemented (lives in system-auth) |
| Identity from transport metadata | mandatory | the from field on incoming envelopes is set by transport, not payload |
| Browser → NATS via WebSocket | mandatory same-origin /nats-ws | createBrowserNatsTransport({ wsUrl }) |
| Federation (cross-root invoke) | defined | MatrixActor.invoke(rootPath, op, data) delegates to transport.invoke (FederationPeer) |
What this means in practice
If you are writing a Matrix package, you depend on @open-matrix/core and you obey the protocol. The SDK enforces most of the protocol mechanically — declaring static accepts produces the right $introspect output; calling this.emit('foo', ...) publishes to the right subject; receiving an envelope on $inbox dispatches to on{Op}.
If you are writing a non-TypeScript bridge (a Python tool, a Go service, an embedded device), you do not need this SDK. You implement the protocol directly: open a NATS connection, publish MxEnvelope JSON to {root}.{mount}.$inbox, subscribe to {root}.{mount}.$events, answer $introspect and $ping. That participant is just as much a Matrix actor as anything in this repo.
See also
- SDK vs runtime host — when to use
MatrixRuntimedirectly vs Host Service. - SDK package layout — where SDK files live in the monorepo.
- Actor Communication Contract — the six declarations in full.
- NATS transport — wire prefixing and root validation.
Source:
projects/matrix-3/packages/core/src/index.ts(public exports),projects/matrix-3/packages/core/src/transport/NatsTransport.ts:107-150(root validation, prefix grammar),WORKSTREAMS/core-and-packaging/ACTOR-COMMUNICATION-CONTRACT.md(six declarations).