This is the implementation root for the native macOS reference client.
It owns pairing and Keychain credentials, catalogue browsing, selective verified caching, controller UX, emulator and BIOS adapters, launch preflight, offline operation, and persistent-save capture and recovery. SwiftUI is the default UI technology with targeted AppKit integration where the empirical Mac adapter spike required it.
The client depends only on the versioned HTTPS protocol and downloaded assets — not Phoenix LiveView internals or server implementation details.
The shipping client. Separate from and does not reuse spike/, which stays as the throwaway probe harness from plan 03-01.
- App target
Playstead(bundle iddev.playstead.mac, macOS 14.0 deployment target, SwiftUI lifecycle), plus aPlaysteadTestsunit test target. - File-system-synchronized source group.
Playstead/(andPlaysteadTests/) are added to the project as an Xcode 16+PBXFileSystemSynchronizedRootGroup, not a conventionalPBXGroupof individually-listedPBXFileReferences. This is a deliberate, load-bearing setup choice: adding a new Swift source file to either target means writing it to disk under the matching directory — noproject.pbxprojedit required. Four later plans in this phase land in two parallel waves and would otherwise all need to edit the sameproject.pbxprojconcurrently, guaranteeing merge conflicts across worktrees. Xcode auto-includes every file under a synchronized root group in the target's build; there is noPBXBuildFile/PBXSourcesBuildPhaseentry to add either. - No third-party Swift Package Manager dependency in this phase. Local persistence uses the system
libsqlite3through a small hand-writtenSQLiteConnectionwrapper (prepare/bind/step/finalize plus atransactionhelper) — seePlaystead/Persistence/. This is the discretion CONTEXT.md grants for the persistence-library choice; the OS-provided library removes both the supply-chain verification burden and the nested-code-signing surface a bundled SPM package would add to notarization. - Signing. Ordinary local Xcode builds and tests use ad-hoc signing with no team or provisioning profile, matching the no-HID verification lane. The default UI-test entitlement file omits Virtual HID; the controller-entitlement test remains a separate lane and requires its approved profile. The app keeps hardened runtime enabled and is not App-Sandboxed (
com.apple.security.app-sandbox= false inPlaystead/App/Playstead.entitlements, per D-04 — sandbox would break launching a downloaded third-party emulator process).scripts/build-release.shreads a Developer ID Application identity from thePLAYSTEAD_DEV_ID_APPenvironment variable andPLAYSTEAD_TEAM_IDfor a distributable Release build; notarization is deferred per the 2026-08-30 owner decision recorded in03-ADAPTER-PIN.json(no paid Apple Developer Program membership yet) —scripts/sign-and-notarize.shsupports it unchanged once a notary keychain profile exists, but this plan does not attempt to run it.
AppPaths centralises the cache root at ~/Library/Application Support/Playstead/ (excluded from Time Machine/iCloud backup on first creation) — never ~/Library/Caches/, which the OS may purge and would break the pinned-offline promise (D-20). Subdirectories: objects/<aa>/<bb>/<sha256> (content-addressed cache), partials/ (in-progress downloads), launch/<asset_set_id>/ (materialized launch directories, clone/copy only — never a hard link into objects/), emulators/<name>/<version>/ (downloaded, hash-verified adapter binaries, quarantine attribute always left intact). The SQLite mirror lives at playstead.sqlite3 in the same root.
cd playstead-mac
xcodebuild build -scheme Playstead -destination 'platform=macOS'
xcodebuild test -scheme Playstead -destination 'platform=macOS'