Appearance
Response envelope
The response to a request/reply call is also an MxEnvelope. The actor fills in op: '$reply', echoes the correlationId, and puts the result in payload. The caller, having subscribed on $reply.<cid> before sending, receives this envelope and resolves its await.
The shape
typescript
interface MxResponseEnvelope extends MxEnvelope {
op: '$reply';
correlationId: string; // echoed from the request
payload: unknown; // the op's result
}In practice, every response envelope is just a regular MxEnvelope with op === '$reply' and correlationId set. The transport handles delivery on the reply subject; the actor handler is responsible for populating payload correctly.
Convention: payload shape
Most actor ops follow a { ok: boolean, ...result } convention so callers can quickly distinguish success from failure even when looking at raw bus traffic. Concrete examples from the running code:
typescript
// system.runtimes / runtimes.list (system-runtimes/RuntimeManagerActor.ts:204)
return {
ok: true,
count: registered.runtimes.length,
runtimes: registered.runtimes,
...(registered.runtimes.length === 1 ? { runtime: registered.runtimes[0] } : {}),
};
// system.registry / registry.list (ServiceRegistryActor.ts)
return {
ok: true,
count: claims.length,
claims,
};
// system.catalog / catalog.list (SystemCatalogActor.ts:192)
return {
ok: true,
count: catalog.length,
catalog,
bindings,
runtimes,
source: 'system.catalog',
};| Field | Convention |
|---|---|
ok: true | The op succeeded. |
ok: false | The op failed; error: string is also set. See Error envelope. |
<domain-specific> | Whatever the op returns: list of items, single record, count, etc. |
Note: the
okflag is convention, not protocol. Some older ops omit it. New ops should include it. Protocol gateways that expose the op as a typed contract should mapok: falseto an error response.
A complete request/reply round-trip
Request:
json
{
"op": "registry.resolve",
"payload": { "logicalMount": "chat.conversation" },
"correlationId": "f12d-7af0",
"replyTo": "$replies.f12d-7af0"
}Response:
json
{
"op": "$reply",
"correlationId": "f12d-7af0",
"payload": {
"ok": true,
"logicalMount": "chat.conversation",
"providers": [
{
"providerRuntimeId": "rt-chat-dev-01",
"runtimeWireRoot": "COM.NIMBLETEC.RICHARD-SANTOMAURO",
"localMount": "chat.conversation",
"componentId": "chat-conversation-01",
"status": "live",
"lastHeartbeatAt": 1714862043221,
"expiresAt": 1714862073221
}
]
}
}Late or duplicate replies
The reply subject is unsubscribed after the first matching response arrives. If the actor publishes a second message for the same correlation, it goes to no subscribers and is dropped. This is by design — duplicate replies are not part of the protocol.
A timed-out caller does not receive any subsequent reply, even if the actor eventually answers. The transport closes the subscription when the timeout fires.
Replies for $introspect
$introspect returns the actor's full declared surface. Concrete shape (from MatrixActor base implementation, paraphrased to match typical output):
json
{
"op": "$reply",
"correlationId": "abc-123",
"payload": {
"mount": "chat.conversation",
"canonicalId": "ChatConversationActor:01",
"description": "Per-conversation chat actor",
"accepts": {
"chat.send": { "description": "Send a message", ... },
"chat.list": { "description": "List messages", ... }
},
"emits": {
"chat.message-added": { "description": "...", "schema": { ... } }
},
"subscribes": { ... },
"children": [ { "id": "...", "mount": "chat.conversation.42", "type": "..." } ],
"skills": { ... },
"kind": "service"
}
}The full set of fields varies per actor; accepts/emits/subscribes/ children are the most reliable.
Trace context on responses
The actor SHOULD propagate traceId/spanId/parentSpanId from the request to the response so distributed tracing covers the full round-trip. The RequestReply.execute helper handles this automatically when the actor uses framework methods to publish.
See also
- Request envelope — the matching request shape.
- Error envelope — how error replies differ.
- Correlation IDs — how reply matching works.
- Envelope schemas — full schema.