In Search of Podcasts
· 14 min read
This post is based on my talk at AtmosphereConf 2026 in Vancouver. You can find the video of that talk here. Last summer, I wrote about podcasts. It was a loose reflection on how to best communicate the decentralization of a medium, and how to allow people to understand decentralization. To me, the phrase "wherever you get your podcasts" represented the ultimate success of that understanding: ...the reason podcasts are so interesting to me in this way is that the critical mass who refer to podcasts in a way that communicates they understand its decentralized nature have never consciously acknowledged or even realized that it is in its nature and design, decentralized. Because the reality is that the language, "wherever you get your podcasts" doesn't actually communicate that podcasts are decentralized. It simply communicates a benefit of that decentralization. But I left the question of how to apply this to AT Protocol open. I think we, as the AT Protocol community, spend a lot of time thinking about how to communicate how AT Protocol works to users who are non-technical. This boils down, in large part, to the language we choose to use when giving this explanation. I think podcasts show us the best way to communicate to users the decentralization of a network is indirectly and often through direct interaction on the network. There are a lot of other lessons you can learn from podcasts about decentralized networks, especially about monetization, but I was just fascinated at the language used to refer to podcasts once I thought more deeply about it. A network is, in large part, people's perceptions about what it is, and the best kind of network, especially a decentralized one, is one where people know how to use it to its full potential without having to know how it works. Since writing that post, there has been a lot of conversation about what language should be used to communicate AT Protocol to the world. But I've been thinking beyond language, in search of real implementation to make atproto as cohesive as podcasts are. The short version is: it's harder than it sounds. The longer version is Podcasts work as a metaphor because podcasts are, at their core, one kind of thing. A podcast is an RSS feed. Different apps can index those feeds, build their own directories, pull from public registries, and present the same underlying media in different ways. That does not mean podcast apps are identical. Apple Podcasts, Spotify, the late Google Podcasts, and smaller podcast apps can all have different interfaces, discovery systems, and business models. But the thing being shared between them is one object: a podcast feed, denoted by a simple header at the top of the feed: <rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"> AT Protocol is different. On atproto, everything is a record, and each record has its own type. Posts, likes, follows, blocks, lists, profiles, comments, videos, and anything you can think of has its own defined schema, denoted by a $type. These schemas are called lexicons and any app can define its own. They are represented in reverse DNS notation, like app.bsky.feed.post or so.sprk.feed.post. But that flexibility creates a problem for interoperability. With podcasts, the question is mostly: Can this app read podcast feeds? In the Atmosphere, the question becomes: Which lexicons should this app understand, how deeply should it understand them, and what social expectations come with that? These lexicons can generally be broken into two types: graph and content, where graph is a record about another user and content is an independent record that is prominent in an app. For our purposes, we'll split graph into two categories for a total of three types: follows, content and blocks. You'll see why they're ordered that way in a minute. Much of the discourse among AT Protocol developers about interoperability boils down to followers. It's not a mystery why. The closest analog to "listen wherever you get your podcasts" in the social sphere would seem to be "follow me wherever you get your social media." This was my initial instinct. There are so many follow lexicons around the atmosphere. Bluesky has follows. Spark has follows. Tangled, Grain, Semble, the list goes on. Almost all of the follow schemas are the exact same shape; a record with a subject field. So, why not standardize follows? Well, we run into a few problems. Notably, many users don't actually want one universal social graph across every app. You might watch a gamer's Twitch streams without being interested in their political takes on Twitter. When Instagram launched Threads, it didn't sync follows from Instagram to Threads automatically, rather allowing users to import follows when they set up their Threads account, but fully separating follows afterwards. Many users—in my opinion, most users—want each platform they use to feel like a different space, and that means following different people across each one. But there are also users who do want one persistent graph. For them, one of the promises of atproto is that their relationships should not be trapped inside a single app. So why don't we just let the user choose? Imagine Spark supports both Spark follows and Bluesky follows. A user can decide which graph they want Spark to use. Maybe they want a Spark-specific graph. Maybe they want to reuse their Bluesky graph. We store that as a preference record, it points to which graph they want to use. At first, this sounds pretty reasonable. If we want to know how many people a user is following, we check their preference, then count the relevant follow records. But if we want to know how many people follow them, it becomes much harder. For every incoming follow, we now need to know whether the person who created that follow intended it to count in Spark. So every time we query or recalculate the follower count of a user, we have to check the preference record of every single follower. Beyond this complexity, the bigger problem with this is that you have to index follows from everyone, including those who don't use your app. Because if they join, or if someone they follow joins, it's the only way to make sure the counts are accurate. This means you end up scaling for users you don't have. Follows are the second most common record type on the protocol. If your app decides to consume every follow from a much larger app, you are now ingesting and storing a huge amount of data just to display counts that don't meaningfully improve your user experience. That was one of the biggest lessons for us at Spark. All this complexity doesn't meaningfully enhance the user experience. It simply inflates a number on your profile. It's interoperability for interoperability's sake. But if we don't have this, what is AT Protocol for? ATproto developers cling to the idea of a persistent social graph as a clear and simple way to pitch the protocol. And it's not a mystery why. It can apply to both PDS migrations and switching between apps. But if we don't interoperate follows across all apps, that second part goes away. A persistent social graph is a nice pitch, but universal follows just aren't compelling enough for smaller apps to make it worth the complexity and expense. But don't worry, there's a much more compelling option to interoperate with that involves much less complexity than follows. Content is the thing people actually open the app to see. For Spark, that means videos. For Bluesky, it means posts. For Tangled, it means repos. For Leaflet, it's documents and comments. For others, it's reviews, events, streams, and many more. This is where atproto starts to become exciting in a way that is more specific to the protocol. Apps can show records created anywhere in the Atmosphere. Some apps already do this. Leaflet supplements its own comments with Bluesky posts that link to the Leaflet document. Spark does the same with Bluesky replies to a cross-posted video. Beyond this, Spark could consume Bluesky posts with video embeds and display them as videos. Leaflet could consume long threads from Bluesky and display them as unified documents. Apps can build new experiences out of records that were created for entirely different contexts. That is much closer to the podcast model in terms of user benefit. If Spark ingests a Bluesky post with a video, all Spark users can view that video and the amount of content available in the app is increased. This makes Spark better for every Spark user, no matter if the creator of the video uses Spark or not. That is very different from ingesting millions of follow records mostly to make a number next to a username slightly more interoperable. Each post we ingest, no matter who made it, makes the app better for every single one of our users, so scaling benefits all users. Unfortunately, if you do it, you will burn in hell forever. Because now we need to come back to This is the really annoying part. If Spark consumes a Bluesky post with a video, what should happen when that post was created by someone the viewer blocked on Bluesky? We could just say: Spark is a different app, so maybe Spark doesn't need to care about Bluesky blocks. But that breaks a clear user contract. If a user blocks someone on Bluesky, they may understand that this does not magically block the person everywhere in the entire Atmosphere. But if Spark is showing them Bluesky content, I think there is a strong social expectation that Spark should respect the blocks attached to that Bluesky context. That means, if Spark wants to consume one app.bsky.feed.post record, to be a good citizen of the Atmosphere, it also has to understand app.bsky.graph.block records. And not just blocks. It also needs to understand list blocks, lists, and list items. Integrating this whole intertwined system would upend the way Spark works to fit Bluesky's philosophy around blocks. This is a lot to ask to consume a single post. And it means that every time an app wants to interoperate with another app’s content, it also needs to interoperate with that app’s safety and visibility systems. That becomes a horrific clusterfuck of a ton of systems, each with their own quirks, all tangled together into one app that has to respect all of them. If the Atmosphere is going to be a place where apps remix each other’s content, then every app should not need to separately understand every other app’s block system. This is why I no longer think follows are the most urgent graph standard. I think blocks are. A universal follow lexicon is nice. It might be useful. Some users want it, and some apps could benefit from it. But a universal block lexicon is something the Atmosphere actually needs. If we want to be able to put content from any Atmosphere app into ours freely, building with lexicons like LEGO bricks, we need a simple block standard that lets us do so without having to implement tons and tons of block systems. And unfortunately, the most widely adopted block system is just too complex and cumbersome to encourage its wide adoption. A standard block system should be the lowest common denominator, the simplest model that can be adopted in the most apps. That means a single record with a subject field. Nothing more and nothing less. At Spark, we approached this backwards. We started by ingesting Bluesky follows. Then blocks. Then feed generators. Eventually, we planned to get to posts. I now think the order should have been the exact opposite. If you are building an atproto app and you want to interoperate with other apps, start with the thing that will make your app meaningfully better for your users. Most of the time, that means content. It's harder now than I hope it will be in the future, but I hope shared standards like blocks will make it easier to be confident in this as a path in the future. For Spark, we worked on these problems for months. We ruminated about it, worked on it, yelled at each other about it, and came away from it dazed and confused. We scrapped almost all of it. Our original work on this interoperability problem led to no concrete features. It was only after we scrapped this effort that I finally started to see the vague outline of what I now believe to be the "right way" to do this interoperability. And to be quite honest, it was only while working on this talk that I found the endpoints to those strands I was pulling on. Unfortunately, none of this is actionable yet, until we have a concrete blocks system in the ecosystem. But I hope this can provide a good roadmap for how to think of these problems, for those facing them. If you only remember one thing from this post, let it be this: Interoperability is not a virtue by itself. Interoperability is only valuable when it creates a better user experience. The point of my original post was not ever really about RSS. It was about language. “Wherever you get your podcasts” works because it describes a benefit of decentralization without requiring the user to understand decentralization. That is still the goal for atproto. But I think I understand the challenge better now. For podcasts, the benefit is simple because the object is simple. A podcast can move through many apps because podcast apps mostly agree on what a podcast is. For atproto, the objects are more varied. The relationships between them are more complicated. The safety expectations are higher. The protocol gives us much more power, but that means the path to “wherever you get your social media” is a much longer road with a lot more roadblocks in the way. The answer is not to make every app implement every lexicon. The answer is to figure out which shared standards unlock real user-facing benefits. I don't know what all of them are yet, but I do know content is one of them. I still believe in the version of the Atmosphere where apps can build on each other. I want an app ecosystem where a video app can understand video posts from a text app, where a publishing app can use comments from a microblogging app, where a community app can pull together records from across the protocol into something that feels new. To me, that infinite remixability is the true killer feature of the atmosphere. A rich ecosystem of apps that remix each other's content, using it in contexts the original creator would never have thought to, or would never be able to. Each person's social presence on different apps worming its way into other apps in unique and creative ways. That is what will make the atmosphere so special to developers and users. And we need to remember that users do not care whether we implemented the most elegant version of lexicon interop. They care whether the app works, whether it respects their expectations, and whether it gives them something they could not get before. That is what podcasts got right. Nobody says, “Subscribe to my independently hosted RSS feed using any compatible client that indexes open podcast registries.” They say: "Wherever you get your podcasts." The Atmosphere's version of that won't be a single phrase, and it won't be a single feature. It will be a set of experiences where users feel the benefits of decentralization without needing to think about the protocol. That is the real challenge for the Atmosphere, not simply to be open, but to make openness feel inevitable.