Groups are a shared context for communications organized around bounded membership in a set of group members. Membership in a group is distinct from following the group; being a follower entails potentially receiving future activities published by an actor, but being a member entails a social role within the group independently of whether activities are received. This document explores ways to create and manage groups within the ActivityPub ecosystem.

Introduction

What is a group?

In a social setting, activities can be bound to various contexts. These contexts can be things like:

Popular implementations of ActivityPub (and popular social networking and social media services) have unfortunately historically neglected support for binding resources to context, in a problem known as context collapse. In particular, the social ecosystem widely lacks primitives for posts having authorship and audience bound to a consistent but dynamic collective group.

In social psychology, groups are established based on a shared purpose or identity that mediates group activities. For example, users hosted on the same network or service do not necessarily share any common identity. You could describe a "collection of all users on this service", but this is not necessarily the same as a "group". The quality that defines a "group" is its entitativity, or the perception of being a group (from [[[understanding-social-groups]]]). It is only when the Group becomes a "real" "entity" (or is "reified") that we can consider it a Group (and not simply a Collection of actors). We can describe properties of the group separately from properties of its members, and separately from properties of the collection.

How does this work differ from other uses of the word "group"?

The term "Group" is used in other contexts in ways that may or may not align with the use of the word "Group" in this document.

Relation to FOAF (Friend Of A Friend) "Group"

The [[[FOAF]]] is one of the earliest vocabularies to define a concept of a "Group", alongside other social concepts. In particular, relations like "member" and "membershipClass" can be used to describe who is a member of the group. FOAF defines "Group" like so:

The Group class represents a collection of individual agents (and may itself play the role of a Agent, ie. something that can perform actions).

This concept is intentionally quite broad, covering informal and ad-hoc groups, long-lived communities, organizational groups within a workplace, etc. [...]

Relation to vCard "Group"

The [[[RFC6350]]] defines a KIND of "group" like so:

a vCard representing a group of persons or entities. The group's member entities can be other vCards or other types of entities, such as email addresses or web sites. A group vCard will usually contain MEMBER properties to specify the members of the group, but it is not required to. A group vCard without MEMBER properties can be considered an abstract grouping, or one whose members are known empirically (perhaps "IETF Participants" or "Republican U.S. Senators").

All properties in a group vCard apply to the group as a whole, and not to any particular MEMBER. For example, an EMAIL property might specify the address of a mailing list associated with the group, and an IMPP property might refer to a group chat room.

The concept of membership, while optional, is one of the defining features of a group according to vCard. It is possible to describe membership in a group using both the vocabulary of vCard and the vocabulary defined in this document.

Relation to Activity Streams 2.0 "Group"

The [[[activitystreams-vocabulary]]] defines a Group only in the most general terms:

Represents a formal or informal collective of Actors.

The groups described by this document can be said to be instances of https://www.w3.org/ns/activitystreams#Group, but they carry additional considerations. Activity Streams 2.0 does not define a concept of membership within a "Group".

Note that the membership concepts defined in this document can be used with other types, and the protocols for managing membership depend on the presence of properties rather than the presence of types.

Relation to ActivityPub and "followers"

[[[activitypub]]] defines an actor system where activities can be published to outboxes and pushed to addressed audiences as notifications. Primarily, ActivityPub defines a way to manage "followers" via the "Follow" activity, which one can later "Accept" or "Reject":

The follow activity generally is a request to see the objects an actor creates. This makes the Followers collection an appropriate default target for delivery of notifications.

However, binding all social contexts to the concept of "followers" limits the range of social contexts that people can participate in. Being a follower does not carry any inherent social considerations beyond a simple desire to see more activities from a certain actor. Also, the concept of members is distinct from the concept of followers; it is possible to be a member without receiving activities intended for followers.

Relation to FEP-1b12 "Group"

[[[FEP-1b12]]] uses the Activity Streams 2.0 "Group" term directly, but assumes that any or all "Group" object necessarily adheres to the protocol requirements laid out in the FEP. In FEP-1b12, a "Group" receives activities in its inbox, and publishes activities to its ActivityPub followers where the type is Announce and the object of the Announce is the received activity (instead of forwarding from inbox as defined in ActivityPub).

The groups described in this document are not constrained in which activities they produce. It is possible to produce Announce activities in accordance with the aforementioned FEP, but this is not a requirement of this document.

Relation to MLS "Group"

[[[RFC9420]]] and [[[RFC9750]]] define a notion of a "group" as a shared cryptographic state:

A client that is part of a group is a member of that group. As groups change membership and group or member properties, they advance from one epoch to another and the cryptographic state of the group evolves.

This document's notion of groups similarly allows for binding state to the group context, but without a strong requirement of cryptography or encryption.

Relation to similar concepts on other platforms

Some platforms implement "group" functionality, although it may not be called a "group".

  • Some social networking services have "groups" which users can join or leave as members, and a single context for posts known as a "wall".
  • Some social communication platforms have "guilds" which contain members and roles and invites, and allow members to post in multiple contexts called "channels" within the guild. (In some cases, the user-facing term for this functionality is "servers"; although at a service level these guilds may be hosted on the same server, they can be thought of as virtual servers.)
  • Various messaging platforms have "rooms", which maintain a list of members that pass messages to each other.

How does this differ from other Social CG task forces?

Relation to Forums and Threaded Discussion Task Force

A popular conception of "groups" is as a sort of forum. However, while the Forums task force deals with the organization of posts into threads and/or forums, the Groups task force deals with the organization of actors into groups which have members and roles. Thus, the work of these two task forces is complementary.

Relation to End-to-End Encryption (E2EE) Task Force

Since MLS is designed around a concept of "groups", alignment between this document's model of groups and the MLS model of groups can allow implementation of the group architecture via an MLS group's application data, and opening the possibility of both authenticated and encrypted groups.

Terms defined

Member

URI
https://swicg.github.io/groups/#Member
Label
membership record
Comment
Tracks membership-related state within a group context.

members

URI
https://swicg.github.io/groups/#members
Label
has a group members collection
Comment
Contains membership records for all members in the group, both inactive and active.
Domain
Group
Range
Collection

memberships

URI
https://swicg.github.io/groups/#memberships
Label
has a memberships collection
Comment
Contains memberships records which refer to you. When you join a group, its corresponding membership will be added to this collection. When you leave a group, its corresponding membership can be deleted and/or removed from this collection.
Range
Collection

User stories

Groups

For information about the group:

Membership

For voluntarily managing one's own membership:

For managing other people's memberships in a group you are authorized to manage:

Roles

Invites

Posts

Potential approaches

Define side effects for the Join activity similarly to ActivityPub's Follow activity

ActivityPub defines a flow for Follow, Accept, Reject, and Undo activities with the following states:

NONE
No follower relation exists. To establish one, a new Follow request must be sent.
PENDING
A Follow activity has been sent, but the Follow activity is not the object of any future Accept, Reject, or Undo activity.
FOLLOWER
An Accept Follow exists, and the Accept is not the object of any future Undo activity, and the Follow is not the object of any future Reject or Undo activity.

And the following state transitions:

This design from ActivityPub has the following shortcomings and issues:

It can seem appealing to mirror the Follow activity flow and its side effects, but with the Join activity instead of the Follow activity -- perhaps assuming that familiarity with the existing Follow flow will make it easier to implement a parallel Join flow. However, doing so inherits all of the aforementioned issues and would lead to a repeat of the implementation errors faced in practice.

A more robust approach with ACID compliance

To address the shortcomings of the mirrored flow described above, we need a design with the following properties:

Membership records

The simplest way to create a membership record is to rely on something like HTTP PUT at an indexed location:

					PUT /members/alice.example HTTP/1.1
					Content-Type: application/activity+json

					{
						"type": "_:Member",
						"_:user": {"id": "https://alice.example"},
						"name": "arisu"
					}
					
PUT a membership record into the group's members collection for alice.example. Alice's display name in the group is set to "arisu", overriding Alice's default name (which is not stated here).

Alternatively, HTTP POST can be used instead, to let the members collection choose the resulting Location:

					POST /members/ HTTP/1.1
					Content-Type: application/activity+json

					{
						"type": "_:Member",
						"_:user": {"id": "https://alice.example"},
						"name": "arisu"
					}
					
POST to the group's members collection for alice.example. Alice's display name in the group is set to "arisu", overriding Alice's default name (which is not stated here).

The response might show that the membership is pending:

					HTTP/1.1 201 Created
					Location: https://group.example/members/01KSQFYKVAGWH0HW09QMTD2VC9
					Content-Type: application/activity+json

					{
						"type": "_:Member",
						"_:user": {"id": "https://alice.example"},
						"_:pending": true,
						"name": "arisu",
					}
					
The membership record has been created.

In this case, the member and the user are not the same -- the member wraps the user. Similarly, metadata about your membership within a group is not metadata of the actor. We can use membership records/entities to achieve this separation.

Using Join to describe actually joining

In MLS, clients are added to groups via Proposal/Commit, and then separately receive a Welcome message that contains the keying material needed to actually join the group. This "add before join" pattern means that the Join does not exist before the client has actually joined the group.

Per MLS Architecture Section 3.7 "Users, Clients, and Groups":

Note that until a client has been added to the group and contributed to the group secret in a manner verifiable by other members of the group, other members cannot assume that the client is a member of the group; for instance, the newly added member might not have received the Welcome message or been unable to decrypt it for some reason.

We could have the new member confirm their membership with a Join activity (which gets republished to the group's outbox), instead of using the Join activity to manage the membership itself.

Changelog

Initial CG Draft