A Rust workspace for the AT Protocol · MIT · crates.io 0.14.5 · git 0.15.0-rc.6
AT Protocol,
from the CID up.
Twenty crates that implement the protocol’s primitives directly: content addressing, identity, repositories, authorisation, transport. You can build a service without inheriting somebody’s framework — and two of the twenty are services built that way: a PDS, and an entryway that fronts a cluster of them.
§ 01
What this is
Most of this workspace was extracted from smokesignal.events, an AT Protocol event and RSVP application, and released under MIT so the parts could be used on their own. That origin shows in the shape of the code: these are libraries that were load-bearing in production before they were packaged.
The crates are separable. atproto-dasl will compute CIDs without dragging in a DID resolver; atproto-repo will read a CAR file without an HTTP client. Nothing here is an “SDK” that assumes it owns your main.
Read the version numbers
Fourteen of the twenty crates are published on crates.io at 0.14.5. The workspace in git is ahead of that, at 0.15.0-rc.6, and no release candidate has been published or tagged. If you depend on a version string from the repository README, Cargo will not find it.
Six crates are not on crates.io at all. Two never will be: atproto-pds and atproto-entryway are servers, publish = false, built from the repository or the container images. atproto-firehose, atproto-space and atproto-space-client are publishable and have not been released; use a git dependency. atproto-oauth-dioxus is unmaintained and does not currently build. Read the status column first.
Three more point the other way. atproto-oauth-aip, atproto-xrpcs-helloworld and atproto-oauth-axum are still resolvable on crates.io at 0.14.5, but they have been removed from the workspace and will not be released again. Cargo will happily build against them; nothing upstream will change under them either. See what replaced them.
§ 02
How the crates stack
Layers depend downward. Nothing in a lower band knows the band above it exists, which is why you can take atproto-dasl or atproto-identity in isolation and leave the rest.
§ 03
Start here
Take the smallest set that does the job. Every crate is separately versioned and separately publishable; there is no meta-crate that pulls in the workspace.
[dependencies]
atproto-identity = { version = "0.14.5", features = ["hickory-dns"] }
atproto-record = "0.14.5"
atproto-attestation = "0.14.5"
atproto-client = "0.14.5"
reqwest = "0.12" # the line 0.14.5 is built against
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
anyhow = "1"
use std::time::Duration;
use atproto_identity::resolve::{HickoryDnsResolver, resolve_subject};
use reqwest::{Client, redirect::Policy};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// The handle names the host this fetches from: refuse redirects.
let http_client = Client::builder()
.redirect(Policy::none())
.timeout(Duration::from_secs(10))
.build()?;
// Empty slice = system nameservers.
let dns_resolver = HickoryDnsResolver::create_resolver(&[]);
let did = resolve_subject(
&http_client, &dns_resolver, "alice.bsky.social",
).await?;
println!("{did}");
Ok(())
}
On the git workspace the call is the same, but the client is not: 0.15 is built on reqwest 0.13, and every crate whose API takes a reqwest type re-exports the one it was compiled against. Take Client from atproto_identity::reqwest and drop your own reqwest line; a 0.12 Client is a different type, and the error reads “expected Client, found Client”.
§ 04
Contents
- Catalogue — all twenty crates with plate marks, published versions, status, module surface, and links to docs.rs and source.
- Guides — six walkthroughs: resolve an identity, verify a repository CAR, sign a record, complete an OAuth flow, write a record to a PDS, consume the firehose.
- Concepts — what this workspace means by CID, DRISL, MST, TID, DPoP, NSID, and attestation, with the crate that owns each.
- Tools — all eighteen binaries — the command-line tools, the
atpmcpMCP server, and thepdsandentrywayservers — with the feature flags they need and what they print. - PDS — operating
atproto-pds: storage, environment, build flags, entryway mode, and an honest account of what is not wired up. - Entryway — operating
atproto-entrywayin front of one or more PDS instances: keys, member PDSes, configuration, and what it owns that the PDS gives up.