Skip to content

MSC4357: Live Messages via Event Replacement - #4357

Open
DonPrus wants to merge 1 commit into
matrix-org:mainfrom
DonPrus:msc-live-messages
Open

DonPrus wants to merge 1 commit into
matrix-org:mainfrom
DonPrus:msc-live-messages

Conversation

@DonPrus

@DonPrus DonPrus commented Sep 16, 2025 •

Copy link
Copy Markdown

Summary

This MSC proposes "Live Messages": recipients see a message evolve in real time while it is being typed.
It leverages existing m.replace edits on m.room.message (no new event type), marked by an unstable
flag in content to denote a "live session". Non-supporting clients gracefully degrade to a normal edited
message; supporting clients render a smooth, streaming-like UX.

What this adds

  • Identification: initial message carries org.matrix.mscXXXX.live: {}; subsequent updates use m.replace
    with full m.new_content; the final update omits the live flag (session complete).
  • Control: optional state event m.room.live_messaging (enabled: boolean) to allow room-level opt-in/out.
  • Server: no new endpoints; existing relations/aggregation apply; admins may rate-limit high-frequency edits.

Backwards compatibility

Old clients see "a message with edits" and always end up with the final content.

Rendered Markdown
Rendered: proposals/4357-live-messages.md

Author

Author: @DonPrus

Signed-off-by: Igor Somov <donprusne@gmail.com>
@DonPrus DonPrus changed the title MSC: Live Messages via Event Replacement (draft) MSC4357: Live Messages via Event Replacement (draft) Sep 16, 2025
@DonPrus DonPrus changed the title MSC4357: Live Messages via Event Replacement (draft) MSC4357: Live Messages via Event Replacement Sep 16, 2025
messages.
- **Storage**: Live sessions produce more events. Deployments can rely on retention policies and rate-limits.

## Alternatives

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conceptually this proposal sounds similar to #3489 (live location sharing). That one uses a state event and reference relations though. Replacements strike me as a more intuitive solution though.

@DonPrus DonPrus Sep 16, 2025 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree the concept is similar to MSC3489 in that both stream incremental state. For live text, I believe m.replace on m.room.message is the most intuitive and compatibility‑friendly primitive: older clients already understand “edits” and will converge to the final content; supporting clients can render the intermediate states seamlessly. It also avoids adding a new event type purely for live typing and reuses the well‑understood edit aggregation path (per MSC2676 / spec).


### Semantics:

- If absent, default is enabled (unless server policy states otherwise).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC the enforcement can only happen on the client side. This means clients would need a way to discover such global server policy?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the draft I wrote “default is enabled (unless server policy states otherwise)”, which is ambiguous without a standard way to advertise that policy. I propose to clarify that the normative control here is room‑level via m.room.live_messaging; clients MUST honor it. Servers MAY reject live‑marked events in unencrypted rooms as a local policy, but there is no standardized discovery for a global ban, so it’s out of scope for this MSC. I’ll remove/adjust the “unless server policy states otherwise” wording to avoid implying a discovery mechanism that doesn’t exist


- If absent, default is enabled (unless server policy states otherwise).
- If `enabled: false`, clients **MUST NOT** offer live mode in this room.
- Servers **MAY** enforce rejection of events that carry live markers in rooms where it is disabled.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only possible in unencrypted rooms because org.matrix.msc4357.live is in content which is encrypted.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, feature still works end‑to‑end (supporting clients decrypt, detect the marker, and render progressively), but enforcement and special aggregation are client‑side only in E2EE. I’ll add an explicit “E2EE considerations” subsection stating that server‑side enforcement is only feasible in unencrypted rooms.

update replaces the entire content (`m.new_content` reflects the complete current text).
- **Completion**: on explicit send or mode exit, send a final update without the live marker. After this, do not send
further updates for this session.
- **Rate limiting**: clients **MUST** avoid flooding and respect server guidance; batching is encouraged.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does batching mean combining several updates into a single event replacement?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By batching I mean coalescing local interim changes and emitting a single m.replace update at a bounded cadence (e.g. every ~2–3s or at natural boundaries like end‑of‑word), rather than sending an event per keystroke. Each update still contains the full current content in m.new_content; there’s no special “multi‑update container”. I’ll tighten the wording to make this explicit.

Comment on lines +38 to +39
- **Completion**: on explicit send or mode exit, send a final update without the live marker. After this, do not send
further updates for this session.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it allowed to transition back from completion into live mode?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intend completion to be terminal for that message. Once the final update (without the live marker) is sent, the live session is over. Further changes are normal edits; resuming live mode should be done by starting a new live message. Allowing a message to re‑enter live mode risks confusing clients (especially non‑supporting ones) that have already treated it as finalized. I’ll add a normative MUST‑NOT to make this explicit.

@turt2live turt2live added proposal A matrix spec change proposal. Process state. A-Client Server Client-Server API kind:feature MSC for not-core and not-maintenance stuff needs-implementation This MSC does not have a qualifying implementation for the SCT to review. The MSC cannot enter FCP. labels Sep 16, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation requirements:

  • Client (sending)
  • Client (receiving)

@Saiv46

Saiv46 commented Oct 23, 2025 •

Copy link
Copy Markdown

Shouldn't we use Sticky Events from MSC4354? It seems a perfect fit for live messages. Then on completion just send ordinary message without the edits.

Otherwise users would hit into existing rate limits by constantly updating a single message.

gumadeiras pushed a commit to TigerInYourDream/openclaw that referenced this pull request Apr 10, 2026
When the Matrix channel plugin uses `streaming: "partial"` mode, the
draft preview messages and their progressive edits now carry the
`org.matrix.msc4357.live` marker. This allows supporting Matrix clients
(e.g. Robrix) to render a streaming animation while the LLM is
generating a response, instead of showing repeated edit flashes.

Flow:
1. Initial draft message is sent with `org.matrix.msc4357.live: {}`
2. Each progressive edit also carries the live marker
3. When the stream completes, a final edit is sent WITHOUT the marker,
   signaling to clients that the stream has ended

Non-supporting clients are unaffected -- they see normal message edits
as before, gracefully degrading to the existing behavior.

Ref: matrix-org/matrix-spec-proposals#4357
@Saiv46 Saiv46 mentioned this pull request Apr 16, 2026
4 tasks done
@toger5

toger5 commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

@Saiv46 Sticky events solve a different problem:

  • On sync I want to guarantee users download a specific event.

This MSC seems to be targeted so that If I am already looking at an event i can see updates.
Which does not need to be "force synced" if I dont look at the tile containing this "update stack" I am not interested in those events, so they can be fetched via a pull approach.

Sticky events are useful if you want a timeline item to (for at most 1h) have an impact on the room list even for gappy syncs where you are not yet actively viewing a room.
Like for call participations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Client Server Client-Server API kind:feature MSC for not-core and not-maintenance stuff needs-implementation This MSC does not have a qualifying implementation for the SCT to review. The MSC cannot enter FCP. proposal A matrix spec change proposal. Process state.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants