Appearance
NATS
NATS is Matrix's native transport. Every actor invocation, event, and state record ultimately publishes or subscribes to a NATS subject. All other protocol adapters (HTTP, WebSocket, MCP, REST/OpenAPI, gRPC, AsyncAPI) are translators that turn their wire shape into NATS publishes and back.
Source:
projects/matrix-3/packages/core/src/transport/NatsTransport.tsis the canonical transport implementation.projects/matrix-3/packages/docs/content/architecture/nats-topology.mdcovers connection-mode trade-offs.
Why NATS
NATS is the only widely-adopted transport that natively supports both request/reply and pub/sub with leaf-node federation. The protocol's guarantees come from there:
- One subscription pattern, one transport library, one set of ACL rules.
- Federation across providers via leaf nodes — outbound only, no open inbound ports required on each Host.
- JetStream for durable streams (
static streams) and KV state (static state). - Token-bucket QoS, per-subject backpressure, optional account isolation.
Three connection modes
Source:
projects/matrix-3/packages/docs/content/architecture/nats-topology.md. Modes are configured in<env>.environment.json.
| Mode | Behavior | When to use |
|---|---|---|
embedded | Host runs its own NATS server. All traffic local. | First-run before login; isolated dev/test. |
external | Host connects to remote NATS as a WebSocket client. No local server. | Container workers; lightweight devices. |
colocated | Host connects to a separate local NATS process the user manages. | Power users sharing one NATS across multiple Hosts. |
| Leaf node | Host runs its own NATS AND attaches it as a leaf to a hub. | Heavy local traffic + cross-root federation. |
The hub topology (hub.hivecast.ai:7422 for HiveCast, or any NATS hub for self-hosting) is the federation backbone. Subscription interest from leaves propagates to the hub; no per-route lookup table.
Subject mapping (verbatim)
semanticToNats translates Matrix's slash-form semantic topics into dot-form NATS subjects. From projects/matrix-3/packages/core/src/transport/NatsTransport.ts:267:
Format: {root}.{mount}.{$facet}
system.llm/$inbox → com.example.system.llm.$inbox
$replies.abc-123 → com.example.$reply.abc-123
system.llm/# → com.example.system.llm.>
# → com.example.>
generic.topic → com.example.generic.topicWildcard mapping:
| Semantic | NATS |
|---|---|
+ | * |
# | > |
Wire payload encoding
Default jsonMode: true (NatsTransport.ts:132). The transport encodes payloads as JSON via TextEncoder/TextDecoder. Empty payloads encode as null. With jsonMode: false, the transport accepts strings and Uint8Array payloads directly. Production code uses JSON exclusively.
Credentials
NatsTransport accepts NATS user credentials via the credentials option (or user / pass aliases):
typescript
interface INatsTransportOptions {
root?: string;
topicPrefix?: string;
jsonMode?: boolean;
onError?: (err: Error) => void;
credentials?: { user: string; pass: string };
user?: string;
pass?: string;
// ...
}The connection itself must already be established with these credentials; the transport stores them for inspection (transport.credentials).
Browser NATS
Browsers connect through the HTTP gateway's /nats-ws endpoint. The gateway proxies the WebSocket and mints a NATS-scoped JWT for the authenticated user. From the browser's perspective, this is just a NATS client over WebSocket; from the server's perspective, every browser session is a separately-authenticated leaf with subject ACL pinned to the principal's authority root.
Each browser tab registers as a runtime under system.runtimes (e.g., RUNTIME-BROWSER-F81354A7). Director shows browser tabs alongside server-side runtimes.
Reply subject handling
NATS supports protocol-native reply subjects (_INBOX.*). Matrix does NOT use them by default — RequestReply.execute publishes its own {root}.$reply.<cid> form so every subject is root-prefixed and NATS-account-ACL-authorizable. The source comment makes this explicit:
Source:
projects/matrix-3/packages/core/src/engine/remoting/RequestReply.ts:318. "Do not use natsClient.request() here: protocol reply inboxes (_INBOX.*) bypass our root-prefixed subjects and break ACL enforcement."
Account model
Per-tenant NATS accounts are the strongest isolation tier. The hub account model (target):
Operator (signs all accounts)
├── AI_HIVECAST — platform account
├── COM_NIMBLETEC_RICHARD_SANTOMAURO — Richard's account
├── COM_GMAIL_RICHARDMATHEWSANTOMAURO — personal account
├── AI_HIVECAST_DEV — dev/CI (broad permissions)
└── SYS — internal NATSEach account can publish/subscribe only to its own root's subjects. Cross-account communication uses NATS service imports/exports.
Status: target state, partial. Today, the hub uses a single shared account with
pub/sub: ">"(full traffic). NATS account isolation for free-tier users is documented as a CRITICAL gap innats-topology.md. Subject-prefix isolation enforced by the Host runtime is the current production posture.
Backpressure
NATS drops to its native backpressure rules under load. The transport exposes mailbox configuration (in MatrixRuntime) with highWaterMark and onFull: 'drop-oldest' defaults (MatrixRuntime.ts:163). Slow subscribers may miss events; ops design should not rely on fan-out delivery to every subscriber.
See also
- Subjects — wire grammar.
- Subject grammar — formal transformation rules.
- Request envelope — what flows over NATS.
- HTTP gateway — adapter that delegates to NATS.
- WebSocket — browser → NATS path.