A Rust workspace for the AT Protocol · MIT · v0.14.5
AT Protocol,
from the CID up.
Eighteen crates that implement the protocol’s primitives directly: content addressing, identity, repositories, authorisation, transport. You can build a service without inheriting somebody’s framework.
§ 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
Fifteen of the eighteen crates are published on crates.io at 0.14.5. The workspace in git is ahead of that, at 0.15.0-rc.2, and no release candidate has been published. If you depend on a version string from the repository README, Cargo will not find it.
Three crates are not on crates.io at all: atproto-pds, atproto-space, and atproto-oauth-dioxus. Use a git dependency, and read the status column first.
Two more point the other way. atproto-oauth-aip and atproto-xrpcs-helloworld 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"
use atproto_identity::resolve::{create_resolver, resolve_subject};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let http_client = reqwest::Client::new();
// Empty slice = system nameservers.
let dns_resolver = create_resolver(&[]);
let did = resolve_subject(
&http_client, &dns_resolver, "alice.bsky.social",
).await?;
println!("{did}");
Ok(())
}
§ 04
Contents
- Catalogue — all eighteen 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 — the thirty command-line binaries, what feature flags they need, and what they print.
- PDS — operating
atproto-pds: storage profiles, environment, build flags, and an honest account of what is not wired up.