5 min read

The (Absolute) State of The ATmosphere: 1. The Good

The (Absolute) State of The ATmosphere: 1. The Good
Anything that has me make this many repositories in three weeks (most of which I worked on for multiple days) is doing something right.

I finally wrote up what I did over the last few weeks, so I figured I'd zoom out a bit and try and cover what I learned in the process and the ups and downs of working with atproto at the tail end of the year of our lord 2025. Where possible, I'll do my best to link to all the bookmarks I've made of tools or explainers by smarter people than me.

I'm going to make this a three-parter focusing on what's good, what's bad, and what needs work. The importance of giving a compliment sandwich during feedback is still drilled into me from my teaching days, so I think I'll wrap up on day 30 with some general reflections and my overall excitement about this ecosystem.

I'd like to preface all of this by saying I am enormously grateful to all the open-source devs working with atproto right now, from Bluesky employees to random nerds like me working on stuff in their spare time. It is no understatement that this project has renewed my enthusiasm for open source: the spirit of "you can just do things" is everywhere and it's energizing as all hell.

That said, especially for actual Bluesky employees, the majority of their audience is made up of two of the least pleasant types of online person: obnoxious open-source people and prolific social media posters. Generally I think we'd all be better off if we paused and tried to communicate with people online as if they were standing in front of us, or at the very least tried not to assume the worst about everyone, but that ship has sailed. So I'll just try my best to stand against that current by saying that any criticisms I write in the next few days comes from a place of hoping (and generally believing) that the jagged edges of the ecosystem will improve with time.

It is also highly possible that I have missed some tool that solves my problems or am wrong about how some things work. Feel free to ping me on Bluesky (@bront.rodeo) if you have corrections, suggestions, or interesting stuff that I should add here.

Okay, that's out of the way. Let's get into what rocks about atproto right now:

The Model In General

I wrote up the differences between ATProto and ActivityPub at the beginning of the year, but the ecosystem has changed a good bit since then. Other people have written it up better than I can since then, but I am pretty sold on ATProto's overall approach to decentralization.

Anecdotally, while some of this is due to the fact that, well, they have actual funding, I think the way they split up their stack and the way dataflow is designed just makes it significantly friendlier to build on than any ActivityPub implementation I've seen. Not having to deal with the utter lack of a source of truth and potential for losing reach because of internecine mod warfare is pretty nice too - although I do wonder if, as we see more external PDS hosts and standalone applications take off, we may get some of the fragmentation inherent to networks like Mastodon. Some of the lack of confusion is just because there isn't a meaningful alternative to Bluesky right now.

Lexicons/API Design

I didn't dive suuuuper deep into this but what I did was very easy. Basically your application uses a set folder structure to declare different datatypes, and that structure also defines how an API request might be made. By means of example, from my cat tracking app, in lexicons/com/ffion I have defined playing.json:

{
  "lexicon": 1,
  "id": "com.ffion.playing",
  "defs": {
    "main": {
      "type": "token",
      "description": "Ffion is playing."
    }
  }
}

I define a record type, status, in lexicons/com/ffion/status.json, and now I can use the universal atproto API to get a collection of these records. In JS, for example:

    const response = await agent.com.atproto.repo.listRecords({
      repo: hardcodedDid,
      collection: 'com.ffion.status',
      limit: 100
    })

This is pretty straightforward and just works as far as I can tell, although maybe I would feel differently if I were building more than a toy application.

The base API design (see the Bluesky HTTP reference) is also just pretty nice. I haven't even had to bother defining a custom endpoint or anything yet because everything I need is in there. It's not sexy, but a shared standard for how apps serve social content is really powerful, and saves so much time spent on design thinking.

Resolve Lexicon - I just found this useful for getting a better sense of what different lexicons (lexica?) do than you get from the base documentation.

Typelex - compile lexicons from Typescript. Probably not for me since I resent being forced to use Typescript in the first place.

The PDS

This is the first-class citizen of the atproto ecosystem and I am in love with it. Setting up a PDS was the first thing I did, and (assuming you have a bit of experience with running your own server and DNS) is frighteningly easy. This is the part of the ecosystem that I am still kind of blown away by. You, or a trusted third party, can just host all of your data and route it to client applications. You own your data. This is where the promise of both credible exit and a universal, open-source API start to feel real.

The default PDS setup documentation is great and covers (I think) any small-instance needs without forcing you to get into the weed. I've been perfectly happy just using the simple pdsadmin bash script wrapper but I know that the atproto team have been hard at work on adding more features to goat, like account migration.

The only reason I haven't migrated my own account over to my personal PDS is that I'm using it for testing stuff and am likely to break things, but if you just want to feel like you own your own data, now is as good a time as any to set one up. It's easy!

PDSls - explore PDSes, great way to get a sense of how they work (and debug your own).

PDSfs - mount a PDS as a local filesystem for exploring.

Notes on migrating a bluesky account

Developing On Top Of This

It's so easy! If you choose to use a third-party PDS, you no longer have to worry about storing your data and can basically just write any app as a wrapper for an external API, while maintaining the ability to move it to self-hosting anytime you like. If you get sick of Bluesky you can write your own. OAuth is built in. How applications interoperate is clear and easy to work with. And AI-assisted code tools do shockingly well with everything atproto-related for how young the ecosystem is. Especially with spinning up my cat social network and bots, I was able to have all the basic CRUD features I wanted working in a matter of minutes.

While I'm personally frustrated by the lack of an official Python SDK, I can suck it up enough to admit that what's out there is pretty great (and I'd be shocked if more Python tools aren't coming).

ATProto Quickstart

Bot starter template

ATCute - set of npm tools for building on ATProto

Jacquard - tools for Rust