~3 Weeks of ATproto (cross-post)

I went to the Brooklyn atproto meetup on Wednesday and met a lot of cool and interesting folks doing cool and interesting work. Shoutout to the leaflet team for organizing and inspiring me to start crossposting my atproto work over here. This also reminded me that I should probably do a writeup of what I've been up to.

After initially blogging every day's worth of work on my 30 days of protocols (which really has just turned out to be 30 days of atproto) I realized that the rules I set out for myself did not actually require me to make a blog post every day, and that I wasn't getting as much time actually writing code as I wanted because I also had to write up everything I was doing. So I've been heads down exploring for about three weeks. Here's what I've done so far, with a few takeaways for each:

A Social Media Network For My Cat

This really drove home how simple making an app that ties into the broader ATProto ecosystem can be. I defined a lexicon for different potential cat statuses, made a simple HTML frontend, and saved an OAuth cookie from my PDS, then set up a server to listen for any time my camera detected Ffion. Admittedly Claude did a lot of the busywork but still - the ATProto section of this wasn't hard.

Most of the actual difficulty (and why this isn't live) was the computer vision bit. This is another ecosystem that's way easier to set up than the last time I was seriously into it - I got a python camera listener using YOLO to post to my server anytime it saw the cat. The coolest part to me was using moondream to describe the images and (right now) a heuristic of synonyms to determine which of the default states (eating, playing, sleeping, and zoomies) it corresponds to. It's easy to envision adding another LLM to parse the description and decide which status is closest to it. My mixed feelings on LLMs are well-documented, but this is one of the more obvious clear positive use cases: automating image descriptions and sifting fuzzy data into categories is something LLMs do really well.

Unfortunately, I realized there are many edge cases that I maybe don't want to be posted to a database that's public by default. This realization came pretty quickly when the camera caught my wife and the cat together while she was doing her makeup - luckily she was not nude, but the possibility was there! I added some filtering in both the image description and detection to avoid this happening, but since anyone can hypothetically see anything that gets posted to my PDS, I'm not really confident enough to keep this running live yet.

Generally, this both helped the power of the PDS click for me and was the beginnings of some of the frustrations I have with the ecosystem as it stands. It's just a universal self-hosted database that can talk to any compatible app. That's amazing! It is crazy that on my own server I'm hosting something that lets me own all my records for Bluesky and any other app, including my goofy cat app.

On the other hand, the fact that all this work is public by default is frustrating. Maybe there's a mock PDS system out there, but I haven't seen one yet, and especially when you're first testing out a project, it'd be nice not to post my tests, accidents, and potentially insecure information to something that is broadcasting to the entire network.

Some Bots

This is where both the power of the ecosystem and the available dev tools and ease of use seemed to align perfectly. My first bot, markov-generated Max Stirner haikus, literally took me 20 minutes to make. I found an existing markov haiku generator, downloaded The Ego And Its Own from Project Gutenberg, and modified Bluesky's bot starter template slightly. All I had to do was create a unique account for it on my PDS and I can run it in the background indefinitely.

The second bot, which posts entries from 17th-century Encyclopaedia Britannica editions, took a bit longer to set up, but that was mostly doing my best to parse OCR-ed text files from old books. It's still a bit buggy but I think it's fun and good enough for now.

I am a big fan of bots. I really miss the peak days of Twitter bots: @everyword, @horse_js, the one that posts every time the New York Times publishes a new word, and so on. A lot of the creative tech folks and botmakers I'm aware of migrated to Mastodon and are still hanging out on cozy servers there, but I'd love to see more tech-art folks playing with the affordances of ATProto. This was the easiest time I've ever had setting up a bot: no developer account, no API key, just a simple script with a username and password. If you're a fan of the form, there's no better place to be than Bluesky right now.

A Haiku Feed

This is down right now because it can't resolve my server's did:web which is emblematic of the issues I've had with making feeds (and the general issues I've had trying to use did:web for just about anything). I tried using the Python community feed generator, but was unable to publish, I think because the Python client SDK doesn't work well with custom handles or non-Bluesky PDSes. So I changed to the official Bluesky Typescript one, and still ran into a number of weird issues.

The documentation is a bit old and its behavior is weird:

For whatever reason, despite did:web being a second-class citizen across the ATmosphere, publishFeed makes you create and host a did:web specifically for the URL hosting your feed. Why is this? And why are we made to use something that tends to break almost everywhere else?

I wanted to serve my feed from a subpath (atproto.bront.rodeo/haikus) but even running my server at that path and redefining my .well-known/did.json to use it as an endpoint didn't solve it, so I'm running it from the didweb subdomain.

Again, the lack of devtools is frustrating here: the only way to test what my feed actually looks like is publishing it live. It would be really nice to have some local wrapper to display the feed before you publish. Backfilling a feed is also not super well-documented - obviously people have figured out how to do it, but it seems like something that should be a default option and not monkeypatched by users.

In Conclusion, The ATmosphere Is A Land Of Contrasts

I'm thinking of following this up with a more thorough writeup of the different parts of the ecosystem I've touched and the good and bad things about them, in which case I'll get deeper into this, but what I've discovered so far is really promising. You really can "just build things" in this ecosystem, and once the PDS really clicks for you, it's hard not to get excited at the prospects of open social. When it's this easy to host the first-class citizen and source of truth, whole new ways of thinking about the social web open up.

That said, this ecosystem is young, and (I think understandably) it looks like most of the engineering and documentation work has been done more around the protocol itself than how your average dumb full-stack dev like me could use it. This is improving rapidly, and Bluesky just hired a DevRel Engineer, so I'm really excited to see what comes next, but right now there are rough edges that might be easy for cryptography and decentralization people to figure out but were not obvious to me. The next step for Bluesky is to be something even beginners can build on easily, and while it's getting there there's still a lot of low-hanging friction-reducing fruit to be picked.

All in all: I'm excited! There is a ton of promise here, and I think I'm still wrapping my head around what's possible with this model of how data is stored and shared. Onward and upward!

Cat Lexicon Server Prototype

I'm short on time again - had a wedding ceremony to attend last night and a reception to attend today - so today's another 5-minute throwaway. I set up a quick server prototype that I can run some basic curl commands to and from and that validates my lexicon schema.

Cat Lexicon Server Prototype

I'm short on time again - had a wedding ceremony to attend last night and a reception to attend today - so today's another 5-minute throwaway. I set up a quick server prototype that I can run some basic curl commands to and from and that validates my lexicon schema.

Published by:

Brent - lesser daemon

Writing about tech, culture, and attempting to be alive in the world.

lesser daemon © 2025

Ghost: The best open source blog & newsletter platform

Beautiful, modern publishing with email newsletters and paid subscriptions built-in. Used by Platformer, 404Media, Lever News, Tangle, The Browser, and thousands more.