Archive of https://github.com/w-social-eu/w-social-atproto (see also https://github.com/brw/w-social-atproto-archive)
0

Configure Feed

Select the types of activity you want to include in your feed.

feat: setup claude md docs for each domain to improve claude quality (#135)

* feat: setup claude md docs for each domain to improve claude quality

* fix: fixed feedback & cleaner docs

* fix: feedback lexicon claude md deprication note

---------

Co-authored-by: wilhelmlofsten <107505740+wilhelmlofsten@users.noreply.github.com>

+814
+98
CLAUDE.md
··· 1 + # w-social-atproto — W Social fork of AT Protocol 2 + 3 + W Social's fork of `bluesky-social/atproto`. The **source of truth** for the W Social PDS, AppView (bsky + dataplane), bsync, and ozone services. Custom `eu.wsocial.*` lexicons, Neuro RemoteLogin auth, QuickLogin (W Identity), invitation system, and Python `wadmin` tooling are layered on top of the upstream monorepo. 4 + 5 + ## Related repositories 6 + 7 + This repo is the source of truth for PDS, AppView (bsky + dataplane), bsync, and the ozone backend. Deployment and clients live in sibling repos: 8 + 9 + - [w-social-appview](https://github.com/w-social-eu/w-social-appview) — Helm charts that deploy bsky + dataplane + bsync built from this repo 10 + - [w-social-infrastructure](https://github.com/w-social-eu/w-social-infrastructure) — Nomad job that runs the PDS built from this repo 11 + - [w-social-next-js](https://github.com/w-social-eu/w-social-next-js) — Expo client (iOS/Android/web) that talks to PDS + AppView 12 + - [ozone](https://github.com/w-social-eu/ozone) — Next.js moderation console UI; `packages/ozone/` here is the backend service 13 + - [bluesky-social/atproto](https://github.com/bluesky-social/atproto) — upstream reference; diff against it when merging upstream 14 + 15 + ## Monorepo layout 16 + 17 + ``` 18 + packages/ ~50 TS packages, pnpm workspaces 19 + pds/ PDS — heavily modified for W Social 20 + bsky/ AppView (federated reads) 21 + ozone/ Moderation backend 22 + bsync/ Stash/blob sync 23 + ws-client/ W Social addition — WebSocket client 24 + lex-cli/ Codegen CLI (lexicon → TS) 25 + lexicon/, identity/, repo/, sync/, xrpc/, xrpc-server/, crypto/, did/, syntax/, common/, ... 26 + lex/* Lexicon toolkit subpackages 27 + oauth/* OAuth provider + client packages 28 + internal/* Internal helpers (handle-resolver, simple-store, ...) 29 + services/ Production runtime entrypoints + Dockerfiles 30 + pds/, bsky/, dataplane/, bsync/, ozone/ 31 + lexicons/ JSON lexicon schemas 32 + com/, app/, chat/, tools/, io/ upstream 33 + eu/wsocial/ W Social-only NSIDs (DO NOT touch others) 34 + pds-wadmin* Python admin CLI (Brevo email + admin tasks) 35 + mock-neuro-server/ Test double for Neuro RemoteLogin 36 + quicklogin-client/ Reference QuickLogin web client 37 + examples/ Demo apps (remotelogin, ...) 38 + interop-test-files/ Cross-implementation conformance fixtures 39 + ``` 40 + 41 + ## Key commands 42 + 43 + ```sh 44 + make deps # pnpm install --frozen-lockfile 45 + make build # codegen + tsc across all packages 46 + make codegen # regenerate TS clients/servers from lexicons/ 47 + make test # full test suite (requires Redis + Postgres via dev-infra) 48 + make lint # ESLint + Prettier + tsc verify 49 + make fmt # auto-fix lint + format 50 + make run-dev-env # local PDS + AppView with seeded data 51 + make run-dev-env-logged # same, pino-pretty formatted 52 + pnpm dev # watch-mode tsc across all packages 53 + ``` 54 + 55 + ## Tool versions 56 + 57 + - Node.js `>=18.7.0` (currently pinned to 18 via `make nvm-setup`) 58 + - pnpm `8.15.9+` (managed via Corepack) 59 + - TypeScript `^5.8.3` 60 + - Python `>=3.10` (for `pds-wadmin-modules/`) 61 + 62 + ## Conventions 63 + 64 + - **Don't modify upstream lexicons** (`com.atproto.*`, `app.bsky.*`, `chat.bsky.*`, `tools.ozone.*`). Federation breaks if we diverge. Add to `lexicons/eu/wsocial/` instead. 65 + - **Lexicon-first endpoints** — add the JSON schema first, run `make codegen`, then implement the handler in `packages/pds/src/api/eu/wsocial/...` (or wherever the NSID maps). 66 + - **PDS migrations** are numbered TS files in `packages/pds/src/account-manager/db/migrations/` — never rename existing migrations, only append. 67 + - **Commits:** conventional-ish (`feat:`, `fix:`, `chore:`) but the existing history is mixed; match nearby commits. 68 + - **TypeScript strict** — no `any` unless justified; `noImplicitAny: true` repo-wide. 69 + - **Testing** — Jest is primary; some newer packages use Vitest (`vitest.config.ts` at root). Tests requiring storage run under `packages/dev-infra/with-test-redis-and-db.sh`. 70 + 71 + ## Domain dictionary 72 + 73 + | Term | Meaning | 74 + |---|---| 75 + | **PDS** | Personal Data Server — owns user data and writes (login, posts, profile) | 76 + | **AppView** | Aggregation service for read APIs (feeds, search, profiles); `bsky` + `dataplane` | 77 + | **dataplane** | AppView's indexer; gRPC + firehose consumer, owns the read database | 78 + | **bsync** | Synchronization service between PDS and AppView (subscriptions, mutes, blocks) | 79 + | **firehose** | The WebSocket repo-subscription stream that drives all indexers | 80 + | **lexicon** | The schema language defining XRPC endpoints; NSID-addressed JSON | 81 + | **NSID** | Namespaced ID — reverse-DNS string identifying a lexicon (e.g. `eu.wsocial.admin.createPassInvitation`) | 82 + | **XRPC** | The HTTP+JSON RPC protocol used between atproto services | 83 + | **DID** | Decentralized identifier for accounts (`did:plc:...`, `did:web:...`) | 84 + | **WID** | W Identity — wallet/credential issued by Neuro; binds atproto accounts to real-world identity | 85 + | **JID** | Juridical identifier from Neuro (legal/national ID); used for invitation matching | 86 + | **Neuro** | Trust-anchor identity provider integrated via RemoteLogin | 87 + | **QuickLogin** | OAuth-like flow for the W Identity mobile app (lives under `io.trustanchor.quicklogin.*`) | 88 + 89 + ## Package-level context 90 + 91 + Most packages have their own `CLAUDE.md` with stack, layout, and patterns. See: 92 + 93 + - `packages/pds/CLAUDE.md` — PDS internals + W Social customisations 94 + - `packages/bsky/CLAUDE.md` — AppView read service 95 + - `packages/dataplane/CLAUDE.md` and `services/dataplane/` — indexer 96 + - `services/CLAUDE.md` — production entrypoints, Dockerfiles, runtime config 97 + - `lexicons/CLAUDE.md` — lexicon authoring rules 98 + - and one for every other major package
+15
examples/CLAUDE.md
··· 1 + # examples/ — Demo apps 2 + 3 + Standalone demo applications. Not built, tested, or deployed as part of the main pipeline — they're for documentation and partner integration reference. 4 + 5 + ## Current examples 6 + 7 + - `remotelogin/` — minimal RemoteLogin (Neuro) demo client 8 + 9 + ## Conventions 10 + 11 + - Each example is self-contained with its own `README.md` 12 + - No imports from `packages/*` at relative paths — pretend you're an external consumer; use the published-style import 13 + - Don't put production logic here 14 + 15 + If a demo starts being useful as a real internal tool, promote it out of `examples/` and give it a proper home.
+38
lexicons/CLAUDE.md
··· 1 + # lexicons/ — JSON schemas for XRPC endpoints 2 + 3 + The source of truth for every XRPC endpoint, record type, and subscription in this repo. Each file defines one NSID. Tooling (`@atproto/lex-cli`) reads these and emits TypeScript clients + server stubs. 4 + 5 + ## Directory map 6 + 7 + | Tree | Owner | Touchable? | 8 + |---|---|---| 9 + | `com/` | atproto core (Bluesky) | **No** — upstream-owned, federation breaks if we diverge | 10 + | `app/` | Bluesky app schemas | **No** — upstream-owned | 11 + | `chat/` | Bluesky chat | **No** — upstream-owned | 12 + | `tools/` | Ozone moderation | **No** — upstream-owned | 13 + | `io/trustanchor/` | Trust Anchor / QuickLogin | **Coordinated** — W Social + Trust Anchor co-own; coordinate before changing | 14 + | `eu/wsocial/` | **W Social — yes, edit freely** | All W Social-specific endpoints go here | 15 + 16 + > **Note on `com/`, `app/`, `chat/`, `tools/`:** any W Social additions already living under these namespaces are **deprecated but still in use**. Never add new endpoints there — new W Social functionality goes in `eu/wsocial/`. Existing extensions will be migrated to `eu.wsocial.*` over time, slowly, to preserve backwards compatibility. 17 + 18 + ## eu/wsocial layout 19 + 20 + ``` 21 + eu/wsocial/ 22 + admin/ Admin endpoints (createPassInvitation, ...) 23 + quicklogin/ Account-side QuickLogin endpoints (linkWid, ...) 24 + server/ Server-config endpoints (allocateWidForAccount, checkHandleAvailability, ...) 25 + ``` 26 + 27 + ## Authoring rules 28 + 29 + 1. **Reverse-DNS NSID** — `eu.wsocial.<area>.<verb>`. The file path mirrors the NSID with `/` between segments. 30 + 2. **One NSID per file**, named `<verb>.json` (e.g. `createPassInvitation.json`). 31 + 3. **`type`** at `defs.main.type` is one of `query`, `procedure`, `subscription`, `record`. 32 + 4. **Lint with eslint** — `make fmt-lexicons` enforces JSON formatting. 33 + 5. **Codegen after every change** — `make codegen` from repo root. Generated TS is checked in (`packages/*/src/lexicon/`). 34 + 6. **No breaking changes without a deprecation window** — the W Social Expo client pins this repo's `@atproto/api` and lags behind PDS deploys. 35 + 36 + ## See also 37 + 38 + - `XRPC_ARCHITECTURE.md` in repo root — how a request flows from JSON → handler
+17
mock-neuro-server/CLAUDE.md
··· 1 + # mock-neuro-server — Test double for Neuro RemoteLogin 2 + 3 + A standalone Express server that mocks the Neuro identity provider for PDS tests and local development. Used wherever a real Neuro endpoint would be — login callbacks, JID lookups, JWT issuance for tests. 4 + 5 + ## Stack 6 + 7 + - Node.js (single `server.js`, no TypeScript) 8 + - Lightweight Express + `jose` 9 + 10 + ## When to use 11 + 12 + - **Local dev** — start it alongside `make run-dev-env` if you need to exercise the Neuro flow without a real Neuro tenant 13 + - **PDS tests** — `packages/pds/tests/admin-neuro-endpoints.test.ts` and friends spin this up 14 + 15 + ## Don't ship it 16 + 17 + `mock-neuro-server/` is not bundled with any production image. Never point a deployed PDS at it.
+15
packages/api/CLAUDE.md
··· 1 + # @atproto/api — High-level client SDK 2 + 3 + The typed client library used by application code (and by the W Social Expo app via its `WsocAgent` extension). Wraps `@atproto/xrpc` with: 4 + - Per-NSID typed methods generated from lexicons 5 + - `BskyAgent` / `AtpAgent` session helpers 6 + - Helpers for common types (record references, rich text, blobs) 7 + 8 + ## When to touch 9 + 10 + - After regenerating from lexicons (`make codegen`) — generated files refresh automatically 11 + - Adding non-codegen helpers (rich text utilities, convenience wrappers) 12 + 13 + ## Versioning 14 + 15 + This package is published to npm and consumed by the W Social Expo client. Backwards-incompatible changes need coordination with [w-social-next-js](https://github.com/w-social-eu/w-social-next-js).
+7
packages/aws/CLAUDE.md
··· 1 + # @atproto/aws — AWS helpers 2 + 3 + Shared AWS clients for atproto services: S3 blob stores, CloudFront invalidation, SES, etc. We don't currently run on AWS for W Social production (we use UpCloud + Hetzner via `w-social-infrastructure/`), but tests and migration scripts may still pull this in. 4 + 5 + ## Don't add credentials here 6 + 7 + Configuration comes from env vars at the service level. This package only exposes typed helpers.
+51
packages/bsky/CLAUDE.md
··· 1 + # @atproto/bsky — AppView (read API) 2 + 3 + The Bluesky AppView. Aggregates data from PDSes via the firehose and serves the `app.bsky.*` read endpoints (feeds, search, profiles, threads). In production this is split: `bsky` answers XRPC, `dataplane` indexes the firehose, `bsync` syncs cross-cutting state. They share the same package code but are deployed separately under `services/`. 4 + 5 + ## Stack 6 + 7 + - **Framework:** Express + `@atproto/xrpc-server` 8 + - **DB (reads):** Postgres via `kysely` 9 + - **gRPC:** `@connectrpc/connect` between `bsky` and `dataplane` 10 + - **Cache:** Redis (`ioredis`) — view caches, rate limiting 11 + - **Feature flags:** Custom (`feature-gates.ts`), optional etcd watcher 12 + - **KWS:** Children's-safety integration (`kws.ts`) — age verification 13 + - **Courier:** Notification fan-out (`courier.ts`) 14 + - **Stash:** Cross-AppView keyvalue store (`stash.ts`) 15 + - **Rolodex:** Identity/handle directory (`rolodex.ts`) 16 + 17 + ## Layout (`src/`) 18 + 19 + ``` 20 + api/ XRPC handlers for app.bsky.*, chat.bsky.*, tools.ozone.*, com.atproto.* 21 + auth-verifier.ts Token + service-auth verification (delegates to PDS for user tokens) 22 + config.ts Env parsing 23 + context.ts AppContext DI container 24 + data-plane/ 25 + bsync/ bsync client 26 + client/ gRPC client wrapping the dataplane 27 + server/ Dataplane server implementation (Postgres reads) 28 + hydration/ N-step hydration: take a set of refs → flesh into full views 29 + views/ Final view assembly (posts, profiles, threads, ...) 30 + pipeline.ts Standard hydrate → view pipeline used by handlers 31 + proto/ ConnectRPC-generated bsync + dataplane protocol stubs 32 + courier.ts Push notification dispatcher 33 + kws.ts Kids Web Services age gate 34 + feature-gates.ts Feature-flag plumbing 35 + etcd.ts Optional etcd watcher for live config 36 + ``` 37 + 38 + ## Key patterns 39 + 40 + - **Hydration → View** — handlers don't query Postgres directly. They build a `HydrationState`, hand it to `views/*`, and let the view assemble the response. Adding a new field usually means: add to hydrator, add to view, register in lexicon. 41 + - **Dataplane indirection** — DB reads go through the dataplane gRPC interface (even when bsky+dataplane are co-deployed). Don't reach for `kysely` from inside an XRPC handler. 42 + - **No writes** — this is a read service. Mutations belong on the PDS or, for AppView-private state (mutes, blocks, notifs), in bsync. 43 + 44 + ## Commands 45 + 46 + ```sh 47 + pnpm --filter @atproto/bsky test 48 + pnpm --filter @atproto/bsky build 49 + ``` 50 + 51 + Service entrypoint lives in `services/bsky/api.js`. The dataplane entrypoint is `services/dataplane/index.js`.
+29
packages/bsync/CLAUDE.md
··· 1 + # @atproto/bsync — AppView sync service 2 + 3 + Synchronization service between PDSes and the AppView. Holds AppView-private state that isn't in user repos: notification preferences, push tokens, mute/block lists, subscription state. Exposed via ConnectRPC, called by bsky's handlers. 4 + 5 + ## Stack 6 + 7 + - **RPC:** `@connectrpc/connect-node` (HTTP/2 by default) 8 + - **DB:** Postgres + `kysely` 9 + - **Proto:** generated under `src/proto/` from upstream `.proto` definitions 10 + 11 + ## Layout (`src/`) 12 + 13 + ``` 14 + client.ts Re-exported client used by bsky 15 + config.ts Env parsing 16 + context.ts AppContext 17 + db/ Postgres migrations + queries 18 + proto/ ConnectRPC stubs 19 + routes/ Service handlers (per RPC method) 20 + ``` 21 + 22 + ## Commands 23 + 24 + ```sh 25 + pnpm --filter @atproto/bsync test 26 + pnpm --filter @atproto/bsync build 27 + ``` 28 + 29 + Service entrypoint: `services/bsync/`.
+5
packages/common-web/CLAUDE.md
··· 1 + # @atproto/common-web — Browser-safe shared utilities 2 + 3 + The web-platform-compatible subset of `@atproto/common`. No Node imports. Consumed by `@atproto/api` and other libraries that need to run in browsers. 4 + 5 + If you add a helper here, make sure it really works in a browser — no `Buffer`, no `node:*` imports, no fs/streams.
+5
packages/common/CLAUDE.md
··· 1 + # @atproto/common — Node-only shared utilities 2 + 3 + Helpers that need Node APIs (streams, fs, crypto): CBOR, CID generation, async helpers, byte utilities. Anything Node-only that more than one package needs. 4 + 5 + For browser-compatible equivalents see `@atproto/common-web`.
+14
packages/crypto/CLAUDE.md
··· 1 + # @atproto/crypto — Key + signature primitives 2 + 3 + Low-level crypto for atproto: signing keys (secp256k1, P-256), DID-formatted public keys (`did:key`), and signature verification. No business logic — just primitives. 4 + 5 + ## Used by 6 + 7 + - `@atproto/repo` — commit signing 8 + - `@atproto/identity` — verifying DID document signing keys 9 + - `@atproto/pds` — account keys, service-auth tokens 10 + - `@atproto/oauth-provider` — JWT signing 11 + 12 + ## When to touch 13 + 14 + - Practically never. Crypto bugs are silent and dangerous. If a change is needed, write extensive tests and have it reviewed by someone who's done crypto before.
+25
packages/dev-env/CLAUDE.md
··· 1 + # @atproto/dev-env — Local development environment 2 + 3 + Spins up a full atproto stack (PDS + AppView + ozone + PLC + bsync + bsync) in-process for tests and `make run-dev-env`. **This is the canonical test harness** — most integration tests in this repo go through `TestNetwork` exported here. 4 + 5 + ## Entrypoints 6 + 7 + ``` 8 + src/ 9 + bin.ts Runnable entry (`pnpm run start` from this package) 10 + network.ts TestNetwork — full stack including AppView 11 + network-no-appview.ts TestNetworkNoAppView — PDS-only, faster for PDS-only tests 12 + pds.ts, bsky.ts, ... Individual service test fixtures 13 + seed/ Pre-baked seed data (users, posts, follows, ...) 14 + mock/ Mock identity services (PLC, mail, etc.) 15 + ``` 16 + 17 + ## When to use which 18 + 19 + - **`TestNetwork`** — anything that exercises AppView reads after a PDS write 20 + - **`TestNetworkNoAppView`** — PDS-internal flows (account creation, invitations, Neuro) 21 + - **Seed builders** — when you need a populated network; check `src/seed/` for existing builders before writing your own 22 + 23 + ## Don't ship this 24 + 25 + `@atproto/dev-env` is a devDependency. It pulls in everything; keep it out of production code paths.
+19
packages/dev-infra/CLAUDE.md
··· 1 + # @atproto/dev-infra — Test infra (Redis + Postgres) 2 + 3 + Docker-compose backed Redis + Postgres for running tests. Not a runtime dependency; only used during `make test`. 4 + 5 + ## Files 6 + 7 + - `docker-compose.yaml` — `db_test` (Postgres 5433) + `redis_test` (6380) 8 + - `with-test-db.sh` — starts Postgres, runs the wrapped command, tears down 9 + - `with-test-redis-and-db.sh` — starts both, runs, tears down 10 + - `_common.sh` — shared startup/teardown logic 11 + 12 + ## Usage 13 + 14 + ```sh 15 + ./packages/dev-infra/with-test-redis-and-db.sh pnpm test 16 + ./packages/dev-infra/with-test-db.sh psql postgresql://pg:password@localhost:5433/postgres -c 'select 1;' 17 + ``` 18 + 19 + `make test` already wraps everything with this. You only run the scripts directly when iterating on a single package's tests.
+8
packages/did/CLAUDE.md
··· 1 + # @atproto/did — DID parsing + verification 2 + 3 + Low-level DID handling: parse `did:plc:...` / `did:web:...`, validate format, extract method-specific parts. Doesn't resolve to a document — for that you need `@atproto/identity`. 4 + 5 + ## When to touch 6 + 7 + - Adding support for a new DID method (rare) 8 + - Tightening validation (with tests)
+17
packages/identity/CLAUDE.md
··· 1 + # @atproto/identity — DID + handle resolution 2 + 3 + Resolves atproto identities. Given a handle (`alice.wsocial.eu`) returns the DID. Given a DID returns the DID document and the PDS endpoint. Used everywhere we need to look up where a user's data lives. 4 + 5 + ## Resolvers 6 + 7 + - **HandleResolver** — DNS TXT (`_atproto.<handle>`) + HTTP `/.well-known/atproto-did` 8 + - **DidResolver** — `did:plc` (via PLC directory) + `did:web` (via HTTPS) 9 + 10 + ## Caching 11 + 12 + Production callers should pass an `IdentitiesCache` (e.g. `simple-store-redis`) — without it every resolution hits the network. 13 + 14 + ## See also 15 + 16 + - `packages/internal/handle-resolver/` and `packages/internal/handle-resolver-node/` for the lower-level handle resolution 17 + - `packages/internal/identity-resolver/` for the unified resolver
+26
packages/internal/CLAUDE.md
··· 1 + # packages/internal/* — Internal helper libraries 2 + 3 + Small focused packages that are reused across services but don't deserve a top-level name. Not published independently; treat them as internal. 4 + 5 + ## Subpackages 6 + 7 + | Package | Purpose | 8 + |---|---| 9 + | `did-resolver` | Lower-level DID resolution primitives | 10 + | `fetch` | Cross-platform fetch wrapper with retry/timeout | 11 + | `fetch-node` | Node-specific fetch (with TLS knobs) | 12 + | `handle-resolver` | Handle → DID resolution (platform-neutral) | 13 + | `handle-resolver-node` | Node-specific resolver (DNS over UDP, etc.) | 14 + | `identity-resolver` | Unified handle + DID resolver facade | 15 + | `pipe` | Stream/pipeline helper for async iterators | 16 + | `rollup-plugin-bundle-manifest` | Rollup plugin used by the OAuth UI build | 17 + | `simple-store` | Key-value store interface | 18 + | `simple-store-memory` | In-memory implementation | 19 + | `simple-store-redis` | Redis-backed implementation | 20 + | `xrpc-utils` | Server-side XRPC helpers (rate limiting, validation) | 21 + 22 + ## When to touch 23 + 24 + - Adding a generic Node helper that more than one service needs → consider one of these instead of inlining 25 + - Switching identity resolution backend → `identity-resolver` is the right seam 26 + - Caching tweaks → `simple-store-*` (don't roll your own cache)
+31
packages/lex-cli/CLAUDE.md
··· 1 + # @atproto/lex-cli — Lexicon codegen CLI 2 + 3 + The CLI that turns JSON lexicons (in `lexicons/`) into TypeScript clients and server handlers. Run indirectly via `make codegen` from the repo root, or directly inside a package's `codegen` script. 4 + 5 + ## What it generates 6 + 7 + For each lexicon NSID it emits: 8 + - **Client types** — request/response interfaces consumed by `@atproto/api` 9 + - **Server stubs** — handler signatures consumed by `@atproto/xrpc-server` 10 + 11 + Generated files land in each consuming package's `src/lexicon/` (or `src/client/lexicons.ts`). 12 + 13 + ## When to run 14 + 15 + Any time a `.json` file under `lexicons/` is added, removed, or edited: 16 + 17 + ```sh 18 + make codegen 19 + # or, scoped: 20 + pnpm --filter @atproto/pds codegen 21 + ``` 22 + 23 + The root `precodegen` step builds `lex-cli` first, so a `make codegen` from a clean tree is safe. 24 + 25 + ## Don't edit generated files 26 + 27 + Anything under `src/lexicon/` in a consuming package is regenerated. Treat them as build artifacts. If you need to influence the output, the change goes in the lexicon JSON or in `lex-cli`'s templates. 28 + 29 + ## See also 30 + 31 + - `lexicons/CLAUDE.md` — what lives where in the lexicon tree
+28
packages/lex/CLAUDE.md
··· 1 + # packages/lex/* — Lexicon toolkit subpackages 2 + 3 + A family of lower-level lexicon utilities, broken out so consumers can pick only what they need. Most code in the repo goes through the top-level `@atproto/lexicon` and `@atproto/lex-cli` instead — these are building blocks. 4 + 5 + ## Subpackages 6 + 7 + | Package | Purpose | 8 + |---|---| 9 + | `lex` | Umbrella entry — re-exports the core surface | 10 + | `lex-builder` | Programmatic construction of lexicon docs | 11 + | `lex-cbor` | CBOR encode/decode aware of lexicon types | 12 + | `lex-client` | Typed XRPC client wrapper | 13 + | `lex-data` | Data validation against lexicon refs | 14 + | `lex-document` | LexiconDoc parser + normaliser | 15 + | `lex-installer` | Install lexicons into a registry at runtime | 16 + | `lex-json` | JSON ↔ Lexicon coercion | 17 + | `lex-password-session` | Password-session helpers (used by upstream tooling) | 18 + | `lex-resolver` | Resolve NSIDs to docs (similar to `lexicon-resolver` upstream) | 19 + | `lex-schema` | JSONSchema for LexiconDoc itself | 20 + | `lex-server` | Typed XRPC server wrapper | 21 + 22 + ## When to touch one of these 23 + 24 + Almost never. If you're adding an endpoint, you don't need these. They power `@atproto/lex-cli` and `@atproto/lexicon` under the hood. 25 + 26 + ## See also 27 + 28 + - `packages/lexicon/` and `packages/lex-cli/` — the consumer-facing API
+9
packages/lexicon-resolver/CLAUDE.md
··· 1 + # @atproto/lexicon-resolver — Resolve lexicons from DIDs 2 + 3 + Looks up the lexicon document for a given NSID by resolving the authoritative DID (the namespace owner) and fetching its published lexicon record. Used when a service receives an XRPC call referencing a lexicon it doesn't have locally. 4 + 5 + In practice we ship most lexicons in the repo, so this is mainly relevant for third-party namespaces and federated content. 6 + 7 + ## See also 8 + 9 + - `packages/lexicon/` — the runtime that uses what this resolver returns
+20
packages/lexicon/CLAUDE.md
··· 1 + # @atproto/lexicon — Lexicon schema runtime 2 + 3 + The runtime library that validates data against lexicon schemas. Used by both clients (request encoding) and servers (input/output validation). Pure TypeScript, no Node-only deps where avoidable. 4 + 5 + ## What's here 6 + 7 + - Lexicon parsing (`LexiconDoc` definitions) 8 + - Validators for each primitive (`string`, `bytes`, `cid-link`, `at-uri`, ...) 9 + - Record/blob validators 10 + - The `Lexicons` registry used at runtime 11 + 12 + ## When to touch this 13 + 14 + - Adding a new format/primitive to the lexicon language (rare; upstream concern) 15 + - Fixing a validation bug (always add a regression test in `tests/`) 16 + 17 + ## Don't touch this when 18 + 19 + - You're adding a W Social endpoint — that's a lexicon JSON change + handler change, no runtime change needed 20 + - You're tweaking codegen output — that's `lex-cli`
+33
packages/oauth/CLAUDE.md
··· 1 + # packages/oauth/* — OAuth 2.1 stack for atproto 2 + 3 + The OAuth 2.1 + DPoP implementation atproto uses. Powers the W Social PDS as an OAuth **provider** (issuing tokens for client apps) and supplies client SDKs for web, Node, browser, and Expo. **QuickLogin / W Identity sits on top of this stack** — see the QuickLogin bridge in `packages/pds/src/account-manager/helpers/quicklogin-oauth-bridge.ts`. 4 + 5 + ## Subpackages 6 + 7 + | Package | Role | Used by | 8 + |---|---|---| 9 + | `oauth-provider` | The provider runtime (login UI, token issuance, DPoP) | `@atproto/pds` | 10 + | `oauth-provider-api` | HTTP layer of the provider | `oauth-provider` | 11 + | `oauth-provider-frontend` | Login/consent UI app | `oauth-provider` | 12 + | `oauth-provider-ui` | Reusable UI components for the provider screens | `oauth-provider-frontend` | 13 + | `oauth-client` | Core client (framework-agnostic) | `oauth-client-*` flavours | 14 + | `oauth-client-browser` | Browser SDK | Web client demos | 15 + | `oauth-client-browser-example` | Reference web client | n/a | 16 + | `oauth-client-expo` | React Native / Expo SDK | [w-social-next-js](https://github.com/w-social-eu/w-social-next-js) | 17 + | `oauth-client-node` | Node SDK | Server-to-server flows | 18 + | `oauth-types` | Shared TS types | All of the above | 19 + | `oauth-scopes` | Scope definitions + parsing | provider + clients | 20 + | `jwk` | JWK + JWKS helpers | provider | 21 + | `jwk-jose` | JOSE-backed JWK implementation | Node provider | 22 + | `jwk-webcrypto` | WebCrypto-backed JWK | Browser / Expo | 23 + 24 + ## W Social-specific bits 25 + 26 + - **QuickLogin bridge** — `packages/pds/src/account-manager/helpers/quicklogin-oauth-bridge.ts` translates the W Identity QuickLogin flow into oauth-provider session state. The PDS's provider is otherwise stock. 27 + - **DPoP enforcement** — required for all token use; we don't allow bearer-only clients. 28 + 29 + ## When to touch 30 + 31 + - Adding a new scope → `oauth-scopes` (after coordinating with the W Identity team) 32 + - Tweaking the login screen → `oauth-provider-frontend` / `oauth-provider-ui` 33 + - Bug in token issuance → `oauth-provider`
+49
packages/ozone/CLAUDE.md
··· 1 + # @atproto/ozone — Moderation backend service 2 + 3 + Backend for the Ozone moderation console. The UI lives in a separate repo: [w-social-eu/ozone](https://github.com/w-social-eu/ozone). Implements `tools.ozone.*` XRPC endpoints: report intake, account/label actions, team management, moderator audit trail. 4 + 5 + > Not to be confused with the [ozone](https://github.com/w-social-eu/ozone) repo — that's the Next.js admin UI that talks to **this** service. 6 + 7 + ## Stack 8 + 9 + - **Framework:** Express + `@atproto/xrpc-server` 10 + - **DB:** Postgres via `kysely` 11 + - **Background:** custom daemon (`daemon/`) for scheduled actions, label propagation, jetstream consumption 12 + - **Jetstream:** `jetstream/` — consumes the firehose as a moderator 13 + - **Communication:** templated email/Slack notifications to reporters and subjects 14 + - **Image:** invalidation hooks for CDN purge 15 + 16 + ## Layout (`src/`) 17 + 18 + ``` 19 + api/ XRPC handlers for tools.ozone.* 20 + auth-verifier.ts Moderator-token verification 21 + config/ Env parsing 22 + context.ts AppContext DI 23 + daemon/ Background workers (scheduled actions, label sync) 24 + db/ Postgres migrations + queries 25 + mod-service/ Core moderation actions (apply/revoke labels, takedowns, ...) 26 + team/ Moderator team + role management 27 + set/ Labeler "sets" (groupings of subjects) 28 + verification/ Account verification badges 29 + safelink/ URL safety lists 30 + tag-service/ Subject tags 31 + setting/ Server settings 32 + scheduled-action/ Delayed/conditional actions 33 + sequencer/ Audit-event firehose 34 + jetstream/ Firehose consumer (for live moderation context) 35 + communication-service/ Templated comms (email/Slack) 36 + ``` 37 + 38 + ## Commands 39 + 40 + ```sh 41 + pnpm --filter @atproto/ozone test 42 + pnpm --filter @atproto/ozone build 43 + ``` 44 + 45 + Service entrypoint: `services/ozone/`. 46 + 47 + ## See also 48 + 49 + - The Ozone UI lives in [w-social-eu/ozone](https://github.com/w-social-eu/ozone)
+74
packages/pds/CLAUDE.md
··· 1 + # @atproto/pds — Personal Data Server 2 + 3 + Reference PDS implementation, **heavily forked** for W Social. Owns user data and accepts writes (login, posting, profile edits, blob uploads). Talks to AppView via standard atproto APIs. Forked code lives mostly in `src/account-manager/`, `src/api/eu/`, `src/api/io/trustanchor/`, and the migrations directory. 4 + 5 + ## Stack 6 + 7 + - **Framework:** Express + `@atproto/xrpc-server` 8 + - **DB:** SQLite via `better-sqlite3` + `kysely` query builder (one DB per account in `actor-store/`, plus a shared account DB) 9 + - **Cache/queue:** Redis (`ioredis`) 10 + - **Auth:** Custom JWT layer (`jose`) + Neuro RemoteLogin integration + QuickLogin OAuth bridge 11 + - **Mail:** Nodemailer (legacy); Brevo via Python `wadmin` modules (current) 12 + - **Crypto:** `@atproto/crypto` for signing keys 13 + 14 + ## Layout (`src/`) 15 + 16 + ``` 17 + account-manager/ Account DB, login flow, invitation system, WID inventory 18 + db/migrations/ Numbered TS migrations (append-only) 19 + helpers/ 20 + neuro-auth-manager.ts Neuro RemoteLogin integration 21 + quicklogin-oauth-bridge.ts QuickLogin → OAuth bridge 22 + ... 23 + actor-store/ Per-account repo storage (each user has their own SQLite) 24 + api/ 25 + com/atproto/ Upstream com.atproto.* handlers 26 + admin/ addNeuroLink, listNeuroAccounts, etc. 27 + app/, chat/ Upstream app.bsky.* and chat.bsky.* (proxied to AppView) 28 + eu/wsocial/ W Social custom endpoints (admin, quicklogin, server) 29 + io/trustanchor/ QuickLogin protocol handlers 30 + auth-verifier.ts Access-token + service-auth verification 31 + auth-scope.ts Scope/role definitions 32 + sequencer/ Repo commit firehose emitter 33 + mailer/ Email templates + send 34 + config/ Env parsing and config object 35 + context.ts AppContext — central DI container 36 + did-cache/ DID resolution cache 37 + disk-blobstore.ts Blob storage (filesystem) 38 + image/ Thumbnail/preview generation 39 + pipethrough.ts Proxy reads to AppView 40 + read-after-write/ RAW consistency helpers 41 + repo/ MST commit pipeline 42 + well-known.ts DID + atproto-did discovery routes 43 + ``` 44 + 45 + ## Key patterns 46 + 47 + - **Lexicon-first endpoints** — JSON in `lexicons/eu/wsocial/<name>.json`, run `make codegen` from repo root, then implement handler in `src/api/eu/wsocial/<name>.ts` and register in `src/api/eu/wsocial/index.ts`. 48 + - **Migrations are append-only** — never rename or reorder. Add `NNN-name.ts`, export from `migrations/index.ts`. The current head is `023-refresh-token-login-jid.ts`. 49 + - **AppContext DI** — services get the `AppContext` injected and pull what they need from it. Don't create new ad-hoc singletons. 50 + - **Neuro/QuickLogin integration** lives in `account-manager/helpers/`. Don't sprinkle Neuro calls across the codebase — go through the manager. 51 + 52 + ## Commands 53 + 54 + ```sh 55 + pnpm --filter @atproto/pds test 56 + pnpm --filter @atproto/pds build 57 + ``` 58 + 59 + Tests need Redis + Postgres — run via root `make test`, which wraps with `packages/dev-infra/with-test-redis-and-db.sh`. 60 + 61 + ## Tests 62 + 63 + `tests/` is rich and the **canonical pattern source**. When adding tests: 64 + 65 + - W Social admin/auth tests: `admin-neuro-endpoints.test.ts`, `quicklogin-auth.test.ts`, `invitation-*.test.ts` 66 + - Use the `runTestServer()` / `TestNetwork` helpers from `@atproto/dev-env` 67 + - For Neuro flows, use `mock-neuro-server/` as the test double (started in test setup) 68 + 69 + ## Code style 70 + 71 + - Prettier formatted (root config) 72 + - ESLint with the repo plugins; `pnpm verify` runs the full chain 73 + - No `any` unless commented 74 +
+20
packages/repo/CLAUDE.md
··· 1 + # @atproto/repo — User repo + Merkle Search Tree 2 + 3 + Implements the atproto user repository: an authenticated append-only log of records keyed by collection + rkey, stored as a Merkle Search Tree (MST) over CBOR-encoded blocks. Every user's data on the PDS lives in one of these. 4 + 5 + ## What's here 6 + 7 + - `MST` — the search tree structure 8 + - Commit signing/verification (via `@atproto/crypto`) 9 + - CAR file import/export (the wire format for repo sync) 10 + - Storage abstractions (`RepoStorage` interface; PDS implements one over SQLite) 11 + 12 + ## When to touch 13 + 14 + - Changing the commit format → coordinate with upstream, this affects federation 15 + - Adding a new record-level helper → fine, add a test 16 + - Performance work on the MST → the canonical place 17 + 18 + ## See also 19 + 20 + - `packages/sync/` — the firehose subscriber that consumes these commits
+14
packages/sync/CLAUDE.md
··· 1 + # @atproto/sync — Firehose subscriber + repo sync 2 + 3 + The library every indexer uses to consume `com.atproto.sync.subscribeRepos` (the firehose). Reconnects, parses CAR frames, exposes commits/handles/identities/account events. 4 + 5 + Used by: 6 + - `services/dataplane/` — to index the AppView 7 + - `services/bsync/` — for some cross-cutting state 8 + - `packages/ozone/src/jetstream/` — moderator's view of activity 9 + 10 + ## Key types 11 + 12 + - `Firehose` — the high-level consumer 13 + - `MemoryRunner` / `DiskRunner` — durable cursor strategies 14 + - Frame parsers for each event kind
+7
packages/syntax/CLAUDE.md
··· 1 + # @atproto/syntax — Identifier + format validators 2 + 3 + Validators for atproto-shaped strings: DIDs, handles, NSIDs, AT-URIs, record keys, TIDs. Used everywhere an untrusted input claims to be one of these. 4 + 5 + ## Don't bypass 6 + 7 + If you're handling a user-supplied string that should be one of the above, run it through here. Manual regex checks scattered across the codebase are how we get bugs.
+9
packages/tap/CLAUDE.md
··· 1 + # @atproto/tap — atproto tap client 2 + 3 + CLI/library for low-level inspection of atproto servers — handy for debugging the firehose, dumping repos, or poking at endpoints by hand. Useful in incident response and local exploration. 4 + 5 + ## When to use 6 + 7 + - Reproducing a federation bug 8 + - Sampling firehose traffic 9 + - Verifying a PDS or AppView is up and responding
+27
packages/ws-client/CLAUDE.md
··· 1 + # @atproto/ws-client — WebSocket client (W Social addition) 2 + 3 + Thin WebSocket client used for long-lived atproto streams (firehose subscriptions and similar). Added by W Social on top of the upstream packages. 4 + 5 + ## Stack 6 + 7 + - `ws` (^8.12) for the underlying socket 8 + - Depends on `@atproto/common` for utility helpers 9 + - TypeScript, builds to `dist/` 10 + 11 + ## Layout 12 + 13 + ``` 14 + src/ Client implementation 15 + tests/ Jest tests 16 + ``` 17 + 18 + ## Commands 19 + 20 + ```sh 21 + pnpm --filter @atproto/ws-client test 22 + pnpm --filter @atproto/ws-client build 23 + ``` 24 + 25 + ## When to use it 26 + 27 + Use this package — not raw `ws` — for any atproto WebSocket consumer in this repo. It centralises reconnection, backoff, and CBOR framing.
+19
packages/xrpc-server/CLAUDE.md
··· 1 + # @atproto/xrpc-server — XRPC server framework 2 + 3 + The server-side counterpart to `@atproto/xrpc`. Used by PDS, AppView, ozone, and bsync to expose XRPC endpoints. Handles: 4 + - Route registration from lexicon definitions 5 + - Input/output validation against the lexicon 6 + - Error responses (`InvalidRequestError`, `AuthRequiredError`, ...) 7 + - Subscription (WebSocket) endpoints — the firehose lives on this 8 + 9 + ## How a handler is registered 10 + 11 + 1. Lexicon JSON defines the NSID and shapes 12 + 2. `make codegen` emits a `Server` interface into the consuming package's `src/lexicon/` 13 + 3. The service wires a handler via `server.eu.wsocial.<...>.method({ auth, params, input }, ctx)` 14 + 15 + See `packages/pds/src/api/eu/wsocial/` for canonical examples. 16 + 17 + ## See also 18 + 19 + - `XRPC_ARCHITECTURE.md` in repo root — detailed walk-through
+14
packages/xrpc/CLAUDE.md
··· 1 + # @atproto/xrpc — XRPC client 2 + 3 + The low-level HTTP+JSON client for XRPC. Wrapped by `@atproto/api` for typed access. Handles: 4 + - Request encoding (params, body, headers) 5 + - Response parsing 6 + - Error normalisation (`XRPCError`) 7 + - Auth header injection 8 + 9 + ## When to touch 10 + 11 + - Adding a new transport feature (e.g. new auth scheme) 12 + - Fixing a serialisation bug 13 + 14 + For everyday work — adding an endpoint, calling a service — use `@atproto/api`, which sits on top of this.
+31
pds-wadmin-modules/CLAUDE.md
··· 1 + # pds-wadmin-modules — Python admin CLI modules 2 + 3 + Python modules backing the W Social PDS admin CLI (`bash-wadmin` at repo root). Handles tasks that don't fit cleanly in TypeScript: Brevo (email) automation, bulk admin operations, account lifecycle scripts. 4 + 5 + ## Stack 6 + 7 + - Python `>=3.10` 8 + - `requirements.txt` — runtime deps 9 + - `pyproject.toml` — module metadata 10 + - Brevo SDK for transactional email + lists 11 + 12 + ## Layout 13 + 14 + ``` 15 + brevo_integration.py Top-level Brevo helpers (lists, contacts, automations) 16 + wadmin/ CLI module package (commands invoked via bash-wadmin) 17 + requirements.txt 18 + pyproject.toml 19 + README.md 20 + ``` 21 + 22 + ## Related entry points (repo root) 23 + 24 + - `bash-wadmin` — bash wrapper that activates a venv and dispatches commands 25 + - `pds-wadmin-dev`, `pds-wadmin-stage`, `pds-wadmin-prod` — environment-specific shims pointing at the right PDS URL + secrets 26 + 27 + ## Conventions 28 + 29 + - Keep TypeScript logic in `packages/pds/`; only put things here that are inherently Python (Brevo SDK, data-processing scripts, CSV munging). 30 + - All credentials come from env vars / SOPS-decrypted files. No secrets in this directory. 31 + - New CLI commands go under `wadmin/` as submodules; mirror the pattern of existing ones.
+13
quicklogin-client/CLAUDE.md
··· 1 + # quicklogin-client — Reference QuickLogin web client 2 + 3 + A single-page HTML test client for the QuickLogin / W Identity flow. Hand-crafted, no build step — open `index.html` in a browser pointing at a PDS with QuickLogin enabled and walk through the auth flow. 4 + 5 + ## Use cases 6 + 7 + - **Manual QA** of QuickLogin endpoints during development 8 + - **Reference implementation** for partners integrating QuickLogin 9 + 10 + ## Don't confuse with 11 + 12 + - `packages/oauth/oauth-client-browser-example/` — the upstream OAuth example, generic 13 + - The real W Social client in [w-social-next-js](https://github.com/w-social-eu/w-social-next-js) — that's the production Expo app
+27
services/CLAUDE.md
··· 1 + # services/ — Production runtime entrypoints 2 + 3 + Thin runtime wrappers around the `packages/*` libraries. Each service here is a deployable container: a tiny `index.js` (or `api.js`), a `Dockerfile`, and per-environment env files. 4 + 5 + ## Services 6 + 7 + | Dir | What it runs | Image | Deployed by | 8 + |---|---|---|---| 9 + | `pds/` | `@atproto/pds` | `ghcr.io/w-social-eu/w-social-atproto/pds` | [w-social-infrastructure](https://github.com/w-social-eu/w-social-infrastructure) (Nomad) | 10 + | `bsky/` | `@atproto/bsky` (API only) | `ghcr.io/.../bsky` | [w-social-appview](https://github.com/w-social-eu/w-social-appview) (Helm) | 11 + | `dataplane/` | `@atproto/bsky` (data-plane gRPC server) | `ghcr.io/.../dataplane` | [w-social-appview](https://github.com/w-social-eu/w-social-appview) | 12 + | `bsync/` | `@atproto/bsync` | `ghcr.io/.../bsync` | [w-social-appview](https://github.com/w-social-eu/w-social-appview) | 13 + | `ozone/` | `@atproto/ozone` | `ghcr.io/.../ozone` | [w-social-appview](https://github.com/w-social-eu/w-social-appview) (or wherever ozone runs) | 14 + 15 + ## Conventions 16 + 17 + - **Each service is `~50 lines of glue** — load env, build a server from the package, start listening. Logic belongs in `packages/`. 18 + - **Tracing** — `pds/tracer.js` sets up OpenTelemetry. Other services follow the same shape; keep them consistent. 19 + - **PDS env files** — `dot.env.example.quicklogin` is the QuickLogin-flavoured template; real values come from the infra repo's secrets store. Don't check in real `.env`. 20 + - **Dockerfiles** stay minimal. Build steps live in pnpm workspaces, not in the Dockerfile. 21 + - **`run-script.js`** in `pds/` is the one-shot admin entry (migrations, account ops). Invoked by the wadmin CLI. 22 + 23 + ## When working here 24 + 25 + - Adding a runtime feature flag → env var, parsed in `packages/<service>/src/config.ts`, plumbed via `index.js` only as much as needed 26 + - Adding a new service → mirror the layout of `bsync/` (the smallest one) 27 + - Changing the Dockerfile → flag it; deployment in the appview/infrastructure repos may need a matching change