bus API
Table of Contents
upsquad/bus/v1/envelope.proto
Endpoint
Endpoint addresses a routing participant on the bus. The bus maps an Endpoint to exactly one tenant-scoped queue; it is never resolved across tenants.
| Field | Type | Label | Description |
|---|---|---|---|
| kind | EndpointKind | kind is the participant class (team, role, coordinator). | |
| id | string | id identifies the participant within its kind: a team id for TEAM, a role name for ROLE. It is empty for COORDINATOR (there is one Coordinator queue per tenant). |
Envelope
Envelope is the single A2A message contract carried on the bus. Every field is intra-tenant; the bus refuses to enqueue an Envelope with an empty tenant_id.
| Field | Type | Label | Description |
|---|---|---|---|
| id | string | id is a globally-unique message id (UUIDv4). The bus generates one if the producer leaves it empty. It is distinct from the transport-level stream entry id and survives retries/re-enqueues unchanged. | |
| schema_version | EnvelopeSchemaVersion | schema_version pins the envelope contract. Consumers reject versions they do not understand. Must be a known, non-unspecified value. | |
| tenant_id | string | tenant_id scopes the envelope to a single tenant. REQUIRED. The bus keys every queue by this value; cross-tenant delivery is impossible. | |
| task_id | string | task_id links the envelope to the Task — the unit of work AND the unit of accounting (ADR-0015). The Coordinator accrues cost/effort per hop onto this Task. | |
| conversation_id | string | conversation_id groups all envelopes belonging to one logical exchange (e.g. a WorkflowRun). Stable across the query/reply round-trips within a Task. | |
| continuation_token | string | continuation_token is the resume token for suspend/resume. A worker emitting a QUERY stamps the token it will be resumed with; the Coordinator echoes it on the matching REPLY so the suspended work-item is rehydrated and re-dispatched. Empty for fire-and-forget WORK. | |
| from | Endpoint | from is the participant that emitted the envelope. | |
| to | Endpoint | to is the participant the envelope is delivered to. The bus derives the queue key from (tenant_id, to.kind, to.id). | |
| kind | MessageKind | kind is the semantic class of the payload (work/result/query/reply/ control). Must be a known, non-unspecified value. | |
| payload | bytes | payload is the opaque application body (typically JSON or a serialized domain proto). The bus does not interpret it. content_type describes it. | |
| content_type | string | content_type is the IANA media type of payload (e.g. "application/json"). Advisory; the bus does not enforce it. | |
| created_at | google.protobuf.Timestamp | created_at is when the producer minted the envelope. The bus stamps it if left zero. Preserved across retries. | |
| attempt | uint32 | attempt is the 1-based delivery attempt counter. EnqueueWork defaults it to 1; the bus increments it on every retry / crash-reclaim. When it exceeds the configured max, the envelope is routed to the DLQ. | |
| idempotency_key | string | idempotency_key deduplicates redelivery and duplicate publishes. The bus records this key in its dedupe store on successful completion; any later delivery carrying an already-completed key is acked and dropped without re-invoking the handler. Empty disables consumer-side dedupe for the message. | |
| headers | Envelope.HeadersEntry | repeated | headers carries optional out-of-band metadata (trace ids, the DLQ failure reason, etc.). Not interpreted for routing. |
Envelope.HeadersEntry
| Field | Type | Label | Description |
|---|---|---|---|
| key | string | ||
| value | string |
EndpointKind
EndpointKind classifies a routing participant. The bus derives a queue (Redis Stream) key from (tenant_id, EndpointKind, id), so the kind + id together address where a message is delivered.
| Name | Number | Description |
|---|---|---|
| ENDPOINT_KIND_UNSPECIFIED | 0 | ENDPOINT_KIND_UNSPECIFIED is the zero value reserved by protobuf. |
| ENDPOINT_KIND_TEAM | 1 | ENDPOINT_KIND_TEAM addresses a team work-queue; id is the team id. All workers serving that team compete for messages on one queue. |
| ENDPOINT_KIND_ROLE | 2 | ENDPOINT_KIND_ROLE addresses a capability/role work-queue (e.g. "coding", "architect"); id is the role name. All workers of that role compete for messages on one queue. |
| ENDPOINT_KIND_COORDINATOR | 3 | ENDPOINT_KIND_COORDINATOR addresses the deterministic Coordinator's control queue; id is empty. Results, replies, and control messages destined for the Coordinator route here. |
| ENDPOINT_KIND_FOREIGN | 4 | ENDPOINT_KIND_FOREIGN addresses a foreign A2A agent reachable over the Google A2A wire protocol (HLD docs/hld/HLD-a2a-egress-foreign-agents.md §6.1). id is the per-tenant foreign_agent_registry key (NEVER a raw URL — the base URL + credential resolve from the registry, so a workflow definition never embeds an external endpoint or secret). A FOREIGN destination is NOT a Redis work-queue: the deterministic Coordinator, after running its unchanged per-hop choke-point (Governor.Check → audit → cost), hands the hop to the ForeignDispatcher port (the A2A egress adapter, T5.4) instead of EnqueueWork. Workers can never forward to a FOREIGN endpoint — only the Coordinator routes the external edge, so the governed-every-hop invariant holds at the perimeter (HLD §8). |
EnvelopeSchemaVersion
EnvelopeSchemaVersion is the current envelope schema version. Producers stamp Envelope.schema_version with this value; consumers reject envelopes whose schema_version they do not understand. Bumping this is a versioned, buf-breaking-checked change.
| Name | Number | Description |
|---|---|---|
| ENVELOPE_SCHEMA_VERSION_UNSPECIFIED | 0 | ENVELOPE_SCHEMA_VERSION_UNSPECIFIED is the zero value reserved by protobuf. An envelope carrying the unspecified version is rejected by the bus as malformed. |
| ENVELOPE_SCHEMA_VERSION_V1 | 1 | ENVELOPE_SCHEMA_VERSION_V1 is the initial envelope contract (this file). |
MessageKind
MessageKind is the semantic class of an envelope payload. It drives how
the Coordinator and harness interpret the message; it does NOT affect
routing (that is determined by to).
| Name | Number | Description |
|---|---|---|
| MESSAGE_KIND_UNSPECIFIED | 0 | MESSAGE_KIND_UNSPECIFIED is the zero value reserved by protobuf and is rejected by the bus as malformed. |
| MESSAGE_KIND_WORK | 1 | MESSAGE_KIND_WORK is a unit of work dispatched to a team/role for an agent to execute (the Coordinator's "next hop"). |
| MESSAGE_KIND_RESULT | 2 | MESSAGE_KIND_RESULT is the completed output of a work item, returned to the Coordinator for governance, audit, cost accrual, and next-hop routing. |
| MESSAGE_KIND_QUERY | 3 | MESSAGE_KIND_QUERY is a sub-query emitted by a worker that needs input from another role/team. The emitting agent checkpoints and stands down; it carries a continuation_token so the Coordinator can resume it on the matching reply. |
| MESSAGE_KIND_REPLY | 4 | MESSAGE_KIND_REPLY answers a prior QUERY. The Coordinator matches it to the suspended work-item via continuation_token and re-dispatches. |
| MESSAGE_KIND_CONTROL | 5 | MESSAGE_KIND_CONTROL is an out-of-band control signal (e.g. cancel, pause, coordinator liveness) that is not itself a unit of accounted work. |
Scalar Value Types
| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby |
|---|---|---|---|---|---|---|---|---|
| double | double | double | float | float64 | double | float | Float | |
| float | float | float | float | float32 | float | float | Float | |
| int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| uint32 | Uses variable-length encoding. | uint32 | int | int/long | uint32 | uint | integer | Bignum or Fixnum (as required) |
| uint64 | Uses variable-length encoding. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum or Fixnum (as required) |
| sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 2^28. | uint32 | int | int | uint32 | uint | integer | Bignum or Fixnum (as required) |
| fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 2^56. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum |
| sfixed32 | Always four bytes. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| sfixed64 | Always eight bytes. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| bool | bool | boolean | boolean | bool | bool | boolean | TrueClass/FalseClass | |
| string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | string | string | string | String (UTF-8) |
| bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) |