Skip to content

MSC4482: Ability to bookmark messages#4482

Draft
Gernomaly wants to merge 12 commits into
matrix-org:mainfrom
Gernomaly:Bookmarks-MSC
Draft

MSC4482: Ability to bookmark messages#4482
Gernomaly wants to merge 12 commits into
matrix-org:mainfrom
Gernomaly:Bookmarks-MSC

Conversation

@Gernomaly

@Gernomaly Gernomaly commented May 23, 2026

Copy link
Copy Markdown

@Gernomaly Gernomaly marked this pull request as draft May 23, 2026 16:47
@Gernomaly

Copy link
Copy Markdown
Author

Signed-off-by: xeni xeni@koeln.ccc.de

@turt2live turt2live left a comment

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.

This MSC appears to be a work in progress, so I haven't done the normal "implementation requirements" comment yet. When ready, feel free to request such a comment in the SCT Office.

Comment thread proposals/4482-ability-to-bookmark-messages.md
@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 May 23, 2026
Comment thread proposals/4482-ability-to-bookmark-messages.md Outdated
@IT-ess

IT-ess commented May 23, 2026

Copy link
Copy Markdown

I completed the proposal part. Tell me if I'm too verbose @Gernomaly
We probably need to elaborate the last parts too.

@Gernomaly

Copy link
Copy Markdown
Author

Love the additions! I am going to elaborate on the alternatives parts later today. Including the comparison that travis suggested 👍

### New room type

This MSC introduces a new room type called `m.bookmarks`.
This kind of room SHOULD only hold some `m.bookmark` events defined below.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@Gernomaly I'm not sure anymore about this one.
As said in private, I want to adapt my Refs client so it supports this MSC. However, when I need to create a personal bookmark ex-nihilo (not from an existing Matrix event), I need to send my custom Ref event somewhere, and then reference it with our new m.bookmark "pointer event".
Currently I'm using my own custom room type to store my custom events, so using just this m.bookmarks instead would be nice.
So my proposition is that instead of SHOULD only we put MAY ? Does that sound good ?

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 think should is fine, its not a must and may is too soft imo

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is SHOULD without only ok for you ?

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.

id just stay with should only tbh, its not like the should only prevents you of not adding anything else imo, and from my point of view your events are a kind of bookmark as well :P . To me it its important to at least for the moment keep the scope together a bit and adapt it if needed in the future if the protocol develops into that direction (referencing msc guide)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ok I will put back the only then. You're right we should keep it scoped to the generic usecase for now

Comment thread proposals/4482-ability-to-bookmark-messages.md
Comment thread proposals/4482-ability-to-bookmark-messages.md Outdated
}
],
"m.pointer": {
"roomId": "<roomId>",

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.

Since room IDs alone are not routable in Matrix, would you also need a via property possibly? I assume you'd normally already be in the room so maybe not? 🤔

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Our approach of pointers is kinda simple, we are ok if some pointers are just "dead". It should be up to the client to eventually clean up dead pointers (bookmarks pointing to rooms you're no longer in for instance).

Also, I guess if you don't clean a bookmark to a public room you're no longer part of, having the via parameter could help you joining this room back, so I have mixed opinions on this.

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.

Since room IDs alone are not routable in Matrix, would you also need a via property possibly? I assume you'd normally already be in the room so maybe not? 🤔

you should be in the room, or at the very least join via the server of the user who created the bookmark event. if their homeserver isn't participating in that room anymore, any via's you'd have set would also likely be useless.

if you really want to, we could use the most popular server by users that's in that room, hence having a decent chance of still being part of that room?

I don't particularly care either way, for my use case it's not necessary but I'm open to adding it.

## General

If the client support the `m.bookmarks` room type, it should'nt be displayed as a normal room in the regular room list. Instead the client could display bookmarks in dedicated sections of the client.
The client should ensure that only one `m.bookmarks` room is existing at once.

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.

Could an account data event help to let clients store the room ID of the one bookmarks room?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We imagined that but it would probably require extra work if we need to upgrade the m.bookmarks room at some point.


## Room creation

The room should be created upon first bookmark creation.

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 feels like it could be an implementation detail. Would there be any issues with letting clients create the room prematurely?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

When we discussed it IRL I remember two arguments :

  • waste of ressources
  • zero click creation of a room that contains nothing yet, so it could be weird for a user that also uses a client that does not support m.bookmarks rooms, and thus display the fallback room containing nothing.

We're aware that the first bookmark creation should be a little longer, but that is probably up to the client to make it smooth.

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.

@Johennes is that a sufficient answer to that question or do you still think we should change it?

Comment thread proposals/4482-ability-to-bookmark-messages.md
}
}
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Add the fact that each message of a room should be bookmarked at most once (maximum one m.bookmark event pointing to an event). This ensures that we have a binary state for each message: either bookmarked or not.

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.

agreed tho i dont really know how we should implement this

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I already started implementing it on the rust-sdk if you're curious. That's why I'm coming with all these questions and precisions.
Implementation is not that obvious tbh.

"event_id": "$EVENT_ID",
"via": ["$SERVER_NAME"]

}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: add a m.relates_to block on this event so we can handle editing the event with m.replace relations. This isn't very useful as is because editing the pointer or the fallback text isn't very useful, but since it is an extensible event, one may want to add extra blocks to this bookmark. We want to have a future proof event.

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.

sounds reasonable to me!

@stefanceriu

Copy link
Copy Markdown
Member

I'm sorry I didn't notice this sooner but you should have a look at MSC2437: Store tagged events in Room Account Data too:

The first use case would be to let him mark some events as favorites to keep a reference on important messages or attachments. Clients would then be able to handle a global bookmark of these favourite events, or display a list of them at the room level.

@IT-ess

IT-ess commented Jun 24, 2026

Copy link
Copy Markdown

I'm sorry I didn't notice this sooner but you should have a look at MSC2437: Store tagged events in Room Account Data too:

The first use case would be to let him mark some events as favorites to keep a reference on important messages or attachments. Clients would then be able to handle a global bookmark of these favourite events, or display a list of them at the room level.

This is a different approach. We describe why we think it is a better way from line 108, but here are the main points:

  • Account data is fetched in one go, we don't have a way to paginate it. When we store this kind of data in account data, we push data to clients that don't even need it.
  • Our approach provides a fallback "free" implementation for clients that implements Extensible Events. I admit they are few right now, but it will improve over time.
  • This implementation is way more extensible, thanks to extensible events again. One could imagine adding additional blocks to the bookmarks to implement folders for instance.

Let us know if you think this different approach is valuable enough ! @stefanceriu

@stefanceriu

Copy link
Copy Markdown
Member

I mostly wanted to link the two together. We prototyped message bookmarks ourselves in one of our hackatons (based on bnjbvr/bookmarks) in which we decided to go against #2437 and store everything in the account data, as it made building the UI we wanted easier to build.

Your solution on the other hand would take care of both paths but I do wonder if it is a specialisation of message forwarding i.e. something like #2723 in which m.forwarded is your m.pointer.

@IT-ess

IT-ess commented Jun 25, 2026

Copy link
Copy Markdown

I missed that (great) demo, thank you for the link. I was aware of this other MSC implementing things through account data, but I never saw it landing in Element X (I don't have access to the branch you mentioned), so my guess was that no effort was made in the rust sdk to implement this already.
For the record, I've made an implementation of this MSC for the Rust SDK here, there is also a small video demo linked. I may open smaller PRs to the upstream, but I'm not sure if its required or necessary since there is already a concurrent implementation 🤷

About the m.forwarded block, they are indeed very similar except we don't require the sender and timestamp in m.pointer. We could eventually reuse the same block, but I'm afraid that in terms of naming m.forwarded feels pretty specific related to m.pointer.

@Gernomaly

Copy link
Copy Markdown
Author

About the m.forwarded block, they are indeed very similar except we don't require the sender and timestamp in m.pointer. We could eventually reuse the same block, but I'm afraid that in terms of naming m.forwarded feels pretty specific related to m.pointer.

It might actually be an idea to think about as a protocol if we should resuse "m.pointer" for "m.forwarded" in the future

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.

6 participants