An ActivityPub Philosophy

This is going to be a look at my philosophy and views on ActivityPub and why I believe the solutions to ActivityPub criticisms must come from communities. I believe there needs to be a clear way for communities to form and build upon the ActivityPub specification. The public needs to do so while keeping the cost to participate as close to zero as possible. At the end, I will present a concrete solution of extending ActivityPub to help organize its own extensions.

I’m going to assume that the reader is familiar with the ActivityPub protocol or at least familiar enough such that I don’t need to give background information.

Background: Go-fed and I

I don’t expect folks to know me. On Mastodon I am @cj@mastodon.technology. I have been working on an ActivityPub library implementation in golang [go-fed] for a little over a year. I started back in late November or early December of 2017, just before the ActivityPub spec matured. Due to the complicated technical solution required, it took me quite a long time to have a first release. It’s taken me another six or eight months to work toward the next major release of go-fed. Also, building a library means I don’t have direct end-users like other projects have. Honestly, I don’t mind. It has allowed me to think much more about general development practices around ActivityPub since my direct users are other software developers.

So please consider this post a year in the making.

The Incomplete Philosophy & Fediverse of Flavors

I want to give an overview of a philosophy that I’ve adopted while working on ActivityPub. Succinctly: I view ActivityPub as a transport protocol that alone is not sufficient to build an application.

It’s not meant to dictate what an application is, nor its domain’s behaviors, nor its domain’s side effects. There are two kinds of federating: transmitting data and dictating peer app behavior. ActivityPub is a minimalistic protocol governing the sharing of information and the most sparse set of side effects in order to allow federation (transmission) between peers. It doesn’t dictate federation (app behavior) between peers for all domains. Anything more than just sending and receiving information needs to be built on top of ActivityPub as an extension.

ActivityPub alone is not a specification that solves all domain behaviors.

It has taken me a long time to realize this. ActivityPub doesn’t make it easy to adopt this philosophy because it also happens to contain its own “ActivityPub extension” specifically for the social media domain. This is why social media applications have adopted ActivityPub – the “ActivityPub extension” for the social media domain is itself embedded and hidden within the original ActivityPub specification. The ActivityPub specification handles both kinds of federating (transmission and app behavior) for the social media domain to a certain degree.

On the other hand, a code forge application would use ActivityPub to guarantee it can physically transmit and receive data federatively. But the ActivityPub specification alone is insufficient at dictating what other code forge applications may or may not do with the data. That requires building an ActivityPub extension by the code forge community. I think this is a fundamental issue that some folks have with ActivityPub. It does not dictate to peers what it may or may not do with the data they receive and the expectations around handling such data for other domains.

When looking at ActivityPub as an incomplete specification, there are some neat consequences. I have a cheesy metaphor for it. Building on ActivityPub allows creating different “flavors” of Fediverse: a social media one, an economic one, a code forge one, an educational one, and so on. Despite all the different flavors of Fediverse, they are all still a part of the same network. Developers may have their apps freely pick and choose which flavors of Fediverse to use to build the user experience they want from a single-flavor microblog to a multi-flavor code-forge-managed-by-an-economic-co-op. These “flavors” are simply different domains.

Also, each developer’s application doesn’t have to develop their own standard. They could, but I think it’s more preferable that each domain of the Fediverse builds one or more independent communities to standardize their specific solutions through the use of ActivityStreams extensions. Concretely, all that needs to be done is to define new ActivityStreams types and properties, as well as new expected behaviors when handling these types and properties. This is similar to Sections 6 and 7 of the ActivityPub specification. From there, developers would look only at the flavors they cared about and pick those additional behaviors to implement.

Unfortunately, when the ActivityPub protocol was published there was neither guidance nor support on how to build these communities, how to develop more specialized domains, or how to organize more rigorous behaviors around the data being shared. And there still isn’t.

If this mindset seems alien or the philosophy is hard to take seriously, let’s step back and reframe ourselves. ActivityStreams comes as a form of RDF data known as JSON-LD. In contrast to the modern web which uses HTTP to serve and share hypertext documents linked together by hyperlinks, ActivityPub uses HTTP to serve and share structured-data JSON documents linked by IRIs. REST follows this model closely, so none of this is surprising. However, ActivityPub takes it one step further by specifying a way to transmit this data without having to build (or code generate) custom REST client endpoints. This is a key differentiator, but at a cost.

The cost is that developers who are used to an application-specific mindset struggle with viewing ActivityPub as a purposefully incomplete specification since it doesn’t specify federating (app behavior) in all domains. This is exacerbated by ActivityPub being touted as a complete specification. When comparing against application-specific REST APIs that are concrete, it makes sense that forcing ActivityPub upon this community is bound to generate criticisms along the vein of “it’s underspecified,” “it’s ambiguous,” and “look how I can write a broken compliant application.”

While I tend to view those particular kinds of criticisms as simply stemming from a philosophical difference, there are a lot of remaining criticisms I agree with. Issues such as security, discoverability, or lacking certain social media features. I really do think the next steps involve building the community of developers and interested non-technical folks in such a way that allows for multiple independent specifications to build off of ActivityPub.

The Future: Addressing Criticisms & Expanding Domains

I don’t expect people to buy into my mindset or philosophy on what ActivityPub is and what those next steps should be. At minimum, I hope folks that reject it at least appreciate where I am coming from. I know it’s very easy to discuss general principles and philosophies, so now I would like to offer my own personal fantasy, in concrete terms, of what could be in store for the future. To do so, I need to identify the problems it is solving.

The first problem is getting different ActivityPub communities to self-organize to solve their own domain problems, build their own specifications on top of ActivityPub, and hold each other accountable at sticking to those specifications rigorously. A second problem is discoverability of these specifications for fellow developers without having a centralized organization hosting a registry or dictating a process. The cost of extending ActivityPub should always remain as close to zero as possible for numerous philosophical and moral reasons that I don’t want to get into here.

Note that there is some prior art. ForgeFed has solved the first problem by hosting a repository on GitHub and having a mailing list at Framasoft. They organized their own process and collaborated to build and create several proposals. So there is some evidence that existing tools can be sufficient for solving the self-organizing problem. However, it does not solve the second problem of getting would-be ActivityPub developers to discover these extensions.

My simple proposed fantasy is: Why not build on top of ActivityPub to solve both of these problems?

First, we as a community create an ActivityStreams extension and define behaviors to document the specifications built on top of ActivityPub. We now have a way to store ActivityPub extension specifications in the Fediverse itself. Next, building an application server that understands this extension and can federate it over ActivityPub means anyone can simply host an instance, allow users to register, build its community, and be free to draft new specifications on top of ActivityPub. Since this data is then federated by ActivityPub itself, it is reachable by both technical and non-technical users. There is neither a central authority nor a central registry as each community is responsible for its own ActivityPub specifications. This is the democratization of ActivityPub across all domains. People cannot have their ActivityPub extension specification censored. As long as the core ActivityPub protocol as currently written is followed, federation compatibility naturally leads to new domains and apps implementing them.

As hosts of these specs, we would all have to be good citizens and not purposefully and maliciously create specifications that collide namespaces or repurpose existing semantics from other specs in ways that are incompatible. Instances and specific specs may become blacklisted if obviously malicious. My fantasy solution does not solve these human problems, but it is not meant to. It’s meant to help facilitate human interactions. I concede this proposal will make protocol purists uncomfortable with the idea of bringing humanity so close to the heart of a technical process. I know some folks are pessimistic about humans and would prefer technology solve human problems. But in my experience, and based on my analysis of the criticisms, that is not the kind of solution that I think is needed.

My proposed solution is the complete manifestation of the philosophy presented above. It is applying itself to better itself.

What do you think?