AT Protocol
Twenty-four short videos on the AT Protocol (atproto): a federated protocol for large social applications where your account is a DID with a domain handle, your public data is a signed repository on a personal data server, every host feeds a verifiable firehose that relays merge and apps index, and feeds, labels, OAuth and migration sit on top. One idea each, about a minute.

The AT Protocol, atproto, is the protocol under Bluesky and a growing set of other apps. Its founding promise is that you can take your account and leave: your identity is a permanent DID with a domain name as its handle, all your public data lives in one signed repository on a host you can change, and every host feeds a shared stream that any app can index. These twenty-four videos teach the model one idea at a time, in order: identity, then the repository and its records, then how data moves through the firehose, relays and AppViews, then what sits on top: feeds, labels, OAuth and permissions, account migration, the new Spaces extension for non-public data, and where the protocol stands with the IETF. The series reads atproto.com as it stood on 22 October 2026. Each video is about a minute. Below each one is the script and a question to check yourself with.

Made with the Video Curriculum Guide; the unit cards, recorded sources and the independent review are in the AT Protocol Curriculum.

1. The AT Protocol: a social web you can leave

Atproto is a federated protocol for large social applications whose founding promise is that you can leave with your account; data lives on host servers, every host feeds one shared public stream, and it is not a blockchain.

The Authenticated Transfer Protocol, atproto, is a protocol for large social applications. Its founding promise: your account and its data are a bag you can carry to another server.

It is federated. Your data lives on a host server, not on your phone. It is not a blockchain, and does not use one.

But it is not a web of small islands either. Every host feeds one big shared stream, and apps build their views from it.

Everything in that stream is public. Posts, likes, follows: signed, and readable by any app.

This series takes it apart one idea at a time. Identity. Repositories. Sync. And the apps on top.

Check yourself. Where does your data live, and who can read the shared stream?

2. Your account is a DID; your handle is a domain

An account has a permanent DID and a human-readable domain handle; the handle resolves to the DID by a DNS TXT record or a well-known file, and the DID document must claim the handle back.

An account has two names. A DID, a decentralized identifier: a permanent id number. And a handle, a domain name: the name tag people read.

Handles can change. The DID never does. Apps use the DID. People use the handle.

A handle points at a DID in one of two ways. A DNS text record, or a small file on the domain's website.

And the DID points back at the handle. Both directions must agree, or anyone could claim a name for someone else's account.

Own a domain, and it can be your handle. The name is yours, not the app's.

Check yourself. Why must the link between handle and DID be confirmed in both directions?

3. The DID document: a key, a handle, and an address

Resolving a DID yields a document with the signing key, the handle claim and the PDS address; atproto allows did:web and did:plc.

Resolve a DID and you get a document. A page with three rows that matter.

A signing key. Every change to your data is signed with its secret half.

The handle you claim.

And the address of your host server, your personal data server. That is how anyone finds where your data lives today.

Two kinds of DID are allowed. did web, which is just a domain you control. And did plc, which is next.

Check yourself. Name the three things in a DID document that the protocol uses.

4. did:plc: an identity you can recover

A did:plc identity is a ledger of signed operations whose genesis hash is the DID; rotation keys above the signing key install a new one when it is lost; a central directory, not a blockchain, keeps the ledger; for three days a higher rotation key you kept yourself can undo a change. That is the recovery.

did plc is a DID method made for atproto. Your identity is a ledger of signed changes, and the DID is a hash of the first one.

Rotation keys are the master keys, above the everyday signing key. Lose or leak the signing key, and a rotation key signs a change that installs a new one.

The ledger is kept by a central directory. Not a blockchain: a server that checks and stores signed operations.

Keep one rotation key yourself, on paper. For three days after any change, a higher rotation key can undo it. That is the recovery.

Why not just use a domain? Because you might lose it. did plc needs no domain to keep your identity.

Check yourself. What can a rotation key you kept on paper do in the three days after a bad change?

5. A repository is a signed set of records

All of an account's public data is one repository: records in collections, a Merkle search tree reducing it to one root, every version signed with the DID's key, so anyone can verify and anyone can serve it.

All your public records live in one repository. A ledger box of records: posts, likes, follows, whatever an app defines.

Records are sorted into collections, one per record type. Each record has a key inside its collection.

Above the records sits a hash tree. One root hash stands for everything.

Every version of the repository is a commit: a seal on the root. Signed with the key in your DID document.

So anyone can check it, and anyone can serve it. The repository proves itself. The server holding it does not matter.

Check yourself. What does the seal on a commit cover?

6. Every record has an address

An AT URI is DID, collection and record key; collections are reversed-domain NSIDs; most keys are TIDs that sort by time; some collections hold one record keyed self; resolution goes through the DID to the host.

A record's address is an AT URI: a street address with three parts. The DID. Then the collection. Then the record key.

The collection is a name with a domain in it, reversed. app dot bsky dot feed dot post. The domain says who defined it.

Most record keys are TIDs: thirteen characters made from a timestamp. They sort by time.

Some collections hold one record, keyed self. Your profile is one.

Resolve the DID to find the host. Ask the host for the collection and key. The address works no matter which server holds the data.

Check yourself. Which part of an AT URI says who defined the record type?

7. Records are hashed, and links are hashes

Records are canonical DRISL-CBOR bytes hashed with SHA-256 into CIDs; references carry CIDs, so a link is a hash; a reply names its parent by URI and CID; the hashes chain to the root.

Inside, a record is CBOR: a compact binary form of JSON. A fixed, canonical encoding, so the same record always gives the same bytes.

Those bytes are hashed with SHA two fifty six. The hash, wrapped as a CID, is the record's fingerprint: its content identifier.

Inside the repository every link is a hash: the tree points at each record by its CID. Between records, a reference is an address, often with the CID beside it.

A reply names its parent twice. The address, to find it. The CID, to know it is unchanged.

Hashes of hashes, up to the root. Change one byte anywhere, and the root changes.

Check yourself. Why does a reply carry both the parent's URI and its CID?

8. A commit is a signed root with a clock

A commit names the DID, the tree root, a TID revision that only increases, and a signature; because the tree is a Merkle search tree, a change touches only one path, so a commit's diff is a few blocks; no other server can forge it, but your own host holds the key.

Each version of a repository is a commit: a sealed page. It names the account, the root of the tree, a revision, and a signature.

The revision is a TID. It only goes up. It is a logical clock: anyone can tell which commit is newer.

The tree is a Merkle search tree. Change one record, and only the path from it to the root changes.

So the difference between two commits is a few blocks. That is what travels when your repository changes.

And the commit is signed with the key in your DID document. No other server can forge a version of you. Your own host can: it holds the key. So you choose it, and you can leave it.

Check yourself. What does the rev field let a stranger decide without trusting anyone?

9. Lexicon: schemas with a domain in their name

Lexicon is the schema language for records, API calls and streams; each schema has an NSID whose reversed domain says who owns it; schemas are published as records; any app can read any other app's records.

What is a post? A like? A recipe? A Lexicon says. Lexicon is the dictionary: the schema language for records, API calls, and streams.

Every schema has a namespaced ID. Reverse the domain, add a name. Whoever controls the domain controls the schema.

A schema defines a record type, a query, a procedure, a subscription, or a bundle of permissions. Typed fields, references, blobs, unions.

Schemas are published as records, in a repository. A DNS record on the domain says which DID holds them.

So any app can read any other app's records, and know what they mean. The schema is public, named, and owned.

Check yourself. How does a developer prove they own a schema name?

10. XRPC: every API call is a Lexicon method over HTTP

API calls are HTTP at /xrpc/ plus the method's NSID; queries are GET and procedures are POST; the Lexicon types inputs and outputs; the atproto-proxy header asks the PDS to forward a call with a token it signs; one method name works on every server.

Atproto's API is HTTP with one convention. The path is slash xrpc slash the method's namespaced ID.

A query is a GET. Read only, cacheable. A procedure is a POST. It can change things.

The Lexicon describes the parameters, the body, and the response. So clients are typed, and inputs are checked.

You talk to your own host. A header can ask it to forward the call to another service. The host signs the forwarded request on your behalf.

One name, every server. That is what makes the network one network.

Check yourself. What does the PDS add when it forwards a proxied request?

11. The PDS is your home: it holds your repo and your keys

The personal data server stores the repository, the signing keys and usually a rotation key, answers the user's app, proxies to services, signs and publishes commits, and can be self-hosted under your own domain.

Your personal data server is your home in the cloud. It stores your repository and holds your signing keys. Usually a rotation key too, unless you keep your own.

It answers your app's requests, and forwards the ones meant for other services.

Every change you make, it signs and publishes as a commit.

You can run one yourself, on a small server, under your own domain. It joins the same network as everyone else.

A host is a home, not a walled garden. Thousands of hosts. One network.

Check yourself. Which two things does a PDS always store?

12. Blobs ride beside the repository

Media are blobs stored beside the repository: uploaded first into temporary storage, then referenced from a record by CID, type and size; unreferenced blobs are garbage collected; quotas are the host's, accepted types and sizes the schema's.

Images, video, audio: blobs. Parcels that live beside the repository, not inside it.

You upload a blob to your host first. It waits on a temporary shelf, not yet visible to anyone.

Then a record references it: the blob's CID, its type, and its size. Now the host keeps it, and serves it.

A blob nothing references is deleted after a while. Delete the last record that points at it, and the blob goes too.

Quotas are the host's call. Which types and sizes a record may carry is the schema's call, checked when the record is written.

Check yourself. When does a host start keeping an uploaded blob for good?

13. The firehose: every change, in order, signed

Each host publishes an event stream: commits with the changed blocks, identity and account events, each with a sequence number for resumption, as binary frames over a WebSocket.

Every host publishes a stream of events. Atproto calls it the firehose.

The main event is a commit: the signed root, and the blocks that changed. Enough to verify it against the version before.

Other events say your identity may have changed, or that an account was deactivated, or taken down.

Every event has a sequence number: a pipe of numbered cards. Disconnect, come back with your last number, the cursor, and you get what you missed.

It is a websocket carrying binary frames. Built for servers, not browsers. Lighter forms come later.

Check yourself. What does a consumer send when it reconnects?

14. A relay is a crawler that re-broadcasts

A relay subscribes to many hosts and merges their streams into one, verifying commits against the previous tree state; since sync v1.1 relays are non-archival; anyone can run one, full-network or partial; a relay is a funnel, not a gate.

Nobody wants to subscribe to thousands of hosts. A relay subscribes to all of them and merges the streams into one.

It checks each commit as it passes: the signature, and that the changed blocks fit the tree. Commits that fail are logged today, and will be dropped once strict checking is switched on.

Since sync version one point one, a relay keeps no archive. It verifies and forwards. That makes it cheap in storage. The cost is bandwidth.

Anyone can run one. Blacksky runs a full network relay. A relay can be full network, or cover just one community.

A relay is a funnel, not a gate. Your data is still yours, on your host, whatever the relay does.

Check yourself. What does a non-archival relay keep, and what does it not?

15. An AppView is a materialized view

An app indexes the stream into its own database, the AppView, computing counts, feeds and search; two apps can build two views; new apps index records that predate them; write to the PDS, read from the AppView.

An app does not query hosts one by one. It drinks from the stream and builds its own index. That index is the AppView: a cached query over the stream.

Like counts. Follower counts. Search. Timelines. All computed from public records, by the app, for the app.

Two apps can build two views of the same network. It is called a view because it is just one way of looking.

A new app can index records that existed before it did. The data was never locked to the first app that read it.

So the loop is: write to your host, it flows through the stream, the view indexes it, the app reads the view.

Check yourself. Why is it called a view?

16. Jetstream and Tap: lighter ways to drink

Jetstream turns the firehose into filtered JSON without signatures, and since version two can replay the past, so you trust its operator; Tap keeps verification and fetches a repository's past from the host before live events; choose by how much you must verify.

The raw firehose is heavy: binary blocks, signatures, thousands of events a second.

Jetstream turns it into plain JSON, lets you filter by collection, and since version two can replay the past. It drops the signatures, so you trust the Jetstream you connect to.

Tap goes the other way: it keeps the verification. Track a repository, and Tap fetches its past from the host, checks every commit, then hands you the live events.

A bot or a prototype can live on Jetstream. Archives, moderation, and anything that must prove authorship need the signed stream.

Three taps on one pipe. Same events, three ways to receive them. Pick by how much you need to verify.

Check yourself. What does Jetstream drop that the firehose carries?

17. A feed is a service, not a setting

In Bluesky, a custom feed is a service with its own DID that answers with a skeleton of post URIs; the app's server hydrates them; the feed is declared by a record in its author's repository; any HTTPS server can host one.

In Bluesky, a custom feed is a service with its own DID.

Ask it for a feed, and it answers with a skeleton: a list of post addresses, in order. No post content. Just which ones.

The app's server fills the skeleton in with the posts, the authors, the counts.

To publish a feed, you write one record in your own repository that points at the service. Anyone can find it, pin it, and share it.

The ranking is the feed's business. The data is everyone's. A feed can run from any server that answers HTTPS.

Check yourself. What does a feed generator return, and what does it not?

18. Labels: moderation as a subscribable layer

A label is a source, a subject and a value, signed by a labeler's key; users choose labelers and the app requests their labels; what a label does is set outside the label (the labeler suggests, the user adjusts, the app enforces); takedowns at the host are a separate lever.

A label is a sticker on content or an account. Who put it there, what it is on, and a short value: spam, nudity, whatever the service that issued it defines.

Labels are signed by a labeler: a service with its own DID and key.

You choose which labelers to listen to. Your app asks for their labels by name on every request.

What a label does, hide, warn, blur, is set outside the label: the labeler suggests, the user adjusts, the app enforces. Speech and reach are two layers.

A host can still take content down outright. That is a different lever, at a different layer.

Check yourself. Who sets what a label does to a post?

19. OAuth: apps log in without your password

OAuth: an app is identified by a public metadata URL with no secret; login happens at the PDS or its entryway, the authorization server; PAR, PKCE and DPoP are required so tokens are bound to a per-session key; app passwords are the old way.

This is OAuth, the web's login handshake. An app identifies itself with a URL: a public metadata document. No registration form, no shared secret.

You log in at your host, or at the login service your host names. Never inside the app. That host or service is the authorization server.

Three protections are mandatory. PAR, a pushed request. PKCE, a code challenge. And DPoP: tokens bound to a key this copy of the app made for this session.

A stolen token is useless somewhere else. It is a key cut for one lock: bound to the key that asked.

App passwords are the old way: a second password, nearly full access. OAuth replaces them with scopes: named permissions, next.

Check yourself. What binds an access token to one app instance?

20. Permissions name a collection, not an account

A scope names a resource and the thing it covers: repo plus a collection, rpc, blob, account, identity; a namespace owner can bundle its record and service scopes into a permission set, published as a Lexicon; the user sees the list; resources are abstract, not endpoints.

A scope says what an app may touch: a key labeled with one drawer. Repo, then a collection: this app may write recipes. Nothing else.

Other scopes cover calls to a service, uploading blobs, account details, and identity.

Whoever owns a schema namespace can bundle its record and service scopes into a permission set, published as a Lexicon. Named and owned, like any schema.

You see the list before you say yes.

Resources are described in the abstract, not tied to particular endpoints. The shape is fixed: name the thing, not the account.

Check yourself. What does repo:com.example.recipe allow?

21. Moving house without asking permission

Migration exports the repository as a CAR and the blobs, imports them at a new host with new keys, updates the DID document, activates the new account and deactivates the old; if the old host is gone, a rotation key you kept yourself still lets you move.

The goal was always that you can move house, boxes and all, without the old host's help.

Export your repository as one file, and your blobs. Anyone can request them; the data is public and signed.

Import them at the new host. It gives you new signing keys.

Update your DID document: new host, new key. The DID itself does not change. Your followers notice nothing.

Activate the new account, deactivate the old. The network sees the events and follows you home. If the old host is gone, a rotation key you kept yourself still lets you move.

Check yourself. Which change makes the network treat the new host as yours?

22. Public by default; Spaces is the private extension

Everything in a repository is public by design; Spaces is an alpha extension where a space is a gated mini-network with per-space permissioned repos on the author's PDS; it gives access control, not confidentiality; the core is settling and a launch is expected in 2026.

Everything in a repository is public. That is a design choice, and it is what makes the big shared stream possible.

For non public data there is an extension: atproto Spaces. A space is a miniature network, gated so only certain people and apps can read it.

Records in a space live in a separate, permissioned repository on the author's host. A space authority, a DID, decides who gets in.

Spaces give access control, not confidentiality. Data in a space is not encrypted. Anyone admitted can read it.

The alpha opened in August twenty twenty six. Breaking changes have landed since; the core is settling, and a launch is expected this year.

Check yourself. Who can read a record in a space?

23. Who keeps the copy: non-archival relays and Hubble

Relays no longer keep repositories, so a dead host loses its data unless you kept a backup; Hubble is a public mirror of every repository, funded by a Bluesky grant, with no media and deletions respected, so users can recover and apps can backfill.

Relays no longer keep a copy of every repository.

So if a host goes dark, its repositories go with it. Apps cannot load the past. Users without their own backup cannot recover.

Hubble is a public mirror of every repository, a library copy of the whole network, synchronised live. Built and run by one developer's project, with a grant from Bluesky.

It stores records, not media. It respects deletions.

Lose your host, and your repository is still there to recover. The protocol made the data portable. A mirror makes it durable.

Check yourself. What does Hubble store, and what does it not?

24. Where atproto stands

In 2026 an IETF working group was chartered for the repository format, sync, the AT URI and identifier resolution; identity has a neutral steward, founded in 2026, and replicas; sync v1.1 runs on the relays with Tap as reference consumer and pieces to come; Spaces is the open front, with a launch expected this year.

In twenty twenty six an IETF working group was chartered for the protocol. Its first scope: the repository format, the sync mechanism, the AT URI, and identifier resolution.

Identity has a neutral steward, the PLC Organization, founded this year, and the directory can be replicated by anyone.

Sync one point one runs on the relays, with Tap as its reference consumer, and a few pieces still to come. Relays are non archival; Hubble keeps the copy.

The open front is non public data: Spaces is in alpha, and a launch is expected this year.

A map with surveyed and unsurveyed parts. Identity, repositories, sync: settled enough to standardize. Private data: still being designed.

Check yourself. Which four things is the IETF group standardizing first?

Do you like what you are reading? Subscribe to receive updates.

Unsubscribe anytime