Building a PDS the Hard Way

Agent IO March 18, 2026
Source
A deep dive into ATProto Did I say that I was nerd-sniped by the AT Protocol ? Maybe not loudly, but my close friends knew that I'd thrown myself into a new side project and may have wondered about the wisdom of that (frequently I've had side projects of side projects of side...). "How hard could it be," I wondered, and at the beginning of February I decided that it wouldn't be that hard and that I could probably have something working before I left for Vancouver for ATmosphereConf . But it was challenging. It helped a lot to have an instance of the Bluesky PDS running behind IO so that I could observe its traffic, and it also helped to have already built the client side of ATProto OAuth into IO , and to have just built slink , which gave me a way to interact with XRPC in Go on my own terms. However, I didn't vibe code it and kept with my characteristic distaste for dependencies , so I wound up writing some key parts (like CID, CBOR, CAR, MST operations and OAuth) by hand and from scratch. One other thing that helped a lot was to start with the Bluesky PDS data structures. As Fred Brooks wrote: Show me your flowcharts and conceal your tables, and I shall continue to be mystified. Show me your tables, and I won’t usually need your flowcharts; they’ll be obvious. Smile, a PDS I haven't decided what I want to do with this other than use it myself for a while. Like IO, it has a TUI and an SSH control interface. Just looking at the start screen raises lots of ideas of things that could be added to it. I call the PDS smile because originally I thought I was building something very personal for a single user who, for whatever reason, might want to run multiple repos. I thought of it as a hobbit-hole, which Tolkien called a smial (💡!), but I didn't want to forever be correcting the spelling for people who heard the name, and smile isn't a bad thing to present to the world. Currently I have one instance of smile that I run on my laptop and publish to the world using a Digital Ocean droplet, IO , and an SSH reverse tunnel. Did you know about these? All I do is run this on my laptop: where cloudhost is the name of my droplet in my Tailnet. Then when I run smile locally, it listens to port 8080, which the tunnel makes available on port 8080 of my droplet, which IO publishes using an ingress . (That port is firewalled in case anyone is tempted to hit it directly.) Commit History Here is the commit history for what I've done so far.

Discussion in the ATmosphere

Loading comments...