+79
-1
README.md
+79
-1
README.md
···
1
1
# PDSharp
2
2
3
-
Personal Data Server written in F#
3
+
> A Personal Data Server (PDS) for the AT Protocol, written in F# with Giraffe.
4
+
5
+
## Goal
6
+
7
+
Build and deploy a single-user PDS that can host your AT Protocol repository, serve blobs, and federate with Bluesky.
8
+
9
+
## Requirements
10
+
11
+
- .NET 9.0 SDK
12
+
- [Just](https://github.com/casey/just) (optional, for potential future task running)
13
+
14
+
## Getting Started
15
+
16
+
### Restore & Build the project
17
+
18
+
```bash
19
+
dotnet restore
20
+
dotnet build
21
+
```
22
+
23
+
### Run the tests
24
+
25
+
```bash
26
+
dotnet test
27
+
```
28
+
29
+
### Run the Server
30
+
31
+
```bash
32
+
dotnet run --project PDSharp/PDSharp.fsproj
33
+
```
34
+
35
+
The server will start at `http://localhost:5000`.
36
+
37
+
### Verify
38
+
39
+
Check the `describeServer` endpoint:
40
+
41
+
```bash
42
+
curl http://localhost:5000/xrpc/com.atproto.server.describeServer
43
+
```
44
+
45
+
## Configuration
46
+
47
+
The application uses `appsettings.json` and supports Environment Variable overrides.
48
+
49
+
| Key | Env Var | Default | Description |
50
+
| ----------- | ------------------- | ----------------------- | ------------------------- |
51
+
| `DidHost` | `PDSHARP_DidHost` | `did:web:localhost` | The DID of the PDS itself |
52
+
| `PublicUrl` | `PDSHARP_PublicUrl` | `http://localhost:5000` | Publicly reachable URL |
53
+
54
+
Example `appsettings.json`:
55
+
56
+
```json
57
+
{
58
+
"PublicUrl": "http://localhost:5000",
59
+
"DidHost": "did:web:localhost"
60
+
}
61
+
```
62
+
63
+
## Architecture
64
+
65
+
### App (Giraffe)
66
+
67
+
- `XrpcRouter`: `/xrpc/<NSID>` routing
68
+
- `Auth`: Session management (JWTs)
69
+
- `RepoApi`: Write/Read records (`putRecord`, `getRecord`)
70
+
- `ServerApi`: Server meta (`describeServer`)
71
+
72
+
### Core (Pure F#)
73
+
74
+
- `DidResolver`: Identity resolution
75
+
- `RepoEngine`: MST, DAG-CBOR, CIDs, Blocks
76
+
- `Models`: Data types for XRPC/Database
77
+
78
+
### Infra
79
+
80
+
- SQLite/Postgres for persistence
81
+
- S3/Disk for blob storage
+142
roadmap.txt
+142
roadmap.txt
···
1
+
================================================================================
2
+
*roadmap.txt* PDSharp: F#/Giraffe PDS Implementation Roadmap
3
+
================================================================================
4
+
PHASE 1: IMPLEMENTATION (Build)
5
+
================================================================================
6
+
Milestone A: Giraffe XRPC Shell
7
+
--------------------------------------------------------------------------------
8
+
- [x] Implement /xrpc/com.atproto.server.describeServer (GET)
9
+
- [x] Implement NSID-based routing with structured error responses
10
+
DoD: describeServer responds with stable JSON
11
+
--------------------------------------------------------------------------------
12
+
Milestone B: Identity + Crypto Primitives
13
+
--------------------------------------------------------------------------------
14
+
- DID document fetch/parse for signing key and PDS endpoint
15
+
- SHA-256 hashing, ECDSA sign/verify (p256 + k256), low-S enforcement
16
+
DoD: Sign and verify atproto commit hash with low-S
17
+
--------------------------------------------------------------------------------
18
+
Milestone C: DAG-CBOR + CID
19
+
--------------------------------------------------------------------------------
20
+
- Canonical DAG-CBOR encode/decode with IPLD link tagging
21
+
- CID creation/parsing (multicodec dag-cbor, sha2-256)
22
+
DoD: Record JSON → stable DAG-CBOR bytes → deterministic CID
23
+
--------------------------------------------------------------------------------
24
+
Milestone D: MST Implementation
25
+
--------------------------------------------------------------------------------
26
+
- Merkle Search Tree per repository spec
27
+
- Key depth = leading zero bits in SHA-256(key) counted in 2-bit chunks
28
+
- Node encoding: (l, e[p,k,v,t]) with key prefix compression
29
+
DoD: Insert/update/delete yields reproducible root CID
30
+
--------------------------------------------------------------------------------
31
+
Milestone E: Commit + BlockStore + putRecord
32
+
--------------------------------------------------------------------------------
33
+
- BlockStore: cid → bytes, indexed by DID/rev/head
34
+
- Commit signing: UnsignedCommit → DAG-CBOR → sha256 → ECDSA sign
35
+
- Implement com.atproto.repo.putRecord/createRecord
36
+
DoD: Write and read records by path/AT-URI
37
+
--------------------------------------------------------------------------------
38
+
Milestone F: CAR Export + Sync Endpoints
39
+
--------------------------------------------------------------------------------
40
+
- CARv1 writer (roots = commit CID, blocks stream)
41
+
- Implement: sync.getRepo, sync.getBlocks, sync.getBlob
42
+
DoD: External services can fetch repo snapshot + blocks
43
+
--------------------------------------------------------------------------------
44
+
Milestone G: subscribeRepos Firehose
45
+
--------------------------------------------------------------------------------
46
+
- Monotonic sequence number + commit event generation
47
+
- WebSocket streaming for subscribeRepos
48
+
DoD: Relay/client receives commit events after writes
49
+
--------------------------------------------------------------------------------
50
+
Milestone H: Account + Sessions
51
+
--------------------------------------------------------------------------------
52
+
- Implement: server.createAccount, server.createSession, refreshSession
53
+
- Password/app-password hashing + JWT issuance
54
+
DoD: Authenticate and write records with accessJwt
55
+
--------------------------------------------------------------------------------
56
+
Milestone I: Lexicon Validation + Conformance
57
+
--------------------------------------------------------------------------------
58
+
- Lexicon validation for writes (app.bsky.* records)
59
+
- Conformance testing: diff CIDs/CARs/signatures vs reference PDS
60
+
DoD: Same inputs → same outputs for repo/sync surfaces
61
+
================================================================================
62
+
PHASE 2: DEPLOYMENT (Self-Host)
63
+
================================================================================
64
+
Milestone J: Topology + Domain Planning
65
+
--------------------------------------------------------------------------------
66
+
- Choose PDS hostname (pds.example.com) vs handle domain (example.com)
67
+
- Obtain domain, DNS access, VPS with static IP, reverse proxy
68
+
DoD: Clear plan for PDS location, handle, and DID resolution
69
+
--------------------------------------------------------------------------------
70
+
Milestone K: DNS + TLS + Reverse Proxy
71
+
--------------------------------------------------------------------------------
72
+
- DNS A/AAAA records for PDS hostname
73
+
- TLS certs (ACME) via Caddy/Nginx/Traefik
74
+
DoD: https://<pds-hostname> responds with valid cert
75
+
--------------------------------------------------------------------------------
76
+
Milestone L: Deploy PDSharp
77
+
--------------------------------------------------------------------------------
78
+
- Deploy built PDS with persistence (SQLite/Postgres + blob storage)
79
+
- Verify /xrpc/com.atproto.server.describeServer
80
+
DoD: describeServer returns capabilities payload
81
+
--------------------------------------------------------------------------------
82
+
Milestone M: Account Creation
83
+
--------------------------------------------------------------------------------
84
+
- Create account using admin tooling
85
+
- Verify authentication: createSession
86
+
DoD: Obtain session and perform authenticated write
87
+
--------------------------------------------------------------------------------
88
+
Milestone N: Smoke Test Repo + Blobs
89
+
--------------------------------------------------------------------------------
90
+
- Write record via putRecord
91
+
- Upload blob, verify retrieval via sync.getBlob
92
+
DoD: Posts appear in clients, media loads reliably
93
+
--------------------------------------------------------------------------------
94
+
Milestone O: Account Migration (Optional)
95
+
--------------------------------------------------------------------------------
96
+
- Export/import from bsky.social
97
+
- Update DID service endpoint
98
+
- Verify handle/DID resolution
99
+
DoD: Handle unchanged, DID points to your PDS
100
+
--------------------------------------------------------------------------------
101
+
Milestone P: Reliability
102
+
--------------------------------------------------------------------------------
103
+
- Backups: repo storage + database + blobs
104
+
- Restore drill on fresh instance
105
+
- Monitoring: uptime checks for describeServer + getBlob
106
+
DoD: Restore from backup passes smoke tests
107
+
--------------------------------------------------------------------------------
108
+
Milestone Q: Updates + Security
109
+
--------------------------------------------------------------------------------
110
+
- Update cadence with rollback plan
111
+
- Rate limits and access controls at proxy
112
+
- Log retention and disk growth alerts
113
+
DoD: Update smoothly, maintain stable federation
114
+
================================================================================
115
+
QUICK CHECKLIST
116
+
================================================================================
117
+
[ ] describeServer endpoint working
118
+
[ ] Crypto primitives (sha256, ECDSA p256/k256, low-S)
119
+
[ ] DAG-CBOR + CID generation correct
120
+
[ ] MST producing deterministic root CIDs
121
+
[ ] putRecord + blockstore operational
122
+
[ ] CAR export + sync endpoints
123
+
[ ] subscribeRepos firehose
124
+
[ ] Authentication (createAccount, createSession)
125
+
[ ] Lexicon validation
126
+
[ ] Domain + TLS configured
127
+
[ ] PDS deployed and reachable
128
+
[ ] Account created, session works
129
+
[ ] Writes + blobs verified
130
+
[ ] Backups + monitoring in place
131
+
================================================================================
132
+
REFERENCES
133
+
================================================================================
134
+
https://atproto.com/guides/self-hosting
135
+
https://github.com/bluesky-social/pds
136
+
https://atproto.com/specs/repository
137
+
https://atproto.com/specs/sync
138
+
https://atproto.com/specs/blob
139
+
https://docs.bsky.app/docs/api/com-atproto-server-describe-server
140
+
https://docs.bsky.app/docs/api/com-atproto-server-create-session
141
+
https://docs.bsky.app/docs/api/com-atproto-repo-put-record
142
+
https://docs.bsky.app/docs/api/com-atproto-sync-get-blob