perlsky is a Perl 5 implementation of an AT Protocol Personal Data Server.
1# perlsky
2
3An AT Protocol Personal Data Server written in Perl 5 that has been extensively tested and aims for accuracy and parity with the official PDS. Nonetheless, **use it at your own risk**.
4
5
6
7## Why
8
9Look, it started as a joke and then quickly got out of hand.
10
11## What's different about it?
12
13It's written in Perl 5.
14
15## Quick start
16
17```sh
18# install dependencies (Debian/Ubuntu)
19apt-get install -y cpanminus libcbor-xs-perl libcryptx-perl \
20 libdbd-sqlite3-perl libio-socket-ssl-perl
21cpanm --notest Mojolicious@9.42
22
23# run locally
24PERLSKY_CONFIG=config.json perl script/perlsky daemon -l http://127.0.0.1:7755
25
26# check it's alive
27curl http://127.0.0.1:7755/_health
28```
29
30For a real deployment with TLS, systemd, and reverse proxy setup, see [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md).
31
32## What's implemented
33
34- **Accounts and auth** — `createAccount`, `createSession`, refresh tokens, invite codes, email updates, password changes, account deletion. Both `did:web` and `did:plc` account methods.
35- **OAuth** — built-in ATProto OAuth provider surface. Modern clients (like Tangled) can authenticate directly against your PDS using PAR, PKCE, `private_key_jwt`, and DPoP. Supports transition scopes, granular permission families, and `include:<nsid>` scopes.
36- **Repos and sync** — native Perl implementations of CAR, DAG-CBOR, CID, and MST. Full `com.atproto.sync.*` surface including firehose, `getRepo`, and `importRepo` snapshot-restore.
37- **Blobs** — upload, download, deduplication, reference-counted lifecycle.
38- **AppView proxying** — unknown `app.bsky.*` and `chat.bsky.*` requests are forwarded to the public Bluesky services (or your own) using per-account service-auth JWTs.
39- **Moderation** — repo, record, and blob takedowns with real enforcement. Persisted labels with query and subscription support.
40- **Crawler discovery** — notifies configured relays (e.g. `bsky.network`) after repo activity.
41- **Metrics** — Prometheus-compatible endpoint at `/metrics`. See [docs/METRICS.md](docs/METRICS.md).
42
43For endpoint-by-endpoint conformance status, see [docs/ENDPOINT_CONFORMANCE.md](docs/ENDPOINT_CONFORMANCE.md). For the module/facade split, see [docs/CODE_STRUCTURE.md](docs/CODE_STRUCTURE.md).
44
45## Testing
46
47Run the local test suite:
48
49```sh
50prove -lr t
51```
52
53### Differential validation
54
55`perlsky` can be tested side-by-side against the official `@atproto/pds` to verify matching behavior on accounts, repos, moderation, sync, firehose, and `importRepo`. This isn't bulletproof but it still helped to shake out a lot of subtle and not-so-subtle bugs:
56
57```sh
58script/differential-validate
59
60# or with PLC-backed accounts
61PERLSKY_DIFF_ACCOUNT_DID_METHOD=did:plc script/differential-validate
62
63# from the test suite
64PERLSKY_RUN_REFERENCE_DIFF=1 prove -lv t/reference-differential.t
65PERLSKY_RUN_REFERENCE_DIFF=1 prove -lv t/reference-differential-plc.t
66```
67
68The harness installs the reference runtime into `.tools/reference-runtime` with Node 20 via `fnm`.
69
70### Browser smoke — [atproto-smoke](https://tangled.org/alice.mosphere.at/atproto-smoke)
71
72End-to-end smoke tests drive real `bsky.app` sessions against a running `perlsky` instance — posting, following, lists, notifications, settings, and more. The browser runtime is a standalone project, [atproto-smoke](https://tangled.org/alice.mosphere.at/atproto-smoke), designed to work with any AT Protocol PDS. `perlsky` provides a thin adapter script on top of it.
73
74```sh
75# clone atproto-smoke next to perlsky (one-time)
76git clone https://tangled.org/alice.mosphere.at/atproto-smoke.git ../atproto-smoke
77cd ../atproto-smoke && npm install && cd -
78
79# bootstrap a reusable smoke account pair, then run
80script/perlsky-browser-smoke bootstrap-pair # one-time setup
81script/perlsky-browser-smoke run-dual # run the smoke
82```
83
84Full details in [docs/BROWSER_SMOKE.md](docs/BROWSER_SMOKE.md).
85
86### Interop fixtures
87
88Crypto and PLC identity tests run against official Bluesky test vectors and the `@did-plc/lib` mock to keep encoding and identity semantics pinned to upstream.