Hi all — I’m Dave, founder of Atmos.
Erlend Sogge Heggen pointed me toward this community and suggested I share what we’re building. Wanted to post some architecture notes from building on AT Protocol, since a few of the design decisions might be useful to the broader conversation here.
What Atmos is
A professional network for creatives — designers, photographers, illustrators — that combines portfolio, social feed, CV, and professional tools under one sovereign identity at @yourname.atmos.cv. Currently in a founding-creator phase.
The stack
-
Reference PDS on Fly.io with
PDS_HOSTNAME=atmos.cv -
Identities are
did:plc:registered withplc.directory -
Standard lexicons only:
app.bsky.feed.post,app.bsky.graph.follow,app.bsky.feed.like -
Web app on Cloudflare Pages, PDS proxied through a Cloudflare Worker on the same domain
-
No custom lexicons yet (more on this below)
Dual-write architecture (ATProto-first)
Atmos writes to both a PDS and Firebase, with ATProto as the source of truth. Posts are written to the PDS first — facets, compressed images, the full app.bsky.feed.post record. Only on PDS success does the mirrored Firestore document get created, carrying the atUri as a reference. Follows and likes sync to the PDS via background triggers. If the PDS write fails, nothing gets written. No partial state.
Images are compressed to fit PDS blob limits; full-quality versions go to Firebase Storage with a blobCids map linking the two.
Federation
Federation works today. The Bluesky relay crawls our PDS — Atmos posts are visible on Bluesky’s AppView. In the other direction, Atmos reads from Bluesky’s public API to display federated profiles and posts from across the network. Atmos users can see and interact with Bluesky users, and vice versa.
Account migration (Bluesky → Atmos)
We have a working migration flow: export the repo via com.atproto.sync.getRepo, migrate blobs, create an account on the Atmos PDS with the same DID, import the repo, then rotate the signing key via PLC operation. The user’s identity survives the move — their DID doesn’t change, just where it points.
The lexicon question
Atmos has record types that don’t map to app.bsky.*: portfolio entries, CV/work-history records, and inspiration boards (curated collections). Right now these live entirely in Firebase — not on the PDS, not federable, not portable.
The question I’d love input on: should apps like Atmos define their own lexicons (e.g. cv.atmos.portfolio.entry) for domain-specific records? Or is there value in a shared professional-profile lexicon that multiple apps could interoperate on? This feels directly relevant to the taxonomy conversations happening on this forum.
A note for builders proxying a PDS behind Cloudflare
If your web app and PDS share a domain through a Cloudflare Worker, a few things we hit in production:
-
Cloudflare strips
Sec-Fetch-*headers before the worker sees them. The PDS OAuth provider needsSec-Fetch-Siteto render the authorize page — you’ll need to synthesize it in the worker. -
Using
redirect: 'follow'in the proxy swallows PDS 303 redirects andSet-Cookieheaders. Useredirect: 'manual'. -
The PDS serves its own OAuth UI assets at
/@atproto/oauth-provider/~assets/*— make sure your worker routes those to the PDS, not your web app.
Happy to share the worker code or dig into any of this further.
Handles are live — you can reserve @yourname.atmos.cv now at atmos.cv. Your identity is a real did:plc: on our PDS, registered with plc.directory. It’s yours to keep even if Atmos disappears.
See you on atmos. ![]()
dave.atmos.cv
