No description
Find a file
2026-04-27 22:29:35 -04:00
apps/pds Align service auth expiration and lxm validation 2026-04-27 22:29:35 -04:00
config Preserve local tunnel config 2026-04-26 15:41:57 -04:00
.codex Initial commit. 2026-04-26 15:41:53 -04:00
.elp.toml Initial commit. 2026-04-26 15:41:53 -04:00
.gitignore Implement Erlang ATProto PDS core 2026-04-26 15:41:53 -04:00
LICENSE.md Initial commit. 2026-04-26 15:41:53 -04:00
README.md Harden firehose framing and repo create semantics 2026-04-26 15:41:56 -04:00
rebar.config Implement Erlang ATProto PDS core 2026-04-26 15:41:53 -04:00
rebar.lock Initial commit. 2026-04-26 15:41:53 -04:00

pds

An Erlang/OTP ATProto Personal Data Server built on Cowboy.

This repository implements the core PDS runtime shape:

  • Cowboy XRPC routing under /xrpc/:nsid
  • local Erlang storage for accounts, sessions, records, blobs, and repo events
  • ATProto account/session/app-password endpoints with did:plc creation through the PLC directory
  • repo record mutation, lookup, listing, blob upload, and CAR export
  • identity handle/DID helpers, verified updateHandle, local resolveDid/resolveIdentity, hosted /.well-known/atproto-did, and hosted /.well-known/did.json
  • OAuth metadata, PAR, authorization-code, refresh-token, and JWKS endpoints with stored single-use grants and PKCE checks
  • sync list/status/latest/repo/record/blob endpoints plus subscribeRepos WebSocket frames
  • official vendored com.atproto.* and app.bsky.* lexicons
  • app.bsky.* and validated atproto-proxy forwarding, including did:web and did:plc DID document service resolution
  • per-account secp256k1 signing keys for DID docs and ES256K service auth JWTs
  • PBKDF2-SHA256 password hashing with legacy SHA256 verification for existing local data
  • sharded local persistence for accounts, sessions, records, blobs, repo status, OAuth grants, and events
  • EUnit coverage for validators, JWTs, codecs, OAuth grants, storage state, HTTP routing, lexicons, proxy resolution, PLC operations, stale swaps, missing blobs, firehose framing, and blob roundtrips

Build

rebar3 compile
rebar3 eunit

For an OTP smoke test without opening a listener, use http.enabled => false:

erl -pa _build/default/lib/*/ebin -noshell \
  -eval 'application:load(pds),
         application:set_env(pds, storage, #{data_dir => "/tmp/pds-smoke", persist => false}),
         application:set_env(pds, http, #{enabled => false}),
         io:format("~p~n", [application:ensure_all_started(pds)]),
         application:stop(pds),
         halt().'

For normal local use, keep HTTP enabled and run:

rebar3 shell

The default listener is 0.0.0.0:8080.

Configuration

Runtime configuration lives in config/sys.config.

  • http: listener IP/port, body limits, blob limits, and enabled
  • storage: local data directory and persistence toggle
  • identity: public base URL, hosted handle domain, optional available_user_domains, PLC directory and plc_submit, default AppView, explicit service_proxies, optional handle_resolutions test/operator overrides, and optional DID document overrides
  • auth: issuer, token TTLs, OAuth grant TTLs, PBKDF2 iteration count, local session JWT secret, and admin password
  • limits: repo pagination and firehose buffer knobs

apps/pds/priv/data/ is ignored and is the default local persistence directory.

Compliance Notes

The implementation follows ATProto wire shapes and endpoint names, but it is not yet a production-certified Bluesky PDS. Service auth JWTs are asymmetrically signed with account keys published in DID documents, PLC creation/update uses signed plc_operation objects submitted to the configured directory, OAuth authorization-code issuance is stored and single-use, blob CIDs use the raw multicodec, and repo CAR exports include deterministic commit/tree/record blocks. Remaining broad interop work includes the PLC email-token flow, OAuth DPoP proof verification, a complete signed MST repository implementation, deeper recursive Lexicon validation, full firehose backfill/diff fidelity, and tests against the official TypeScript implementation.