Skip to content

FMSG-005 Reactions Standard

Status

Revision Date Summary
v0.1.0 2026-09-02 Initial draft

This standard defines how a participant reacts to a message with a single emoji. A reaction is an ordinary plain-text fmsg message, recognised by its shape rather than by a dedicated type, constrained so that it can be verified, delivered, and stored by any conforming host, and so that no message can be built on top of it.

This revision requires fmsg Specification v0.6.0 or later for the terminal flag.

Requirements Language

The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, NOT RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in BCP 14 (RFC 2119 and RFC 8174) when, and only when, they appear in all capitals.

Scope

This standard defines:

  • the shape of a reaction message on the wire;
  • which emoji a reaction may carry;
  • who a reaction is delivered to;
  • how a participant’s effective reaction on a message is determined, including changing and clearing it; and
  • how hosts and clients that do not implement this standard behave.

It does not change the host-to-host protocol, define a client API, or require a host to understand reactions in order to carry them. The client API for reactions is defined by FMSG-003 v0.2.0 and later.

Normative References

Terminology

subject is the message a reaction refers to via pid. It may be a thread’s first message, a reply, or an add-to batch message.

reactor is the address in a reaction message’s from field.

reaction message is an fmsg message meeting the requirements in Reaction Message.

effective reaction is the reaction, if any, that a reactor currently has on a subject, determined per Effective Reaction.

Other terms have the meanings given in the fmsg Specification.

Introduction

This section is non-normative.

Reactions are lightweight acknowledgements such as 👍 or ❤️ attached to a message rather than sent as a reply. Modelling them as messages rather than as a separate side channel means they inherit everything fmsg already provides: reliable store-and-forward delivery with retries, duplicate detection, the participant rule (only a participant of the subject can react to it), the challenge, and immutable, hash-verifiable storage.

The one property reactions need that an ordinary reply lacks is that nothing can be built on top of them: a reaction cannot be replied to, reacted to, or have recipients added. The Specification’s terminal flag provides exactly that, and every host enforces it whether or not it knows what a reaction is.

Because messages are immutable, changing or removing a reaction is done by sending a newer reaction whose data replaces the earlier one.

A reaction has no Media Type of its own. Its data is UTF-8 text, and a Media Type describes representation, not intent; the intent is already carried by the flags. A reaction is therefore any terminal, no-reply, plain-text reply whose whole body is a single emoji. A person who sends exactly that as a reply meant it as a reaction, and clients that know nothing of this standard render it as the short text message it is.

Reaction Message

A message is a reaction message if and only if it has all of the following properties. There is no separate reaction type: a message is recognised as a reaction by its shape, and a message lacking any property is an ordinary message, see Recognising Reactions.

Flags

Flag bit Name Requirement
0 has pid MUST be set.
1 has add to MUST NOT be set.
2 common type MUST be set.
3 important MUST NOT be set.
4 no reply MUST be set.
5 zlib-deflate MUST NOT be set.
6 terminal MUST be set.

terminal is what prevents chaining. no reply is set in addition so that hosts and clients that predate the terminal flag, but recognise no reply, still present the reaction as something not to be replied to.

Fields

Field Requirement
pid The message hash of the subject.
from The reactor. Per the Specification the reactor MUST be a participant of the subject.
to Every participant of the subject other than the reactor, see Recipients.
topic Absent, because pid is present.
type Common Media Type ID 56, text/plain;charset=UTF-8.
size 0, or the byte length of data, which MUST NOT exceed 64.
attachment headers Count MUST be 0.
data Empty, or exactly one emoji encoded as UTF-8, see Emoji.

Emoji

Non-empty data MUST be the UTF-8 encoding of exactly one element of the Unicode RGI_Emoji set defined by UTS #51, that is a single Recommended for General Interchange emoji: a basic emoji, keycap sequence, flag sequence, tag sequence, modifier sequence, or ZWJ sequence. Fully-qualified sequences SHOULD be used.

Implementations SHOULD validate against the RGI_Emoji set of the most recent Unicode version they support. Because that set grows over time, an implementation encountering non-empty data that is a single extended grapheme cluster (UAX #29) whose code points all have the Emoji, Emoji_Component, or Emoji_Modifier property, or are ZWJ or a variation selector, SHOULD treat it as a reaction it cannot render rather than as an ordinary message.

Empty data (size 0) means the reactor has no reaction on the subject, see Effective Reaction.

Recipients

to MUST contain every participant of the subject except the reactor, so that all participants observe the reaction. The subject’s participants are its from, every address in its to, and, when the subject is an add-to batch message, its add to from and every address in its add to.

Where the reactor is the only participant of the subject this standard cannot apply, because a message requires at least one recipient; a reaction to a message one sent only to oneself is not sent.

Effective Reaction

A reactor has at most one effective reaction on a subject.

Among all reaction messages held by a host whose from is the reactor and whose pid is the subject, the one with the greatest time determines the effective reaction. If two such messages share the same time, the one whose message hash is greater when compared as an unsigned big-endian integer determines it. If that message’s data is empty, the reactor has no effective reaction on the subject. Otherwise its data is the effective reaction.

Changing a reaction is therefore sending a new reaction message with the new emoji, and clearing a reaction is sending one with empty data. Earlier reaction messages remain stored and verifiable; they simply no longer determine the effective reaction.

Because the Specification rejects a reply whose time precedes its parent’s, every reaction message has a time after the subject’s.

Sending

A reaction message is created, sent, retried, and recorded exactly as any other message per the Specification. Nothing about its delivery is different.

A client or host MUST NOT create a reaction whose subject has the terminal flag bit set. In particular a reaction cannot itself be the subject of a reaction. The Specification’s Sending Host rule enforces this for hosts that implement v0.6.0.

Receiving

A Receiving Host applies the Specification unchanged. This standard adds no header validation: a host need not recognise reactions to accept, challenge, store, and deliver one, because on the wire a reaction is a plain-text terminal reply.

Recognising Reactions

A host or client that implements this standard determines whether a stored message is a reaction by testing it against Reaction Message after the message is stored. A message meeting every property is a reaction and contributes to the effective reaction of its reactor on its subject. Any other message, including a terminal plain-text reply whose data is not a single emoji, is an ordinary message and MUST NOT contribute to any effective reaction.

There is consequently no malformed reaction and nothing to reject on the wire: a message either has the shape of a reaction or is simply a reply.

Implementations SHOULD treat a type encoded as the string text/plain;charset=UTF-8 with the common type flag bit not set as equivalent to Common Media Type ID 56 when recognising reactions; senders MUST use ID 56. Implementations MAY ignore the Recipients requirement when recognising a stored reaction, since a host cannot always know a subject’s full participant set.

Presentation

This section is non-normative.

Clients that implement this standard are expected to:

  • render, on each message, the set of effective reactions grouped by emoji with the reactors of each, rather than rendering reaction messages as replies in the thread;
  • offer a way to add, change, and clear the viewer’s own reaction on any message they are a participant of that is not terminal;
  • keep the viewer’s own reactions consistent across devices by reading the stored reaction messages rather than local state; and
  • treat an incoming reaction message as a low-priority event that does not warrant the notification an ordinary message would.

Clients that do not implement this standard see a short plain-text reply containing an emoji, or an empty one, with no reply set. That is the intended degradation, and it is why reactions carry no type of their own.

Interoperability

Peer Behaviour
Host implementing Specification v0.6.0 and this standard Accepts, stores, and delivers the reaction; exposes it to its clients as a reaction.
Host implementing Specification v0.6.0 only Accepts, stores, and delivers the reaction as an ordinary terminal message. Its clients see it as a small message. Nobody can reply to it.
Host implementing a Specification version before v0.6.0 Rejects the reaction with code 1 (invalid) because the terminal bit is a reserved bit set. The reactor’s host records the rejection like any other and its clients can show that the recipient host does not support reactions.

Security Considerations

  • Volume: each reaction is a stored message and a connection per recipient domain. The Specification’s per-connection and per-IP rate limits and per-user storage quotas apply. Hosts MAY apply stricter rate limits to messages having the shape of a reaction.
  • Rendering: implementations MUST NOT place data that is not a single RGI_Emoji in a reaction slot. The shape test is what prevents arbitrary text from being displayed as a reaction.
  • Participant rule: reactions inherit the Specification’s participant check, so an address that is not a participant of the subject cannot react to it, and a host cannot be tricked into showing one.
  • Disclosure: a reaction discloses to all participants of the subject that the reactor reacted and with what. It discloses nothing they could not already infer from being participants.

Examples

This section is non-normative.

A reaction by @bob@example.com to a message from @alice@example.com sent to Bob and @chris@example.edu:

{
    "version": 1,
    "important": false,
    "noreply": true,
    "terminal": true,
    "pid": "3f8a…c21e",
    "from": "@bob@example.com",
    "to": [
        "@alice@example.com",
        "@chris@example.edu"
    ],
    "time": 1788393600.120384,
    "type": "text/plain;charset=UTF-8",
    "size": 4,
    "data": "👍",
    "attachments": []
}

On the wire type is the single byte 56 with the common type flag bit set.

Bob later clears the reaction by sending the same message with a later time, size 0, and no data.