Internet-Draft mocha-chat July 2026
Jennings & Nandakumar Expires 7 January 2027 [Page]
Workgroup:
Media Over QUIC
Internet-Draft:
draft-jennings-moq-mocha-chat-00
Published:
Intended Status:
Standards Track
Expires:
Authors:
C. Jennings
Cisco
S. Nandakumar
Cisco

MOCHA Chat: Messaging over MoQ Transport

Abstract

This document specifies the messaging functionality for MOCHA (MoQ Open Communication & Hosting Architecture). It defines how participants send and receive messages in channels using MoQ Transport (MOQT) publish/subscribe primitives. Each device publishes messages on its own track within a channel namespace, enabling decentralized message production with relay-based fan-out. This specification covers message naming, format, causal ordering, delivery, roster management, and channel discovery for text-based chat.

About This Document

This note is to be removed before publishing as an RFC.

Status information for this document may be found at https://datatracker.ietf.org/doc/draft-jennings-moq-mocha-chat/.

Discussion of this document takes place on the Media Over QUIC Working Group mailing list (mailto:moq@ietf.org), which is archived at https://mailarchive.ietf.org/arch/browse/moq/. Subscribe at https://www.ietf.org/mailman/listinfo/moq/.

Status of This Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on 7 January 2027.

Table of Contents

1. Introduction

Messaging is the most fundamental operation in any communication system. This document specifies how MOCHA enables real-time message exchange between participants in channels using MOQT's publish/subscribe model.

MOCHA Chat assigns each publishing device its own MOQT track within a channel namespace. Messages are grouped by NTP time in minutes, enabling straightforward time-based history retrieval and relay caching. Causal ordering is maintained through a previous-message linkage that forms a DAG across the per-device tracks in a channel.

2. Conventions and Definitions

See BCP 14 [RFC2119] [RFC8174].

This document uses terminology and architecture defined in [MOCHA-ARCH], including Provider, Organization, Team, Channel, Device, GroupID, and ObjectID. The MOQT transport primitives (Track, Group, Object, Namespace, Relay) are defined in [MoQTransport]. HClientID and HDevID are defined in [MOCHA-IDENTITY].

The following additional terms are used:

Provider:

The service provider operating the MOCHA deployment. Identified by a domain name or similar unique string.

OrgID:

The organization identifier within a provider's deployment.

TeamID:

An identifier for a team or workspace within an organization.

ChannelID:

An identifier for a specific channel within a team.

MsgID:

A globally unique identifier for a message. Implementations SHOULD use a UUID (version 4) to generate MsgIDs.

3. MOCHA Chat Naming

3.1. Identifier Derivation

The HClientID and HDevID used in namespace tuples and track names are derived per [MOCHA-IDENTITY], Section "Identifier Derivation".

3.2. Channel Namespace

The MOQT tracks that carry chat messages use a namespace tuple with the following fields:

  ("mocha_v1", <Provider>, <OrgID>, "chat", <TeamID>,
   <ChannelID>, <HClientID>)

For example, messages in the "general" channel of team "engineering" at organization "acme" hosted by provider "example.com":

  ("mocha_v1", "example.com", "acme", "chat", "engineering",
   "general", <HClientID>)

3.3. Track Names

Each device publishes messages on its own track within the channel namespace. The track name is a single byte sequence:

  msg_v1_<HDevID>

For example:

  Namespace: ("mocha_v1", "example.com", "acme", "chat",
              "engineering", "general", <HClientID>)
  Track Name: "msg_v1_<HDevID>"

This per-device track design allows each device to publish independently without coordinating Group IDs with other publishers.

3.4. Group Semantics

Groups are NTP time in minutes. The Group ID corresponds to the NTP timestamp (in minutes) at the time the message is published:

  group_id = floor(ntp_timestamp_seconds / 60)

This provides:

  • Natural time-based partitioning of messages.

  • Straightforward mapping from wall-clock time to Group ID for history retrieval.

  • One-minute granularity balances caching efficiency with latency.

3.5. Object Semantics

Within each group, messages are assigned sequentially increasing Object IDs starting at 0. Each message occupies exactly one MOQT object.

3.6. MOQT Object Mapping

  Namespace: ("mocha_v1", "example.com", "acme", "chat",
              "engineering", "general")
    |
    +-- Track: msg_v1_alice-laptop-1
    |   +-- Group 29598720 (minute: 2024-05-15 16:00 UTC)
    |   |   +-- Object 0: "Hello everyone"
    |   |   +-- Object 1: "Ready for standup?"
    |   |
    |   +-- Group 29598721 (minute: 2024-05-15 16:01 UTC)
    |       +-- Object 0: "Let's start"
    |
    +-- Track: msg_v1_bob-desktop-1
    |   +-- Group 29598720
    |   |   +-- Object 0: "Hey Alice!"
    |   |
    |   +-- Group 29598721
    |       +-- Object 0: "Sounds good"
    |       +-- Object 1: "Sharing my screen now"
    |
    +-- Track: msg_v1_carol-phone-1
        +-- Group 29598721
            +-- Object 0: "On my way, 2 min"

4. Message Format

4.1. Encoding

Messages are encoded as JSON [JSON] and compressed before being placed in the MOQT object payload. The compression algorithm is signaled via the MOCHA_COMPRESSION track property (see Section 4.2).

4.2. Compression Track Property

The MOCHA_COMPRESSION track property signals the compression algorithm applied to ALL objects on a message track. Publishers MUST include this property in the PUBLISH message (publisher-initiated flow) or SUBSCRIBE_OK (subscriber-initiated flow).

Subscribers MUST check for this property before processing track payloads. If the property is absent, the subscriber MUST treat the payload as uncompressed. If the property is present with a value the subscriber does not support, the subscriber MUST NOT attempt to process the payload and SHOULD unsubscribe from the track.

The following compression algorithm values are defined:

Table 1
Value Algorithm Reference
0 None This document
1 GZIP [RFC1952]
2 Brotli [RFC7932]

Implementations MUST support GZIP (value 1) and MAY support Brotli (value 2). A publisher that does not compress MUST either set the property to 0 or omit it entirely.

4.3. Message Structure

The message structure follows the MIMI content format style [MIMI-CONTENT], adapted for MOCHA's channel-based messaging. Fields use short keys for compact JSON encoding.

{
  "msgId": "<hex-encoded MsgID>",
  "type": 0,
  "ts": 1715788800000,
  "sender": {
    "userId": "<user identifier>",
    "displayName": "<human-readable name>",
    "devId": "<device identifier>"
  },
  "content": {
    "type": "text/plain",
    "body": "<message text>"
  },
  "prev": ["<hex-encoded MsgID>", ...],
  "threadId": "<hex-encoded MsgID>",
  "replaces": "<hex-encoded MsgID>",
  "expires": 0,
  "ext": {}
}

The message fields are defined as follows:

4.3.1. Top-Level Fields

msgId (REQUIRED):

The globally unique identifier for this message within the channel. Implementations SHOULD use a UUID (version 4).

type (REQUIRED):

Integer message type. This specification defines type 0 (none/system) and type 1 (text). The type field is extensible for future message categories.

ts (REQUIRED):

The time the message was created, in milliseconds since the Unix epoch. Set by the publisher's local clock.

sender (REQUIRED):

The originator of the message. See Section 4.3.2.

content (REQUIRED):

The message payload. See Section 4.3.3.

prev (REQUIRED):

A list of hex-encoded MsgIDs of the immediately preceding message(s) in the channel. This forms a causal ordering DAG across all tracks in the channel. An empty array indicates no known predecessors. See Section 5.

threadId (OPTIONAL):

The hex-encoded MsgID of the root message that started the thread. Present when this message is a reply within a thread. Threads are flat — nested threading is not supported. If absent, the message is a top-level channel message.

replaces (OPTIONAL):

The hex-encoded MsgID of a prior message that this message edits or deletes. Present when type is 2 (edit) or 3 (delete). See Section 6.

expires (OPTIONAL):

Expiration time in milliseconds since the Unix epoch. If non-zero, clients SHOULD hide the message after this time. A value of 0 indicates no expiration.

ext (OPTIONAL):

An object containing extension fields. Implementations MUST ignore unknown extension keys. Extensions are namespaced to avoid collisions (see [MOCHA]).

4.3.2. Sender Info

The sender object identifies the message author:

userId (REQUIRED):

A stable identifier for the user within the identity system (e.g., "alice@acme.example.com").

displayName (REQUIRED):

A human-readable label for rendering in the UI.

devId (REQUIRED):

The identifier of the publishing device. MUST match the HDevID in the track name from which the message is published.

4.3.3. Content Structure

The content object carries the message payload, following MIMI's content disposition pattern:

type (REQUIRED):

A MIME type string indicating the content format. This specification defines "text/plain" for plain text messages. Implementations MUST support "text/plain".

body (REQUIRED):

The content payload. For "text/plain", this is a UTF-8 string containing the message text.

Future specifications MAY define additional content types (e.g., "text/markdown"). Clients receiving an unknown content type SHOULD render the body as plain text if it is a string, or display a placeholder indicating an unsupported format.

4.3.4. Message Type Values

Table 2
Value Name Description
0 none System or control message (no body)
1 text Text message
2 edit Replaces content of a prior message
3 delete Removes a prior message from display

The type enum is extensible. Future specifications define additional values for media and other content.

4.4. Example Message

A text message as JSON (before compression):

{
  "msgId": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
  "type": 1,
  "ts": 1715788800000,
  "sender": {
    "userId": "alice@acme.example.com",
    "displayName": "Alice Smith",
    "devId": "<HashDevID>"
  },
  "content": {
    "type": "text/plain",
    "body": "Hello everyone, ready for the standup?"
  },
  "prev": ["e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6"]
}

5. Causal Ordering

5.1. Previous Message List

Each message contains a "previous" field listing the MsgID(s) of the most recent message(s) the publisher has observed in the channel at the time of publishing. This forms a directed acyclic graph (DAG) across all per-device tracks in a channel.

  Causal DAG across devices:

  Alice's track:     A1 -----> A2 ---------> A3
                      \          \           /
  Bob's track:         --> B1 --> B2 ------>
                                   \
  Carol's track:                    --> C1

In this example:

  • A1 has no previous (first message in channel, or references messages not shown).

  • B1.previous = [A1] (Bob saw Alice's first message).

  • A2.previous = [B1] (Alice saw Bob's reply).

  • B2.previous = [A2] (Bob saw Alice's second message).

  • C1.previous = [B2] (Carol saw Bob's second message).

  • A3.previous = [B2, C1] (Alice saw both Bob and Carol's latest messages).

5.2. Ordering Semantics

The previous message list provides causal ordering:

  • If message B lists message A in its previous list (directly or transitively), then A causally precedes B.

  • Messages with no causal relationship are concurrent and may be displayed in any order (typically by timestamp).

  • Clients reconstruct channel ordering by traversing the DAG.

5.3. Display Ordering

Clients SHOULD use the causal DAG to determine display order. When causal ordering does not fully determine order (concurrent messages), clients SHOULD fall back to timestamp ordering.

A simple linearization algorithm:

  1. Topologically sort messages using the DAG.

  2. For concurrent messages (no causal relationship), sort by timestamp.

  3. For identical timestamps, sort by MsgID (lexicographic on the hash bytes) for deterministic ordering.

6. Message Edit and Delete

A sender can edit or delete a message it previously published by publishing a new object on the same track with the replaces field set to the MsgID of the original message.

6.1. Edit (type 2)

An edit message replaces the content of a prior message. The content field carries the new text. The original message's position in the causal DAG is preserved; the edit object itself also participates in the DAG via its own prev field.

{
  "msgId": "b2c3d4...",
  "type": 2,
  "ts": 1715788900000,
  "sender": {
    "userId": "alice@acme.example.com",
    "displayName": "Alice Smith",
    "devId": "<HashDevID>"
  },
  "content": {
    "type": "text/plain",
    "body": "Hello everyone, ready for standup? (corrected)"
  },
  "prev": ["a1b2c3..."],
  "replaces": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}

6.2. Delete (type 3)

A delete message removes a prior message from display. No content field is required; if present it is ignored.

{
  "msgId": "c3d4e5...",
  "type": 3,
  "ts": 1715789000000,
  "sender": {
    "userId": "alice@acme.example.com",
    "displayName": "Alice Smith",
    "devId": "<HashDevID>"
  },
  "prev": ["b2c3d4..."],
  "replaces": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}

6.3. Processing Rules

  1. Only the original sender (matching userId) MAY edit or delete a message. Receivers MUST ignore edit or delete objects from a different userId than the original message.

  2. Multiple edits to the same message are permitted. The edit with the latest causal ordering (per Section 5) takes precedence.

  3. A delete after an edit takes precedence: the message is removed from display regardless of prior edits.

  4. Receivers SHOULD display an indicator that a message has been edited. Receivers MAY offer access to the edit history.

  5. Relays forward edit and delete objects like any other message object without interpreting their semantics.

7. Threading

MOCHA supports threaded conversations where replies are grouped under a parent message. Threads are flat — nested threading is not supported.

7.1. Thread Replies

To reply within a thread, a device publishes a message on its regular msg_v1_<HDevID> track with the threadId field set to the MsgID of the root message that started the thread. The root message itself has no threadId field.

7.2. Thread Display

Clients SHOULD group messages with the same threadId and display them as a thread under the root message. The root message is identified by its MsgID matching the threadId of the replies.

7.3. Thread Edits and Deletes

Edit and delete messages (types 2 and 3) within a thread MUST carry the same threadId as the message they replace. This allows clients to correctly scope the edit or delete to the thread view.

8. MOCHA Roster Naming

The roster provides a discovery mechanism for participants to learn which devices are active in a channel. Each device publishes its availability and user identity on a dedicated roster track. Participants subscribe to the roster namespace to build the set of message tracks they should follow.

8.1. Roster Namespace

The roster tracks for a channel use the namespace tuple:

  ("mocha_v1", <Provider>, <OrgID>, "roster", <TeamID>,
   <ChannelID>, <HClientID>)

HClientID and HDevID are derived per Section 3.1.

For example:

  ("mocha_v1", "example.com", "acme", "roster", "engineering",
   "general", <HClientID>)

8.2. Roster Track Names

Each device publishes its user information on a track:

  user_<HDevID>

For example:

  Namespace: ("mocha_v1", "example.com", "acme", "roster",
              "engineering", "general", <HClientID>)
  Track Name: "user_<HDevID>"

8.3. Roster Object Format

Each object on a roster track contains a JSON document providing information about the mapping of the device to a user in the identity system. The display_name is obtained from the user's PAB entry (see [MOCHA]) and the user_id is obtained from the identity system (see [MOCHA-IDENTITY]).

{
  "user_id": "alice@acme.example.com",
  "display_name": "Alice Smith",
  "dev_id": "<HashDevID>",
  "joined_at": 1715788000000,
  "status": "active"
}

8.4. Roster Usage

Participants subscribe to the roster namespace to discover which devices are active in a channel. The roster provides the set of msg_v1_<HDevID> tracks that should be subscribed for receiving channel messages.

When a new device joins a channel, it publishes a roster object. When a device leaves, it publishes an updated roster object with status "departed" or the track simply becomes inactive.

9. Channel Discovery

Channel discovery allows participants to learn which channels are available within a team. A designated device (or server) publishes channel metadata on a channel info track. Participants subscribe to this namespace to present users with a list of channels they can join.

9.1. Channel Info Namespace

Channel discovery tracks use the namespace tuple:

  ("mocha_v1", <Provider>, <OrgID>, "channel_info", <TeamID>)

For example:

  ("mocha_v1", "example.com", "acme", "channel_info", "engineering")

9.2. Channel Info Track Names

Each device (or server) that creates or manages channels publishes channel information on a track:

  channel_<HDevID>

For example:

  Namespace: ("mocha_v1", "example.com", "acme",
              "channel_info", "engineering")
  Track Name: "channel_admin-server-1"

9.3. Channel Info Object Format

Objects on channel info tracks contain the names and metadata of channels available in the team:

{
  "channels": [
    {
      "channel_id": "general",
      "name": "#general",
      "topic": "General discussion",
      "type": "public"
    },
    {
      "channel_id": "backend",
      "name": "#backend",
      "topic": "Backend engineering",
      "type": "public"
    },
    {
      "channel_id": "secret-project",
      "name": "#secret-project",
      "type": "private"
    }
  ]
}

10. Availability

MOCHA provides an availability system for communicating user availability and status within a channel. Channel membership implicitly grants availability visibility — all channel members can see each other's availability without explicit subscription consent.

10.1. Availability Namespace

Availability tracks for a channel use the namespace tuple:

  ("mocha_v1", <Provider>, <OrgID>, "availability", <TeamID>,
   <ChannelID>, <HClientID>)

HClientID is derived per Section 3.1.

10.2. Availability Track Names

Each device publishes its availability on a dedicated track:

  availability_v1_<HDevID>

HDevID is derived per Section 3.1.

10.3. Availability States

Table 3
State Description
online User is active and available
away User is idle or stepped away
dnd Do not disturb — suppress notifications
offline User is disconnected

10.4. Availability Object Format

Each object on an availability track contains:

{
  "status": "online",
  "status_message": "In meetings until 3pm",
  "last_active": 1715790000000,
  "idle_seconds": 0
}

Fields:

  • status: One of the availability states above.

  • status_message: Optional human-readable status text.

  • last_active: NTP timestamp (milliseconds) of last user activity.

  • idle_seconds: Seconds since last user interaction on this device. Set to 0 when active.

10.5. Availability Updates

A device publishes a new availability object whenever its state changes (e.g., user becomes idle, changes status, or goes offline). Each new object replaces the previous state.

Devices SHOULD publish an availability object with status "offline" when gracefully disconnecting. If a device disconnects without publishing an offline status, subscribers detect the absence via track inactivity.

10.6. Typing Indicators

Typing indicators are ephemeral availability signals scoped to a channel. They use the same availability namespace with a separate track:

  typing_v1_<HDevID>

10.6.1. Typing Object Format

{
  "is_typing": true,
  "thread_id": null,
  "ts": 1715790000000
}

Typing indicators:

  • SHOULD be delivered via QUIC datagrams (unreliable) for low latency.

  • SHOULD timeout after 5 seconds without an update.

  • MAY be disabled per-user or per-channel.

10.7. Subscribing to Availability

Participants subscribe (SUBSCRIBE_NAMESPACE) to the availability namespace to receive availability and typing updates from all channel members. This follows the same pattern as roster subscription — joining a channel implicitly subscribes the device to availability.

11. Security Considerations

TODO

12. IANA Considerations

12.1. MOCHA_COMPRESSION Track Property

This document requests IANA registration of the MOCHA_COMPRESSION track property in the "MoQ Track Properties" registry (if established by [MoQTransport]).

Property Name:

MOCHA_COMPRESSION

Property Type:

Track Property

Value Type:

Varint

Description:

Signals the compression algorithm applied to all objects on a MOCHA message track.

Reference:

This document, Section 4.2

12.2. MOCHA Compression Algorithms Registry

This document establishes a new "MOCHA Compression Algorithms" registry with the following initial entries:

Table 4
Value Algorithm Reference
0 None This document
1 GZIP [RFC1952]
2 Brotli [RFC7932]

New entries require Specification Required (per [RFC8126]).

13. References

13.1. Normative References

[JSON]
Bray, T., Ed., "The JavaScript Object Notation (JSON) Data Interchange Format", STD 90, RFC 8259, DOI 10.17487/RFC8259, , <https://www.rfc-editor.org/rfc/rfc8259>.
[MOCHA]
"*** BROKEN REFERENCE ***".
[MOCHA-ARCH]
"*** BROKEN REFERENCE ***".
[MOCHA-IDENTITY]
"*** BROKEN REFERENCE ***".
[MoQTransport]
Nandakumar, S., Vasiliev, V., Swett, I., and A. Frindell, "Media over QUIC Transport", Work in Progress, Internet-Draft, draft-ietf-moq-transport-18, , <https://datatracker.ietf.org/doc/html/draft-ietf-moq-transport-18>.
[RFC1952]
Deutsch, P., "GZIP file format specification version 4.3", RFC 1952, DOI 10.17487/RFC1952, , <https://www.rfc-editor.org/rfc/rfc1952>.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/rfc/rfc2119>.
[RFC7932]
Alakuijala, J. and Z. Szabadka, "Brotli Compressed Data Format", RFC 7932, DOI 10.17487/RFC7932, , <https://www.rfc-editor.org/rfc/rfc7932>.
[RFC8126]
Cotton, M., Leiba, B., and T. Narten, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 8126, DOI 10.17487/RFC8126, , <https://www.rfc-editor.org/rfc/rfc8126>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/rfc/rfc8174>.

13.2. Informative References

[MIMI-CONTENT]
Mahy, R., "More Instant Messaging Interoperability (MIMI) Content Format", , <https://datatracker.ietf.org/doc/draft-ietf-mimi-content/>.

Authors' Addresses

Cullen Jennings
Cisco
Suhas Nandakumar
Cisco