Lab Notes #005: Semble <-> Margin Interop

Today is a big day for Semble because we took a big step towards a more interoperable social web — one of the main reasons most of us build on atproto in the first place! @tynanpurdy.com put it best:

View post on Bluesky

We've just shipped our side of a collaboration with @margin.at. Less than two weeks ago we agreed on a complimentary and straightforward form of interop without sharing lexicons. Here are the details of how that works, what it looks like, what's missing, and where things can go moving forward.

How it works

There are nine types of records in Margin, and three of them map perfectly to existing concepts in Semble: bookmarks, collections and collection items (to indicate that something is in a collection). In Semble, these are: cards, collections and collection links.

We've designed our internal representations of these concepts to not depend on specific ATProto details. This approach is part of our layered architecture, something which we will outline in a future post.

What this means is that Cards and Collections are represented as separate entities from their corresponding ATProto records, which are referenced via their StrongRef (aturi + CID). It looks a bit like this:

In fact, our AppView (are we still calling them this??)

...doesn't care what exactly the atproto record looks like, so long as there is a way to map it from the record to the card (basically, does it represent a URL in some way?). This is intentional so that things can evolve and change at the protocol / infrastructure layer without causing upstream breaking changes to our inner layers (especially the domain layer, again, more on this in a future post). It also means that a card can point to records of differing lexicons, like at.margin.bookmark. Making it look a bit more like this:

As long as we can map at.margin.bookmark to a Card, at.margin.collection to a Collection and at.margin.collectionItem to a Card within a Collection, we can ingest them from the firehose just like we do with network.cosmik.card, network.cosmik.collection and network.cosmik.collectionLink record events, the only difference being the mapping step.

The same idea works for Collections, and adding Cards to Collections. After the mapping step, everything else works the same way as it normally would (e.g. the library count will reflect the total number of accounts from both Margin and Semble).

Lastly, Semble also backfills Margin data, so any of your Margin bookmarks or collection made prior to today will also show up in Semble (we perform a lazy sync, so it only gets triggered once you either save a card in Semble or create a bookmark in Margin).

What it looks like

Margin bookmarks will appear the same as Semble cards, with a margin logo present (linking to a view of it on margin). The explore feed can also be filtered by source, making it easy to discover content being shared in either or both apps.

Collection pages also include the Margin logo, which links to Margin.

You can add Cards from Semble or Margin to Collections from Semble or Margin. Likewise, you will see your Semble Cards and Collections in Margin. Cross-pollinate as you see fit!

What's missing?

Margin has two other record types relevant to Semble: highlights and annotations. Since these concepts don't yet exist in Semble, we currently ignore them. Eventually this will change, but for now, you won't see your Margin highlights or annotations in Semble.

What's next?

In the near term, we want to include highlights and annotations within Semble by including them on the Semble Page and as a separate activity type:

In the mid term, we want to support Semble highlights and annotations directly as a card type, not just an activity type, which means they could be added to collections directly.

In the long term, we would love to align on shared lexicons for annotations, bookmarks, collections and any other pattern that is commonly shared across apps (not just Semble and Margin). We are inspired by @standard.site and see a similar initiative as a pathway towards longer term interoperability.

The best part about this all is that it shows how the Atmosphere has no walled gardens.

Happy cross-pollinating y'all 🐝