I’ve uploaded the first version of bovine to pypi, you can find it at The functionality in there is much slimmer than the full server, I have running at It’s basically just an “ActivityPub Client”, for some meaning of the word.

Now the warning, once I finish writing up the example, everybody with access to pip and a domain will be able to copy and paste together something they can use to send valid HTTP signed ActivityPub activities.

I personally consider this a good thing, as it will make it easier for people to get started. On the other hand, I don’t know if I should expect abuse.

On another note, I’m moving bovine to codeberg, so the new repo is helge/bovine: Modular ActivityPub/Fediverse Server - bovine -


If you’d like that, then a dedicated sub-category for Bovine can be created in the #software category.

My vision is that this is just python code and not a dedicated server. I’ve also updated to version 0.0.9 as I found some not so nice things when working out the fake server example.

The result is available at

If I wanted to make everything easier to understand, I should probably even create a synchronous version, which has become the first issue on codeberg.

1 Like

Is it a Server or a Client, according to how ActivityPub spec uses these terms? If it hosts inbox and outbox, I think it’s a Server.

I think it depends on what you are talking about. The library bovine on pypi will contain three things (after I do some refactoring to make stuff clearer):

  1. BovineActor: An implementation of the network interface used by an ActivityPub Server to make the “actor network calls”:
    • POST /inbox of other actors
    • GET object_id (when proxying elements for client)
  2. BovineClient: An implementation that allows one to communicate with the ActivityPub Server as an ActivityPub Client. Operations include:
    • POST /outbox results in ActivityPub Actor performing POST /inbox to the recipients
    • POST /proxyUrl results in ActivityPub Actor performing GET object_id
    • GET /inbox results in retrieving what other Actors have send to it
    • GET /outbox results in retrieving what other Clients of the same Actor have send to it
    • furthermore, it encapsulates creating ActivityStream objects through factories …
  3. Various helper stuff for handling signatures of HTTP requests or OrderedCollections …

I’ll try to have a clear picture of what 3 should be before going for bovine 0.1.0 on pypi. The important part is that I think 1 and 2 offer two classes that should encapsulate a lot of behavior in a way, one can then forget about it.

There are some “white lies” above, because there is for example a caching layer between proxyUrl and GET.

Can BovineActor receive activities from other actors, or it relies on some other service that hosts the inbox?

BovineActor as described above, is unable to receive messages. It doesn’t expose a server endpoint. It is meant to perform calls.

The other half to get to an ActivityPub server is contained in bovine_fedi, but that code works but isn’t really good. There is too much small stuff that was build in a particular way just to work.

The point of separating out the ActivityPub client code is that I can now build things like longhorn, what is behind with bovine as a proper dependency. You do not want to pull the entire server as a dependency, just the code you actually need.

1 Like

I’ve now created a documentation for the package bovine at bovine: Base ActivityPub Classes — bovine 0.0.10 documentation

Also I’ve done the split into BovineClient and BovineActor for it. There is still a lot of work to do, like documenting the Activity-, ObjectFactory classes, and explain how to verify signatures.

However, I am quite confident that one can now use the package to start doing some stuff in python, if one is so inclined. The main advantage is that, I believe the interfaces for BovineClient and BovineActor should be stable.

I’ve tried to create a diagram of how I see the architecture of these things progress. It’s not great yet.

I also coined the term ActivityPub Bot for basically what it says. It’s a bot that sits on your ActivityClient and does some automated tasks such as accepting follow requests.

Example code for an ActivityPub Bot: mechanical_bull.

Untitled Diagram.drawio