Tutorial: Moo Cow

in this tutorial, we will build a simple bot that replies with a random length mooo when mentioned. We will be going through all the steps for it.

Creating an account

In order to use mechanical_bull, we need an account on a server supporting the Moo Client Registration Flow. This can be accomplished through using bovine as a server.

To build this tutorial, I registered the account moocow@mymath.rocks and then ran

$ python -m mechanical_bull.add_user --accept moocow mymath.rocks

Please add did:key:z6MkekwC6R9bj9ErToB7AiZJfyCSDhaZe1UxhDbCqJrhqpS5 to the access list of your ActivityPub actor

We furthermore should update the actor profile to include a name, a summary, and a profile picture.

The handler

We create a file moocow_handler.py and add the following to it:

import bovine
import random

async def handle(client: bovine.BovineClient, data: dict, min_o=4, max_o=20):
   if data.get("type") != "Create":

   obj = data.get("object")
   if not isinstance(obj, dict):

   tags = obj.get("tag")
   if not isinstance(tags, list):
      if isinstance(tags, dict):
         tags = [tags]

This so far ensures that the activitiy, we receive is a new post and that it contains tags. Tags are what is used to encode mentions. We will now iterate over the tags and see if our actor is mentioned.

actor_id = client.information["id"]
def mentions_me(entry):
   return entry["type"] == "Mention" and entry["href"] == actor_id

if not any(mentions_me(x) for x in tags):

So we are now in the position of wanting to reply, for this we build a note and send it via

mention = await client.object_factory.mention_for_actor_uri(obj["attributedTo"])

note = client.object_factory.note(
   content="m" + "o" * random.randint(min_o, max_o),

await client.send_to_outbox(client.activity_factory.create(note).build())

This means we are done. By putting this file into the directory the config.toml file is inand editing it to say:

private_key = "z3u2Yxcowsarethebestcowsarethebestcowsarethebest"
host = "mymath.rocks"

"mechanical_bull.actions.accept_follow_request" = false
"moocow_handle" = { min_o = 5, max_o = 25 }

we are done. After restarting the mechanical bull process, we should be able to contact the new bot.