Collaborative live-editing of Nostr documents

One guiding principle and one vague implementation idea

Dec 14

opened this issue about collaborative editing in the NIPs repo today, and since I was thinking about this same topic days ago I'll write my thoughts here.

These things can be achieved in multiple ways, but it seems to me that they will be more in the spirit of Nostr if we can come up with a scheme that is backwards-compatible with existing document formats (for example, kind 30023 Markdown articles) that allow these things to continue to be used as they are but also be enhanced with live-editing and other stuff.

The idea

A generic CRDT-based scheme for editing stuff collaboratively can be created using ephemeral (kind 2xxxx) events. Clients can choose to only listen to CRDT-edit events only from previously-authorized people.

This scheme would exist on top of static parameterized-replaceable (kind 3xxxx) event documents, that would be saved and published every now and then during the edit session and in the end of it. This could work on top of normal Markdown articles (kind 30023), for example, but also on top of Notion-like documents, spreadsheets or richtext documents if we get a standard kind for these, or any other standard format.

The flow

In the case of a Markdown document edit the flow would be something like:

  1. Alice creates an event kind 30023 with d set to "hello-world" and starts writing.
  2. In the process, she emits a bunch of crdt-edit (kind 21333) events to whoever is listening and wants to follow her writing process live.
  3. Then Alice invites Bob to edit the document with her, she creates a collaboration (kind 31333) event informing others that Bob has some authority over her "hello-world" document too. Now people watching the document will also listen for crdt-edit events from Bob.
  4. Alice is also listening for Bob's crdt-edit events and her client updates the document locally for her upon receiving those. Bob does the same with Alice's edits.
  5. Every now and then, or when they stop editing, both publish their own event kind 30023 "hello-world", these two versions can still be viewed by anyone "statically" while they're sleeping, and by clients that don't support the live-editing madness. Users will default to reading Alice's version, but if they are able to read the related collaboration event they may decide to check Bob's version to see if there is any update there.

Now suppose Bob starts editing the document again while Alice is sleeping:

  1. Bob will have an updated document version and Alice won't, so when Alice comes back online she fetches Bob's updated document and sees it's different from hers. Here there are three possible ways to handle the situation: a. Alice just updates her local document to Bob's version -- this is fine for all the situations in which Alice hasn't edited her document too while Bob was sleeping and now they have diverged, for these situations there are two possible alternatives: b. Special relays keep the crdt-edit events for a while (these events are ephemeral by default, but nothing prevents some relays to choose to store them) and Alice can replay them when she comes online. c. Bob could have published a packaged-crdt-delta (kind 31334) event containing all the edits since the last time Alice had published a kind 30023 along with his last kind 30023 which Alice can then fetch and merge with her stuff locally. Alternatively, special relays can produce this document based on all the crdt-edit they receive. I'm not sure what option is better.

The end

This is probably too confusing, so I'll refrain from commenting until there is some working code that proves it's possible. The Automerge library seems to be a nice fit for making this stuff on top, even though it is a library and not a protocol that strives for backwards-compatibility like Nostr it might be a fine tradeoff for this specific use case.