Appearance
Subject grammar
The Matrix subject grammar is fixed by NatsTransport. Every subject in the system is one of seven cases, and the semanticToNats / natsToSemantic methods round-trip them losslessly.
The wire form
{root}.{mount}.$facetWhere:
{root}is a dot-delimited DNS-like prefix (e.g.,COM.NIMBLETEC.RICHARD-SANTOMAURO). Validation regex (verbatim fromNatsTransport.tsline 108):static readonly ROOT_PATTERN = /^[a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?$/;{mount}is a dot-delimited mount path (e.g.,chat.conversation).$facetis one of$inbox,$events,$exit,$reply, or absent (generic topics).
The semantic form
Outside the transport, code uses the semantic form:
mount/$facet
mount/<wildcard>
$replies.{cid}
$inbox ← root-level facet
generic.topic ← no facetA semantic topic uses slashes to separate mount from facet/wildcard, and dots inside the mount path. Examples:
system.llm/$inbox
chat.conversation/$inbox
chat/$events
$replies.f12d-7af0Cross-root targeting uses an explicit root in the semantic form:
AI.HIVECAST.HOST/system.gateway.http/$inboxThe first slash separates the target root from the local-form mount/facet.
Verbatim transformation rules
From projects/matrix-3/packages/core/src/transport/NatsTransport.ts lines 257–266 (the semanticToNats JSDoc):
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.topicThe seven cases handled by the implementation:
| # | Semantic input | Wire output | Notes |
|---|---|---|---|
| 1 | <root>/<localTopic> | targets a different root | cross-root form |
| 2 | # | {root}.> | root-level wildcard |
| 3 | $replies.<cid> | {root}.$reply.<cid> | reply subject |
| 4 | $inbox / $events / $exit | {root}.<facet> | root-level facet |
| 5 | <mount>/$inbox (or $events/$exit) | {root}.<mount>.<facet> | mount + facet |
| 6 | <mount>/# | {root}.<mount>.> | mount-level wildcard |
| 7 | <topic> (generic) | {root}.<topic> | no facet |
Round-trip the other way (natsToSemantic):
| Wire input | Semantic output |
|---|---|
{root}.> | # |
{root}.$reply.<cid> | $replies.<cid> |
{root}.<mount>.$inbox (or $events/$exit) | <mount>/$inbox |
{root}.<mount>.> | <mount>/# |
{root}.<topic> (no facet) | <topic> |
If a wire subject does not start with the transport's root prefix, natsToSemantic returns it unchanged.
Wildcards
Two wildcards are supported, with a semantic form that differs from NATS to avoid > collisions in user-facing strings:
| Semantic | NATS | Matches |
|---|---|---|
+ | * | exactly one token |
# | > | one or more tokens |
Wildcard tokens may appear anywhere in the mount path, but > (NATS) / # (semantic) is only valid as the final token. The transport applies this conversion in _semanticTokenToNats (lines 515–523).
Reserved facets
The four facets that have transport-level handling:
| Facet | Used by |
|---|---|
$inbox | inbound op delivery (one per actor) |
$events | outbound pub/sub fan-out |
$reply | request/reply correlation (subject suffix $reply.<cid>) |
$exit | child-to-parent lifecycle exit |
$state is a reserved name for KV updates but is handled by the JetStream KV bucket layer rather than the transport's facet handlers. See Reserved subjects for the full list.
What is forbidden
- A bare
.at the start or end of a topic. - Spaces inside a token.
>or*inside a token (only allowed as standalone wildcard tokens).- Any topic that does NOT start with the transport's root prefix when publishing — the transport rejects publishes that would land outside the root (the wire-format ACL boundary).
- Mixing semantic
/and wire.in the same topic. Use one form consistently.
Validation in code
The root passes NatsTransport.ROOT_PATTERN. Invalid roots throw at transport construction:
typescript
// NatsTransport.ts line 122
if (!NatsTransport.ROOT_PATTERN.test(root)) {
throw new Error(
`NatsTransport: invalid root "${root}". Must be alphanumeric with hyphens, dots, and underscores only.`
);
}Mount paths are not regex-validated by the transport itself — they are treated as opaque dot-tokens. Caller validation (e.g., system.registry) does enforce mount conventions where required.
See also
- Subjects — conceptual overview.
- Authority roots — what
{root}is allowed to be. - Reserved subjects — full facet reference.
- Subject naming reference — op-name and event-name conventions.