an atproto pds written in F# (.NET 9) 🦒
pds
fsharp
giraffe
dotnet
atproto
1================================================================================
2*roadmap.txt* PDSharp: F#/Giraffe PDS Implementation Roadmap
3================================================================================
4PHASE 1: IMPLEMENTATION (Build)
5================================================================================
6Milestone A: Giraffe XRPC Shell
7--------------------------------------------------------------------------------
8- [x] Implement /xrpc/com.atproto.server.describeServer (GET)
9- [x] Implement NSID-based routing with structured error responses
10DoD: describeServer responds with stable JSON
11--------------------------------------------------------------------------------
12Milestone B: Identity + Crypto Primitives
13--------------------------------------------------------------------------------
14- [x] DID document fetch/parse for signing key and PDS endpoint
15- [x] SHA-256 hashing, ECDSA sign/verify (p256 + k256), low-S enforcement
16DoD: Sign and verify atproto commit hash with low-S
17--------------------------------------------------------------------------------
18Milestone C: DAG-CBOR + CID
19--------------------------------------------------------------------------------
20- [x] Canonical DAG-CBOR encode/decode with IPLD link tagging
21- [x] CID creation/parsing (multicodec dag-cbor, sha2-256)
22DoD: Record JSON → stable DAG-CBOR bytes → deterministic CID
23--------------------------------------------------------------------------------
24Milestone D: MST Implementation
25--------------------------------------------------------------------------------
26- [x] Merkle Search Tree per repository spec
27- [x] Key depth = leading zero bits in SHA-256(key) counted in 2-bit chunks
28- [x] Node encoding: (l, e[p,k,v,t]) with key prefix compression
29DoD: Insert/update/delete yields reproducible root CID
30--------------------------------------------------------------------------------
31Milestone E: Commit + BlockStore + putRecord
32--------------------------------------------------------------------------------
33- [x] BlockStore: cid → bytes, indexed by DID/rev/head
34- [x] Commit signing: UnsignedCommit → DAG-CBOR → sha256 → ECDSA sign
35- [x] Implement com.atproto.repo.putRecord/createRecord
36DoD: Write and read records by path/AT-URI
37--------------------------------------------------------------------------------
38Milestone F: CAR Export + Sync Endpoints
39--------------------------------------------------------------------------------
40- [x] CARv1 writer (roots = commit CID, blocks stream)
41- [x] Implement: sync.getRepo, sync.getBlocks, sync.getBlob
42DoD: External services can fetch repo snapshot + blocks
43--------------------------------------------------------------------------------
44Milestone G: subscribeRepos Firehose
45--------------------------------------------------------------------------------
46- [x] Monotonic sequence number + commit event generation
47- [x] WebSocket streaming for subscribeRepos
48DoD: Relay/client receives commit events after writes
49--------------------------------------------------------------------------------
50Milestone H: Account + Sessions
51--------------------------------------------------------------------------------
52- [x] Implement: server.createAccount, server.createSession, refreshSession
53- [x] Password/app-password hashing + JWT issuance
54DoD: Authenticate and write records with accessJwt
55--------------------------------------------------------------------------------
56Milestone I: Lexicon Validation + Conformance
57--------------------------------------------------------------------------------
58- [x] Lexicon validation for writes (app.bsky.* records)
59- [x] Conformance testing: diff CIDs/CARs/signatures vs reference PDS
60DoD: Same inputs → same outputs for repo/sync surfaces
61--------------------------------------------------------------------------------
62Milestone J: Storage Backend Configuration
63--------------------------------------------------------------------------------
64- [x] Configure SQLite WAL mode (PDS_SQLITE_DISABLE_WAL_AUTO_CHECKPOINT=true)
65- [x] Implement S3-compatible blobstore adapter (optional via config)
66- [x] Configure disk-based vs S3-based blob storage selection
67DoD: PDS runs with S3 blobs (if configured) and SQLite passes Litestream checks
68--------------------------------------------------------------------------------
69Milestone K: Backup Automation + Guardrails
70--------------------------------------------------------------------------------
71- [ ] Implement BackupOps module (scheduler/cron logic)
72- [ ] Automated backup jobs:
73 - [ ] Databases (Litestream or raw copy) + /pds/actors backup
74 - [ ] Local disk blobs (if applicable)
75- [ ] Guardrails & Monitoring:
76 - [x] Uptime check endpoint: /xrpc/_health with JSON status
77 - [x] Alerts: "Latest backup" too old, Disk pressure > 90%
78 - [ ] Log retention policies
79DoD:
80 - Backups run automatically and report status
81 - Health checks indicate system state
82 - Restore drill: Restore backups onto a fresh host passes verification
83 - Backup set is explicitly documented
84================================================================================
85PHASE 2: DEPLOYMENT (Self-Host)
86================================================================================
87Milestone L: Topology + Domain Planning
88--------------------------------------------------------------------------------
89- Choose PDS hostname (pds.example.com) vs handle domain (example.com)
90- Obtain domain, DNS access, VPS with static IP, reverse proxy
91DoD: Clear plan for PDS location, handle, and DID resolution
92--------------------------------------------------------------------------------
93Milestone M: DNS + TLS + Reverse Proxy
94--------------------------------------------------------------------------------
95- DNS A/AAAA records for PDS hostname
96- TLS certs (ACME) via Caddy
97DoD: https://<pds-hostname> responds with valid cert
98--------------------------------------------------------------------------------
99Milestone N: Deploy PDSharp
100--------------------------------------------------------------------------------
101- Deploy built PDS with persistence (SQLite/Postgres + blob storage)
102- Verify /xrpc/com.atproto.server.describeServer
103DoD: describeServer returns capabilities payload
104--------------------------------------------------------------------------------
105Milestone O: Account Creation
106--------------------------------------------------------------------------------
107- Create account using admin tooling
108- Verify authentication: createSession
109DoD: Obtain session and perform authenticated write
110--------------------------------------------------------------------------------
111Milestone P: Smoke Test Repo + Blobs
112--------------------------------------------------------------------------------
113- Write record via putRecord
114- Upload blob, verify retrieval via sync.getBlob
115DoD: Posts appear in clients, media loads reliably
116--------------------------------------------------------------------------------
117Milestone Q: Account Migration
118--------------------------------------------------------------------------------
119- Export/import from bsky.social
120- Update DID service endpoint
121- Verify handle/DID resolution
122DoD: Handle unchanged, DID points to your PDS
123--------------------------------------------------------------------------------
124Milestone R: Updates + Security
125--------------------------------------------------------------------------------
126- Update cadence with rollback plan
127- Rate limits and access controls at proxy
128DoD: Update smoothly, maintain stable federation
129================================================================================
130QUICK CHECKLIST
131================================================================================
132[x] describeServer endpoint working
133[x] Crypto primitives (sha256, ECDSA p256/k256, low-S)
134[x] DAG-CBOR + CID generation correct
135[x] MST producing deterministic root CIDs
136[x] putRecord + blockstore operational
137[x] CAR export + sync endpoints
138[x] subscribeRepos firehose
139[x] Authentication (createAccount, createSession)
140[x] Lexicon validation
141[ ] Domain + TLS configured
142[ ] PDS deployed and reachable
143[ ] Account created, session works
144[ ] Writes + blobs verified
145[/] Backups + monitoring in place (health endpoint done, backup automation pending)
146================================================================================
147REFERENCES
148================================================================================
149https://atproto.com/guides/self-hosting
150https://github.com/bluesky-social/pds
151https://atproto.com/specs/repository
152https://atproto.com/specs/sync
153https://atproto.com/specs/blob
154https://docs.bsky.app/docs/api/com-atproto-server-describe-server
155https://docs.bsky.app/docs/api/com-atproto-server-create-session
156https://docs.bsky.app/docs/api/com-atproto-repo-put-record
157https://docs.bsky.app/docs/api/com-atproto-sync-get-blob