An easy-to-host PDS on the ATProtocol, iPhone and MacOS. Maintain control of your keys and data, always.
ezpds#
Last verified: 2026-03-31
Tech Stack#
- Language: Rust (stable channel via rust-toolchain.toml)
- Build: Cargo workspace (resolver v2)
- Database: SQLite via sqlx 0.8 (runtime-tokio + sqlite features)
- Dev Environment: Nix flake + devenv (direnv integration via .envrc)
- Task Runner: just
Commands#
nix develop --impure --accept-flake-config- Enter dev shell (flags required; --impure for devenv CWD detection, --accept-flake-config activates the Cachix binary cache in nixConfig — without it, a cold build takes 20+ minutes)nix build .#relay --accept-flake-config- Build relay binary (output at ./result/bin/relay)nix build .#docker-image --accept-flake-config- Build Docker image tarball (Linux only; output at./result; load withdocker load < result;docker-imageis not exposed on macOS — use a remote Linux builder or CI)just nix-check/nix flake check --impure --accept-flake-config- Validate NixOS module evaluation and flake structurecargo build- Build all cratescargo test- Run all testscargo clippy --workspace -- -D warnings- Lint (warnings as errors)cargo fmt --all --check- Check formatting
Dev Environment#
- Managed entirely by Nix flake + devenv; do not install tools globally
- direnv auto-activates via
.envrc(use flake . --impure --accept-flake-config) - Always run
nix developfrom the workspace root, not from a subdirectory —CARGO_HOMEandRUSTUP_HOMEresolve relative to devenv root - Rust toolchain managed by rustup (not Nix's
rust-default); pinned inrust-toolchain.toml(stable, with rustfmt + clippy + rust-analyzer + iOS targets). On first shell entry,enterShellrunsrustup toolchain installautomatically. - Shell provides: just, cargo-audit, sqlite (runtime binary + dev headers/library for sqlx's libsqlite3-sys), pkg-config, cargo-tauri, node (22.x), pnpm, rustup
LIBSQLITE3_SYS_USE_PKG_CONFIG=1is set automatically by devenv (links sqlx against Nix-provided SQLite instead of bundled)DEVELOPER_DIRis set to/Applications/Xcode.app/Contents/DeveloperinenterShell— Nix's Darwin hooks override it to a stub SDK; the re-export restores real Xcode for iOS tooling (xcrun, simctl, xcodebuild)- Binary cache: devenv.cachix.org (activated by
--accept-flake-config); speeds up cold shell builds significantly - nixpkgs pin:
cachix/devenv-nixpkgs/rolling(devenv's own nixpkgs fork — package versions may differ from upstream nixpkgs.search.dev)
Project Structure#
apps/identity-wallet/- Tauri v2 mobile app (iOS)crates/relay/- Web relay (axum-based)crates/repo-engine/- ATProto repo enginecrates/crypto/- Cryptographic operations (P-256 key generation, did:key derivation, AES-256-GCM encryption, did:plc genesis ops and verification)crates/common/- Shared types and utilitiesnix/- Nix packaging and deployment (docker.nix: container image; module.nix: NixOS module)docs/- Specs, design plans, implementation plans
Mobile#
apps/identity-wallet/— Tauri v2 iOS app (SvelteKit 2 + Svelte 5 frontend, Rust backend)- Developer setup and iOS workstation guide: see
apps/identity-wallet/CLAUDE.md
Flake Outputs#
packages.<system>.relay- Relay binarypackages.<system>.docker-image- Docker image tarball (Linux only)nixosModules.default- NixOS module exposingservices.ezpdsoptions (seenix/CLAUDE.md)devShells.<system>.default- Development shell via devenv
Bruno API Collection#
bruno/- Bruno HTTP client collection for all relay endpoints- Open in Bruno desktop app; select the
localenvironment and setadminTokento your relay admin token - Mandatory: When adding, removing, or changing any route (path, method, request body, response shape, auth), update the corresponding
.brufile inbruno/. New routes get a new.brufile with the nextseqnumber.
Relay Architecture#
See crates/relay/CLAUDE.md for relay-specific module structure,
hard rules (route isolation, pattern comments, DB ownership), and step-by-step guides for
adding routes and DB queries.
Conventions#
- Workspace-level dependency versions in root Cargo.toml; crates use
{ workspace = true } - All crates share version (0.1.0) and edition (2021) via workspace.package
- publish = false (not intended for crates.io)
- No ticket or AC references in source code. Do not add comments like
// MM-123,// AC2.1:, or// MM-84.AC3: descriptionto.rsfiles or CLAUDE.md files. Design plans and test plans indocs/are the right home for ticket traceability. Source code comments should describe why in terms of the system, not which ticket required it.
Boundaries#
- Never edit:
flake.lockby hand (managed bynix flake update) - Never edit:
devenv.local.nixis gitignored for local overrides only flake.nixbuildDepsOnlyis scoped to relay-related crates (relay,repo-engine,crypto,common). Adding a workspace crate with native dependencies not incommonArgs.buildInputs(e.g. Tauri's webkit2gtk/Apple frameworks) requires either adding the crate to the scope list or adding its build inputs tocommonArgs.