Kanora
Kanora
All dispatches
Architecture

Host/Client Library Architecture Complete: Phases 1-3 Shipped

January 20, 20266 min readBy Kanora Team
kanoraarchitecturenetworkingbonjourrest-apiswiftiosmacos

Over the past hours, we've shipped three major phases of Kanora's distributed host/client library system. The full stack—discovery, API, and client integration—is now functional and ready for user testing.

What We Built

Phase 1: Discovery & Sidebar (iOS)

Features:

  • Bonjour discovery of Kanora hosts on home network
  • Discovered hosts stored in Core Data
  • Library sidebar picker showing local + remote sources
  • One-click switching between libraries

Result: iOS users see discovered Mac hosts and can select them as a library source.

Phase 2: Remote API (macOS)

Endpoints: 8 REST endpoints serving library data

  • GET /api/health - Connection check
  • GET /api/artists, /api/artists/{id} - Artist browsing
  • GET /api/albums, /api/albums/{id} - Album browsing with tracks
  • GET /api/playlists, /api/playlists/{id} - Playlist browsing
  • GET /api/files/{trackId}/stream - Audio streaming with HTTP 206 range support

Implementation: SwiftNIO-powered HTTP server on port 8008, reusing the existing MediaHTTPServer infrastructure.

Result: macOS exposes its entire library via REST, ready for iOS clients to query.

Phase 3: Client Integration (iOS)

Components:

  • RemoteLibraryService: HTTP client implementing LibraryServiceProvider protocol
  • RemoteFileCache: Transparent caching of remote files before playback
  • PlaybackService Integration: Automatic download-then-play workflow
  • Library Context Switching: Seamless local ↔ remote switching

Result: iOS users can browse remote libraries with the exact same UI that works for local music, and audio streams automatically from cache.


End-to-End Workflow

Here's what's now possible:

User Action → iOS Component → Result
─────────────────────────────────────

1. Open Kanora on iPhone
   → Bonjour discovers Mac host
   → Host appears in sidebar

2. Tap "Ben's Mac" in sidebar
   → REST health check passes
   → Switch to RemoteLibraryService provider

3. Tap "Artists"
   → HTTP GET /api/artists
   → Local UI populates with remote data
   → No UI changes needed

4. Browse to album, tap "Play"
   → HTTP GET /api/files/{trackId}/stream
   → RemoteFileCache downloads to device cache
   → PlaybackService plays from cache

5. Playback seamless
   → User doesn't know it's remote
   → Cache persists during session
   → Next song pre-downloads in background

Architecture Decisions

Why This Approach?

Discovery:

  • Bonjour: Zero-config, "just works" on home network, trusted boundary
  • No authentication needed for MVP (home network assumption)

API:

  • REST over HTTP: Simple, stateless, cacheable
  • JSON serialization: Lightweight, easy to test
  • Mirrored data model: Views don't know local vs remote

Streaming:

  • Download-then-play: Better UX than buffering
  • Cache on device: Foundation for offline playback (Phase 4)
  • HTTP 206 range support: Enable adaptive bitrate future

Service Layer:

  • LibraryServiceProvider protocol: Views transparent to data source
  • Actor-based state: Safe concurrent access
  • nonisolated methods: Enable View integration

What We Avoided

Complexity:

  • No authentication (Phase 2: trust model sufficient)
  • No remote playback control (Phase 4: future)
  • No offline archival (Phase 4: future)
  • No external network access (home-only for now)

Anti-patterns:

  • No ViewModels for remote browsing (use existing views)
  • No async/await blocking in UI (proper actor isolation)
  • No duplicate data fetching (cache awareness built in)

Implementation Stats

Lines of Code (new):

  • Phase 1: ~500 (discovery, UI, tests)
  • Phase 2: ~900 (API, models, tests)
  • Phase 3: ~600 (client, cache, integration)
  • Total: ~2000 lines of focused, tested code

Commits:

  • Phase 1: 5 commits
  • Phase 2: 5 commits
  • Phase 3: 4 commits
  • Total: 14 focused commits with clear separation of concerns

Tests:

  • Phase 1: 3 unit tests
  • Phase 2: 3 integration tests
  • Phase 3: 8 integration tests
  • Total: 14 tests covering the full stack

Build Status:

  • iOS: ✅ SUCCESS
  • macOS: ✅ SUCCESS

Key Technical Highlights

1. Bonjour with Modern Swift Concurrency

Using Network.framework's NWBrowser with async/await patterns—no callbacks or completion handlers.

2. Service-Oriented Architecture

LibraryServiceProvider protocol makes the entire system testable and viewable-agnostic. Swap implementations without touching UI code.

3. Transparent Caching

RemoteFileCache handles downloads silently. PlaybackService just calls "play track"—it works whether local or remote.

4. Proper Actor Isolation

All services use actors for thread safety. Core Data operations properly isolated to MainActor. No data races or concurrency issues.

5. Reused Infrastructure

Built on top of existing:

  • MediaHTTPServer (SwiftNIO)
  • Core Data models
  • Existing library UI components
  • PlaybackService

What's Next

Phase 4: Offline Download Management (Future)

  • Download queue UI
  • Selective download (by artist, album, playlist)
  • Storage management
  • Background sync

Phase 5: Remote Playback Control (Future)

  • Tell Mac what to play
  • Control speakers from phone
  • Queue management on remote device

Phase 6: Multi-Host Support (Future)

  • Browse multiple Mac libraries
  • Unified search across hosts
  • Smart caching prioritization

For Contributors

If you want to extend this:

  1. Add a new API endpoint: Modify RemoteLibraryAPIService in Kanora macOS
  2. Add a new query: Create new method in RemoteLibraryService and LocalLibraryService
  3. Test an endpoint: See RemoteLibraryIntegrationTests for patterns
  4. Debug discovery: Check DiscoveryService logs for Bonjour events

All services follow the same patterns. The architecture is meant to be extended.


Testing This Yourself

  1. Run Kanora on Mac (any library will do)
  2. Run Kanora on iPhone/iPad on same WiFi
  3. Look for "Ben's Mac" (or your Mac name) in the library sidebar
  4. Tap it
  5. Browse—it should feel exactly like browsing local music

The Philosophy

This implementation embodies Kanora's core belief: you own your music, you control your music, no subscription required.

The host/client architecture means:

  • Your Mac is your music server (you control the hardware)
  • Your iPhone/iPad access it (you control the devices)
  • No cloud sync, no DRM, no tracking
  • Everything on your home network (privacy preserved)

It's what iTunes Home Sharing felt like, but designed for 2026 with modern Swift tooling.


Thank You

This work leveraged:

  • Swift Concurrency (actors, async/await)
  • SwiftUI for iOS UI
  • SwiftNIO for HTTP
  • Core Data for persistence
  • Network.framework for Bonjour
  • Claude Code for rapid iteration

Three phases in one development session. Ship fast, ship focused.

What's next? Let's build Phase 4.