Today, Habitat is sharing Chalk, a document editor built on top of atproto spaces and our API for relationship-based access control. We built Chalk because we wanted to demonstrate how atproto spaces can support rich permission-ing beyond big-web social use cases that they were designed for. At Habitat, we're interested in enabling the organizations to own the data underneath the tools they use to communicate and collaborate. We think the future of these tools will be similarly ~atmospheric~, in the sense that data from one may be reused and remixed in others. However, these workplace tools need fine-grained permissions and access controls over small artifacts such as documents, pages, calendar invites, etc.
As an early proof of concept that spaces can support this, we prototyped Chalk, a collaborative document editor that embraces atproto's data ownership model. Each user contributes changes to their own PDS space repo and our AppView uses spaces to sync and merge those changes into a shared document. Importantly, all of the information needed by the AppView is written into the space. This means other AppViews can use the same data to interoperate, enabling cross app collaborative editing.
Screenshot of Chalk:
Chalk utilizes a couple technologies including some of our own recent releases:
Uses the space proxy to let user's sign in with existing atproto accounts but upgraded with the proposed spaces API (not using the alpha spaces PDS'es)
sap to sync permissioned spaces from the PDS into the Chalk AppView
Our relationship based access control API to support "viewer" vs "editor" roles and also to replicate and enforce permissions from the AppView
Yjs CRDTs to encode document updates
Cloudflare durable objects to handle realtime updates
How it works
We think of spaces as encapsulating a permission boundary. Since every doc has its own readers and writers, we create a new space per doc.
Example view of a space
Using our ReBAC API, we can specify which users have permission to write into the space + add other collaborators ("editors") and which users can only read from the space ("viewers"). Since this information is encoded as "relation" records in the space itself, AppViews can crawl that information and enforce those same rules at request time. Of course, even if an AppView doesn't enforce write rules, the underlying space itself is well permissioned and will only expose repos of members with sufficent roles.
A writer relation to a doc
Our ReBAC API also partially solves the space discovery problem with network.habitat.relationship.listRelatedSpaces so users can see which docs they've been granted access to in their home page.
"Shared with me" view in Chalk
Whenever a user wants to contribute to a doc, they write a Yjs CRDT update diff into their repo within the doc's space. An AppView that syncs that space will be notified whenever there are new updates. The AppView can construct the full doc from each of these diffs and serve it to the user.
Since the spaces sync protocol notifies registered AppViews for updates, an AppView can subscribe to updates from all editors in the space including those from other AppViews! Each PDS can't guarantee timely delivery of these notifications though. We're currently using Cloudflare Durable Objects to paper over the realtime updates within our AppView. However, we're thinking about building realtime pubsub rooms around spaces that all AppViews could subscribe to (more on that in future posts 👀).
Try it out yourself!
Head on over to https://chalk.habitat.network and sign in with your regular atproto account. You can inspect the records being written at https://home.habitat.network. Let us know about any issues, questions, or any ideas around Chalk, spaces, ReBAC etc on our Discord: https://discord.gg/dCQ6YUMGPx
Excited to keep the discussion going and continue our road to release series with more mini launches like this!
-Habitat team 📑