Files
Joel Hooks cafdf2b45e feat(memory): Phase 3 — PDS App Password auth (code-complete; verify pending infra)
Replaces the dev-bearer table with PDS-backed App Password authentication
per ADR-0243 Rule 20, scoped to single-user (Joel only) for now.

packages/system-bus/src/lib/pds.ts
  + pdsCreateAppPassword — calls com.atproto.server.createAppPassword on
    the caller's session; returns { name, password, did, handle }
  + pdsRevokeAppPassword — revokes by name
  + pdsValidateAppPassword — one-shot validation via createSession; used
    at register time only, NOT per-request (hash lookup is cheaper +
    safer, and doesn't create server-side session state at PDS)

packages/memory/src/schemas/machines.ts — NEW Typesense schema for
  machines_dev collection: id, user_id, did, handle, machine_name,
  app_password_name, app_password_sha256, created_at, last_seen_at,
  revoked_at

apps/web/lib/memory-auth.ts — NEW auth middleware
  authenticateMemoryRequest(req) → MemoryIdentity | null
  Hot path: sha256(bearer) → Typesense machines_dev lookup →
    { user_id, machine_id, did, source: "app-password" }
  No PDS roundtrip per request. App Password validity is established
  at register time; the hash is the identity key thereafter.
  Dev-bearer fallback retained during transition (MEMORY_DEV_BEARER_TOKENS
  env var); effectively disappears when that var is empty in prod.
  Phase 3.5 TODO: users_dev collection (DID→user_id map is hardcoded for
  now).

apps/web/app/api/runs/*/route.ts — all 6 handlers now call
  authenticateMemoryRequest instead of the inline DEV_BEARER_TOKENS
  table + local authenticate() helper. Rule 4 privacy filtering is
  unchanged (still keyed on auth.user_id from the middleware).

scripts/joelclaw-machine-register.ts — NEW provisioning CLI
  Flow: load cached PDS session from ~/.joelclaw/pds-session.json →
  call com.atproto.server.createAppPassword → sha256(plaintext) →
  upsert machines_dev row → back up old auth.json → write new
  auth.json (0600) with the plaintext bearer. Ready to register Panda
  once the infra is back.

Verification status (pending Typesense reachability):
  [x] pds.ts compiles; curl-tested createAppPassword directly against
      PDS (returned valid password)
  [x] Bun fetch works against PDS directly (ruled out fetch-lib bugs)
  [x] All route handlers typecheck + biome clean
  [x] Auth middleware compiles
  [ ] End-to-end: register panda → POST /api/runs with new bearer →
      Run indexes → search returns it — BLOCKED on Colima SSH tunnel
      which is flapping (ssh 192.168.64.2:22 timing out; matches the
      2026-04-17 healer-suicide-loop memory note)

When infra comes back:
  TYPESENSE_API_KEY=<...> joelclaw-machine-register --name panda --user joel
  then POST /api/runs with the new bearer to confirm.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:12:04 -07:00
..