Skip to content

Communities

A community (what other chat apps might call a “server”) is where people gather into categories and channels to talk. In a conventional app the backend owns all of that data. Colibri works differently: a community is itself an AT Protocol identity.

A community is a set of gated spaces whose authority is the community’s DID. Each member’s messages live in that member’s own repository, and a reader reaches them through the space that holds them.

Where community records are storedEach member's own repo holds the records they author, including messages, reactions and their personal preferences. The community is a single DID whose repo holds its structure and its authoritative member and moderation records, written by the AppView that holds its credentials. A permissioned space is not a container. It is an access-controlled view across every repo that writes into it, and the AppView reads each one directly using a space credential.A space is a view across bothat://authority/space/type/skey/author/collection/rkeysyncwritessyncYour repoon your own PDSsocial.colibri.*messagereactionlabelactor.profileactor.muteactor.settingschannel.readAppViewsyncs every repoThe community's repoone DID, one communitysocial.colibri.*community (self)community.settingscategorychannel (self)rolemembermoderation

All six have the community’s DID as their authority.

Space type Key Holds Who can read
social.colibri.beta.community.profile self the community record anyone, unless the community is private
social.colibri.beta.community.configuration self settings, categories, labels members
social.colibri.beta.community.members self members, roles, labels members
social.colibri.beta.community.moderation self the moderation log holders of moderation.viewLog
social.colibri.beta.channel.text tid channel, messages, reactions, labels per channel
social.colibri.beta.channel.voice tid the channel record per channel

The first four are created once, when the community is created. The last two are space types, and a community has one space of that type per channel.

There is no channel container that holds messages. The space is the channel. Its key is the channel’s identity, and the channel’s own configuration lives at record key self inside it.

Creating a channel creates a space, and deleting one deletes the space. Adding a new kind of channel later means adding a new space type.

Each user also has one space of their own, social.colibri.beta.actor.preferences, whose authority is the user’s own DID. It holds their mutes, their settings and their read cursors, none of which anyone else has any business reading.

Its policy is an empty member list. The space manager authorizes the owner before it consults the policy, so the owner always gets in and no one else ever does.

Which repository a record is written to tells you who is accountable for it.

The AppView holds the community’s credentials and writes these on its behalf. They are the community’s structure and its authoritative state.

Record What it is
social.colibri.beta.community The community definition, at key self in the profile space.
social.colibri.beta.community.settings Category order, join approval, link embeds, and the labelers this community honours.
social.colibri.beta.category A category, holding an ordered list of channel keys.
social.colibri.beta.role A role and its permissions.
social.colibri.beta.member A member: their DID, their roles and when they joined. Keyed by the subject’s DID.
social.colibri.beta.channel A channel’s configuration, at key self in the channel’s own space.
social.colibri.beta.moderation The append-only log of bans, unbans and kicks.

social.colibri.beta.member is keyed by the subject’s DID, so looking someone up is a direct fetch rather than a scan, and a community cannot hold two member records for the same person.

Written by the user, to the user’s own repository, and read through the space.

Record What it is
social.colibri.beta.message A message. Its space is the channel it was sent in.
social.colibri.beta.reaction A reaction, targeting a message by author and key.
social.colibri.beta.label A label on some content, if the user is one of the community’s labelers.
social.colibri.beta.actor.profile The user’s Colibri profile. This one is still public.
social.colibri.beta.actor.mute One muted subject, in the user’s own preferences space.
social.colibri.beta.actor.settings Notification level, community order, GIF favourites.
social.colibri.beta.channel.read Read cursors, one record per community.

Your messages are stored in your own repository. You own them, they travel with your atproto identity, and deleting one is an ordinary record deletion. They are not public: a reader needs a credential for the channel’s space to see them at all.

Joining is the social.colibri.beta.community.join procedure. The AppView checks the invitation or the community’s join policy, and either writes the member record or records a pending application. Nothing is reconciled between two repositories, and there is no state where you are half joined.

The consequence of joining is that the AppView will start answering “yes” when the community’s PDS asks whether you may read that community’s spaces.

  1. Creates an account on the configured PDS and stores its password, encrypted.
  2. Creates the profile, configuration, members and moderation spaces.
  3. Writes the community record, an Owner role holding every permission, and a member record for the creator.
  4. Seeds a usable layout: a general text channel and a General voice channel, each in its own space, grouped into a “Text channels” and a “Voice channels” category.

Channel spaces are created before the record that describes them, so a failure part way through leaves an empty space rather than a record pointing at nothing.