Concepts
The AT Protocol’s vocabulary shows up in every method name and model in this SDK. This page is a short translation of that vocabulary into Python, enough to read the rest of the documentation, with a link to the real specification for each term.
Note
This is not a protocol tutorial and does not try to be. The protocol is documented properly at atproto.com, and there is a full glossary. Everything below is here only so the SDK’s naming makes sense.
Identity
- Handle
A domain name that identifies an account:
marshal.dev,alice.bsky.social. Handles are human-readable and can change. Resolve one with IdResolver:from atproto import IdResolver did = IdResolver().handle.resolve('marshal.dev')- DID
The stable identifier behind a handle:
did:plc:...ordid:web:.... It never changes, so this is what you store in your database, and it is what every method wanting a “repo” argument expects.client.me.didafter login.- DID document
What a DID resolves to: the account’s current handle, its signing key, and the PDS hosting it. The SDK models it as DidDocument, with
get_pds_endpoint()andget_signing_key()accessors. The client reads it at login to find your PDS.See Identity.
Storage
- PDS
Personal Data Server, the host that stores an account’s repository and serves its API. Not necessarily
bsky.social; the client follows whichever one your DID document names.- Repository
The account’s data, as a signed key-value store of records. Everything you create (posts, likes, follows, your profile) is a record in your repository.
- Collection
A namespace within a repository, named by NSID. All your posts live in the
app.bsky.feed.postcollection.- Record
One JSON document in a collection, validated against a lexicon. In the SDK a record is a Pydantic model:
models.AppBskyFeedPost.Record.- Record key (rkey)
A record’s identifier within its collection. Usually a timestamp-based
TID, but some records use a literal key: your profile is always at rkeyself.- AT-URI
The address of a record:
at://did:plc:.../app.bsky.feed.post/3k5z.... The SDK models it as AtUri, which is how you get from a URI back to its parts:from atproto import AtUri uri = AtUri.from_str('at://did:plc:abc/app.bsky.feed.post/3k5z') uri.hostname, uri.collection, uri.rkey- CID
A content hash identifying an exact version of a record. Write methods that modify or delete something take both a URI and a CID, so the server can tell you are acting on the version you think you are.
- Blob
Binary content, images and video, stored separately from records. You upload one with
upload_bloband get back a BlobRef to embed in a record. See Posting.
Schemas
- Lexicon
A JSON schema describing a record type or an API method. Every model and every namespace method in this SDK is generated from one. The network’s lexicons ship with the SDK; yours can be compiled the same way. See Custom lexicons.
- NSID
The reverse-domain name of a lexicon:
app.bsky.feed.post,com.atproto.repo.createRecord. NSIDs are the organising principle of the whole SDK. They become namespace paths (client.app.bsky.feed.post), model aliases (models.AppBskyFeedPost), and constants (models.ids.AppBskyFeedPost).- XRPC
The HTTP convention the protocol uses: every lexicon method is a
GET(query) orPOST(procedure) at/xrpc/<nsid>.client.app.bsky.feed.get_timeline(...)is one of these.
The network
- AppView
A service that aggregates the network into something readable: timelines, threads, follower counts.
app.bsky.*methods are AppView methods;com.atproto.*methods are protocol ones your PDS serves. This is why a non-Bluesky PDS may not answerapp.bsky.actor.getProfile.- Relay
A service that aggregates every PDS’s events into one stream. That stream is the firehose.
- Jetstream
A lighter-weight view of the same events as plain JSON, filtered server-side. No signatures, so no cryptographic verifiability, but far cheaper to consume. See Jetstream.
- Feed generator
A service you run that returns a list of post URIs, which Bluesky then renders as a custom feed. See Building a feed generator.
- Labeler
A moderation service that publishes labels on accounts and records. See Proxies and labelers.
Naming conventions in this SDK
Lexicons are camelCase; Python is not. The generator translates consistently:
Lexicon |
Python |
|---|---|
|
|
|
|
|
|
|
|
One wrinkle: fields whose name collides with a Python keyword get a trailing underscore, so the lexicon’s validate becomes validate_.
See Working with models for the full story.