Daily Rucks: The How and Why

January 28th, 2024

As of this writing, I have just publicly launched my Daily Rucks ActivityPub bot based on Python/Flask. As usual, there is a project page on my website with a brief description and statement of purpose, but since this project is part of a longer journey, I figure it’s a good opportunity to talk a bit more about where this is coming from and where I’m intending for it to go in the future.

What It Does

Daily Rucks is a self-contained ActivityPub bot – a (more or less) full-fledged, interoperable ActivityPub server hosting a single account. The account in question is a bot that posts a voice line by the character Rucks from the game Bastion (2011) once per day. It’s followable from just about any ActivityPub platform that can read Note objects, and preferably also handle MP3 attachments.

A very short aside on Bastion: I first played the game after it was included in the Humble Indie Bundle 5. Back then, it kinda reinvigorated my passion for PC gaming after a few years of dormancy. While I believe it to be a great game that has no problem standing on its own, it also carries a special nostalgic torch for me. Rucks, who functions as the game’s narrator, is voiced by Lo­gan Cun­ning­ham. The combination of Rucks’s varied commentary and Cun­ning­ham’s charming grizzled voice proved to be a major part of the game’s appeal and a fitting aspect to single out for a retrospective. This project was further inspired by JP LeBreton’s social media bots, which post assets or scenes from beloved games for a regular dose of memories.

Daily Rucks’s ActivityPub implementation is an evolution of what I started in Pinhole, an all-custom and somewhat incomplete implementation of the suite of protocols needed to set up a fediverse node. Where Pinhole is capable of nothing except sending messages to one single Mastodon follower (I never debugged its interoperability with other server implementations), Daily Rucks can be followed from a variety of ActivityPub platforms and can handle incoming likes and boosts as well as follows and blocks. As visitors to the Daily Rucks website can see, likes and boosts are counted for each post and aggregated into overall statistics.

Incoming replies are still dropped, though. Because no remote content is ever shown (neither incoming replies nor even user names of interacting AP actors), this hopefully obviates the need for content moderation.

So now Daily Rucks is sitting there and will hopefully keep doing its thing mostly unattended. I put more effort into the audio files and the website than I had planned at the start of the project (and maybe more than was warranted), but I’m hoping now it’ll pick up a few fellow Supergiant Games fans as followers.

How We Got Here

I don’t want to rehash all of my thoughts on social media in general and the fediverse in particular, but if this is your first time here, let me just say that I’m disillusioned by corporate platforms and intrigued by federated, self-hostable social media. I set up my personal Mastodon instance in late 2022 and got increasingly motivated to get involved with the landscape as a hobbyist programmer. In 2023, I set up Mastodon news feed bots for my academic publications and for this blog, and implemented interaction with my static site generator for Mastodon-based blog comments.

But putting something together in pure ActivityPub, without using an existing server, is more challenging. Last fall, Jennifer++ (who’s looking for collaborators on Letterbook) posted this visual summary of what it’s like to tackle an ActivityPub implementation, and you can feel the exasperation in it.

When I saw it, I had just published Pinhole, and my first instinct was to bristle against her conclusion. After all, Pinhole had ostensibly been what she was describing, a “from zero to federation” project based on nothing but Python 3, Flask, and the requests package, and it was a literal weekend project – I had started with a blank text editor on Friday afternoon and finished the last bits of documentation by Sunday. Pinhole’s federated core consists of about 200 lines of Python implementing whatever thin slices of ActivityPub, WebFinger, and HTTP signatures were needed to get the thing to successfully send posts to Mastodon. It hardcodes almost everything, ignores JSON-LD completely, isn’t capable of receiving any Activity types except “Follow” and “Undo”, and doesn’t even have an outbox. But it does federate.

I checked myself rather than reply to her on the spot and thought some more about the perspective she was coming from. I was implementing a single broadcast-only bot, she was (and is) implementing an actual social platform where users will be able to create accounts and interact. She was thinking about standards compliance and measures to ensure the long-term health of the ecosystem, while I was dipping my foot in the water to get a feel for the protocol. I still hope her summary isn’t unduly discouraging to new implementers like me who just want to experiment, but it is an honest reflection of reality.

I still had more plans for my ActivityPub work though, so I took the AP core from Pinhole and set off to the next thing. With a growing awareness of what I was getting myself into, I decided to create a low-stakes testbed for my AP implementation – something that, if it failed, it wouldn’t risk losing people’s data or connections. That’s how the concept for Daily Rucks was born. I decided to simultaneously expand the capabilities of my ActivityPub implementation to do more than just send posts to a single follower, to prepare some fun content for a bot to post based around a video game I enjoyed, and to ramp up my interoperability efforts with other implementations. For the latter, my thanks and a major shoutout go to Daily Rucks’s main tester Jeff Sikes, who helped keep me accountable and checked whether the bot could play nice with notable ActivityPub server software after each major change.

And now Daily Rucks is done. I’m watching and hoping it will survive its first contact with the wider world, and secretly crossing my fingers that some people will feel inclined to follow the account and spread the word. I will monitor it and make adjustments to the code as necessary and as I learn of problems, and in parallel I will set my eyes on the next goal.

What Happens Next

As noted above, my passion for the game Bastion wasn’t the only motivation for creating this project. The goal for me was always to improve my understanding and implementation of ActivityPub in order to do more things with it in the future.

Most pressingly, FediRoster is basically crying out for proper ActivityPub integration. I know of two public sites powered by FediRoster, my own HCI Directory and Randy Resnick’s Fediverse Fans. I still strongly believe in the potential of public opt-in topic lists for account discovery, and that Hendrik Erz’s Academics on Mastodon has been a notable factor in helping the scientific community find their circles on the fediverse a bit better than some other communities have managed to. FediRoster currently relies on a Mastodon bot to send out updates about list additions, but I would love to turn the whole thing into a first-class ActivityPub participant. Adding yourself to a list could be as easy as following a “@join” account, and we could have a group-esque account for each FediRoster instance that boosts everything posted by list members, so you could conveniently follow everyone. This won’t be finished in time to demo it at the next FediForum, but the plan is fairly solid.

My other idea for ActivityPub integration is this very website. The comments on this blog post are currently loaded from my Mastodon server through its own API, but I would ultimately like to decouple the two and outfit this website with its own set of ActivityPub inboxes to provide followable feed accounts (to replace the two bots I linked earlier) and comment sections for individual pages.

You can probably tell from these two future use cases that they are less fault-tolerant than Daily Rucks. Before I set them loose upon the world, I want my ActivityPub implementation to be solidly capable of interoperating with most people’s accounts and properly handle their data for storage and presentation. Daily Rucks is straining badly against the single-file approach I kept when I migrated it from Pinhole, and for the ActivityPub implementation to grow further, I will want to refactor it into a shape with more high-level structure. I might even see if it isn’t possible to turn it into a general-use ActivityPub library after all.

There is still a lot of work to do, and I am planning to do it.

As one last point, you might ask yourself why I’m walking this all-custom path even though it would be easier and faster to reuse an existing implementation. The Social Inbox by distributed.press is a very cool project that does much of what I need for my website, and takahē would be a more mature existing Python implementation if the goal was to integrate it better with my existing publishing stack. To that, the only thing I want to say is that I’m the kinda weirdo who does this stuff for fun, and building my own ActivityPub implementation is my way of learning the standard and the ecosystem. At the end of the day I’m still a hobbyist programmer, and I want to spend my free time (outside of my full-time university employment and, as of this upcoming spring, a very cool teaching side gig on top of it) in a way that I find fulfilling.

So that’s the journey ahead for me. We’ll see how it goes!


You can leave a comment by replying to this Mastodon post from your own account on Mastodon, Firefish, Akkoma, or any other ActivityPub-capable social network that can exchange replies with Mastodon.