Files
at-container-registry/docs/SAILOR.md
2025-10-06 16:28:58 -05:00

3.7 KiB

User approved Claude's plan: ⎿ Implement Sailor Profile & Hold Discovery System

Summary

Add io.atcr.sailor.profile record type to manage user's default hold preference, and update manifest to store historical hold endpoint reference. This enables transparent hold 
routing while preserving image ownership semantics.

Changes Required

1. Create Sailor Profile Lexicon

File: lexicons/io/atcr/sailor/profile.json
- New record type: io.atcr.sailor.profile
- Fields: defaultHold (string, nullable), createdAt, updatedAt

2. Update Manifest Lexicon

File: lexicons/io/atcr/manifest.json
- Add holdEndpoint field (string, required)
- This is historical reference (immutable per manifest)

3. Update Go Types

File: pkg/atproto/lexicon.go
- Add SailorProfileCollection = "io.atcr.sailor.profile"
- Add SailorProfileRecord struct
- Add NewSailorProfileRecord() constructor
- Update ManifestRecord struct to include HoldEndpoint field

4. Create Profile Management

File: pkg/atproto/profile.go (new file)
- EnsureProfile(ctx, client, defaultHoldEndpoint) function
- Logic: check if profile exists, create with default if not

5. Update Auth Handlers

Files: pkg/auth/exchange/handler.go and pkg/auth/token/service.go
- Call EnsureProfile() after token validation
- Use authenticated client (has write access to user's PDS)
- Pass AppView's default_hold_endpoint config

6. Update Hold Resolution

File: pkg/middleware/registry.go
- Update findStorageEndpoint() priority:
  a. Check io.atcr.sailor.profile.defaultHold
  b. If null (opted out): check user's io.atcr.hold, then AppView default
  c. If no profile: check user's io.atcr.hold, then AppView default

7. Store Hold in Manifest

File: pkg/atproto/manifest_store.go
- When creating manifest, include resolved holdEndpoint
- Pass hold endpoint through context or parameter

8. Update Pull to Use Manifest Hold

File: pkg/atproto/manifest_store.go and pkg/storage/routing_repository.go
- On pull, extract holdEndpoint from manifest
- Route blob requests to that hold (not via discovery)

9. Update Documentation

Files: CLAUDE.md, docs/BYOS.md, .env.example
- Document sailor profile concept
- Explain hold resolution priority
- Update examples for shared holds
- Document how crew members configure profile

Benefits

- ✅ URL structure remains atcr.io/<owner>/<image> (ownership clear)
- ✅ Hold is transparent infrastructure (like S3 region)
- ✅ Supports personal, shared, and public holds
- ✅ Historical reference in manifest (pull works even if defaults change)
- ✅ User can opt-out (set defaultHold to null)
- ✅ Future: UI for self-service profile management

Progress Summary

Completed:

  1. Created io.atcr.sailor.profile lexicon
  2. Updated io.atcr.manifest lexicon with holdEndpoint field
  3. Updated Go types in pkg/atproto/lexicon.go
  4. Created profile management in pkg/atproto/profile.go
  5. Updated /auth/exchange handler to manage profile

In Progress:

  • Need to update /auth/token handler similarly (add defaultHoldEndpoint parameter and profile management)
  • Fix compilation error in extractDefaultHoldEndpoint() - should use configuration.Middleware type not any

🔜 Remaining:

  • Update findStorageEndpoint() for new priority logic (check profile → own hold → default)
  • Update manifest_store.go to include holdEndpoint when creating manifests
  • Update pull flow to use manifest holdEndpoint
  • Update documentation

The architecture is solid - just need to finish the token handler update and fix the type issue in the config extraction. Would you like me to continue?