···361361362362End of handoff. Implement auth login and repo list as described, keeping changes focused and testable.
363363364364+365365+--------------------------------------------------------------------------------
366366+367367+## 13) Tangled Core (../tangled-core) – Practical Notes
368368+369369+This workspace often needs to peek at the Tangled monorepo to confirm XRPC endpoints and shapes. Here are concise tips and findings that informed this CLI implementation.
370370+371371+### Where To Look
372372+373373+- Lexicons (authoritative NSIDs and shapes): `../tangled-core/lexicons/**`
374374+ - Repo create: `../tangled-core/lexicons/repo/create.json` → `sh.tangled.repo.create`
375375+ - Repo record schema: `../tangled-core/lexicons/repo/repo.json` → `sh.tangled.repo`
376376+ - Misc repo queries (tree, log, tags, etc.) under `../tangled-core/lexicons/repo/`
377377+ - Note: there is no `sh.tangled.repo.list` lexicon in the core right now; listing is done via ATproto records.
378378+- Knotserver XRPC routes (what requires auth vs open): `../tangled-core/knotserver/xrpc/xrpc.go`
379379+ - Mutating repo ops (e.g., `sh.tangled.repo.create`) are behind ServiceAuth middleware.
380380+ - Read-only repo queries (tree, log, etc.) are open.
381381+- Create repo handler (server-side flow): `../tangled-core/knotserver/xrpc/create_repo.go`
382382+ - Validates ServiceAuth; expects rkey for the `sh.tangled.repo` record that already exists on the user's PDS.
383383+- ServiceAuth middleware (how Bearer is validated): `../tangled-core/xrpc/serviceauth/service_auth.go`
384384+ - Validates a ServiceAuth token with Audience = `did:web:<knot-or-service-host>`.
385385+- Appview client for ServiceAuth: `../tangled-core/appview/xrpcclient/xrpc.go` (method: `ServerGetServiceAuth`).
386386+387387+### How To Search Quickly (rg examples)
388388+389389+- Find a specific NSID across the repo:
390390+ - `rg -n "sh\.tangled\.repo\.create" ../tangled-core`
391391+- See which endpoints are routed and whether they’re behind ServiceAuth:
392392+ - `rg -n "chi\..*Get\(|chi\..*Post\(" ../tangled-core/knotserver/xrpc`
393393+ - Then open `xrpc.go` and respective handlers.
394394+- Discover ServiceAuth usage and audience DID:
395395+ - `rg -n "ServerGetServiceAuth|VerifyServiceAuth|serviceauth" ../tangled-core`
396396+- List lexicons by area:
397397+ - `ls ../tangled-core/lexicons/repo` or `rg -n "\bid\": \"sh\.tangled\..*\"" ../tangled-core/lexicons`
398398+399399+### Repo Listing (client-side pattern)
400400+401401+- There is no `sh.tangled.repo.list` in core. To list a user’s repos:
402402+ 1) Resolve handle → DID if needed via PDS: `GET com.atproto.identity.resolveHandle`.
403403+ 2) List records from the user’s PDS: `GET com.atproto.repo.listRecords` with `collection=sh.tangled.repo`.
404404+ 3) Filter client-side (e.g., by `knot`). “Starred” filtering is not currently defined in core.
405405+406406+### Repo Creation (two-step flow)
407407+408408+- Step 1 (PDS): create the `sh.tangled.repo` record in the user’s repo:
409409+ - `POST com.atproto.repo.createRecord` with `{ repo: <did>, collection: "sh.tangled.repo", record: { name, knot, description?, createdAt } }`.
410410+ - Extract `rkey` from the returned `uri` (`at://<did>/<collection>/<rkey>`).
411411+- Step 2 (Tangled API base): call the server to initialize the bare repo on the knot:
412412+ - Obtain ServiceAuth: `GET com.atproto.server.getServiceAuth` from PDS with `aud=did:web:<tngl.sh or target-host>`.
413413+ - `POST sh.tangled.repo.create` on the Tangled API base with `{ rkey, defaultBranch?, source? }` and `Authorization: Bearer <serviceAuth>`.
414414+ - Server validates token via `xrpc/serviceauth`, confirms actor permissions, and creates the git repo.
415415+416416+### Base URLs, DIDs, and Defaults
417417+418418+- Tangled API base (server): default is `https://tngl.sh`. Do not use the marketing/landing site.
419419+- PDS base (auth + record ops): default `https://bsky.social` unless a different PDS was chosen on login.
420420+- ServiceAuth audience DID is `did:web:<host>` where `<host>` is the Tangled API base hostname.
421421+- CLI stores the PDS URL in the session to keep the CLI stateful.
422422+423423+### Common Errors and Fixes
424424+425425+- `InvalidToken` when listing repos: listing should use the PDS (`com.atproto.repo.listRecords`), not the Tangled API base.
426426+- 404 on `repo.create`: verify ServiceAuth audience matches the target host and that the rkey exists on the PDS.
427427+- Keychain issues on Linux: ensure a Secret Service (e.g., GNOME Keyring or KWallet) is running.
428428+429429+### Implementation Pointers (CLI)
430430+431431+- Auth
432432+ - `com.atproto.server.createSession` against the PDS, save `{accessJwt, refreshJwt, did, handle, pds}` in keyring.
433433+- List repos
434434+ - Use session.handle by default; resolve to DID, then `com.atproto.repo.listRecords` on PDS.
435435+- Create repo
436436+ - Build the PDS record first; then ServiceAuth → `sh.tangled.repo.create` on `tngl.sh`.
437437+438438+### Testing Hints
439439+440440+- Avoid live calls; use `mockito` to stub both PDS and Tangled API base endpoints.
441441+- Unit test decoding with minimal JSON envelopes: record lists, createRecord `uri`, and repo.create (empty body or simple ack).