34 KiB
Companion Targets — End-to-End Implementation Prompt
Purpose: Delegatable prompt for an AI coding agent to bring all 7 watchOS and macOS companion targets from 15-30% stubs to 100% production-ready. Date: 2026-03-27 Scope: 5 watchOS apps + 2 macOS apps across 5 product repos Estimated effort: ~8-12 focused agent sessions
Table of Contents
- Global Rules
- Target Inventory & Current State
- ChronoMind watchOS — 25% → 100%
- ChronoMind macOS — 30% → 100%
- JarvisJr watchOS — 25% → 100%
- JarvisJr macOS — 30% → 100%
- PeakPulse watchOS — 20% → 100%
- NomGap watchOS — 35% → 100%
- ByteLyst Auth watchOS — 15% → 100%
- Cross-Cutting Tasks
- Acceptance Criteria
- Build Verification Commands
1. Global Rules
Coding conventions (MUST follow for ALL targets)
- All logging via
os.Logger— never useprint() - All colors from product theme files — never hardcode hex values in views
- Use
#if canImport(WatchKit)/#if os(watchOS)for platform-conditional code - watchOS minimum: watchOS 10+. macOS minimum: macOS 14+
- Shared code lives in the iOS app's
Shared/directory — companion targets import from there - Data flow between iPhone ↔ Watch uses App Group (
UserDefaults(suiteName:)) +WCSession(WatchConnectivity) - Data flow between iPhone ↔ Mac uses App Group shared
UserDefaults - Commit messages:
feat(watch): descriptionorfeat(mac): description - Never add emojis to code unless the existing codebase already uses them in that file
- Every new file needs a one-line header comment describing its purpose
Architecture pattern for ALL watchOS apps
ProductWatch/
├── ProductWatchApp.swift # @main entry point
├── Views/
│ ├── WatchContentView.swift # Main navigation hub
│ ├── Watch[Feature]View.swift # Feature-specific views
│ └── Components/ # Reusable watch components
├── Store/
│ └── WatchStore.swift # ObservableObject reading from App Group
├── Complications/
│ └── WatchComplications.swift # WidgetKit complications (4 families)
└── WatchSessionManager.swift # WCSession delegate (if bidirectional sync needed)
Architecture pattern for ALL macOS apps
ProductMac/
├── ProductMacApp.swift # @main, MenuBarExtra scene
├── Views/
│ ├── MenuBarPopover.swift # Main popover content
│ ├── MacSettingsView.swift # Settings window (TabView)
│ └── Components/ # Reusable mac components
├── Store/
│ └── MacStore.swift # ObservableObject, App Group sync
└── ProductMac.entitlements # App sandbox + App Group
Shared code reuse rules
Each companion target should import types and engine logic from the iOS app's Shared/ directory. The companion target should NEVER duplicate:
- Model types (timer states, agent configs, session models)
- Engine logic (timer calculations, stage computation)
- Theme colors
- App Group keys and data format
The companion target SHOULD have its own:
- Views (optimized for small/menu-bar screen)
- Store (lightweight, reads from shared data)
- Complications/Widgets (WidgetKit)
2. Target Inventory & Current State
| # | Product | Target | Repo | Directory | Current % | Files | Key Gap |
|---|---|---|---|---|---|---|---|
| 1 | ChronoMind | watchOS | learning_ai_clock |
ios/ChronoMindWatch/ |
50% | 7 files | Missing: WCSession sync, snooze/dismiss actions, haptic cascade, notifications |
| 2 | ChronoMind | macOS | learning_ai_clock |
ios/ChronoMindMac/ |
45% | 5 files | Missing: MenuBarPopover.swift, create-timer UI, live popover, keyboard shortcuts |
| 3 | JarvisJr | watchOS | learning_ai_jarvis_jr |
ios/JarvisJrWatch/ |
25% | 3 files (+2 in Watch dir) | Missing: QuickSessionView, WCSession, complications, voice stub, haptics |
| 4 | JarvisJr | macOS | learning_ai_jarvis_jr |
ios/JarvisJrMac/ |
40% | 5 files | Missing: MenuBarPopover.swift, text session UI, keyboard shortcut handler |
| 5 | PeakPulse | watchOS | learning_ai_peakpulse |
ios/PeakPulseWatch/ |
30% | 3 files | Missing: real sensors (CLLocation, CMAltimeter), HealthKit workout, WCSession, complications |
| 6 | NomGap | watchOS | learning_ai_fastgap |
watch/NomGapWatch/ |
55% | 9 files | Missing: StatsView body, WidgetKit migration, WCSession ↔ Expo bridge verification, notifications |
| 7 | Auth | watchOS | learning_ai_auth_app |
ios/ByteLystAuthWatch/ |
40% | 3 files | Missing: push notification handling, haptic feedback, complication, offline state |
3. ChronoMind watchOS — 50% → 100%
Repo: learning_ai_clock
Directory: ios/ChronoMindWatch/
Shared code: ios/ChronoMind/Shared/ (TimerEngine, Store, Theme, AppGroup, Haptics, Notifications)
What EXISTS (7 files, ~660 lines)
| File | LOC | Status |
|---|---|---|
ChronoMindWatchApp.swift |
16 | Complete |
Views/WatchContentView.swift |
177 | Good — timer list, next-up card, empty state |
Views/WatchQuickTimerView.swift |
56 | Good — 8 preset quick timers |
Views/WatchTimerDetailView.swift |
99 | Good — countdown, urgency badge, pomodoro, cascade progress, snooze info |
WatchTimerStore.swift |
125 | Good — reads from SharedTimerDataManager, quick timer creation, tick, haptic on fire |
Complications/WatchComplications.swift |
243 | Complete — 4 families (circular, rectangular, inline, corner), AppIntentConfiguration, timeline |
ChronoMindWatch.entitlements |
— | Present |
What's MISSING — implement these
3.1 WatchConnectivity (WCSession) for real-time sync
File: WatchSessionManager.swift (~120 lines)
Purpose: Bidirectional WCSession so the iPhone app can push timer updates in real-time,
and the Watch can send commands back (snooze, dismiss, pause, resume).
Implementation:
- WCSessionDelegate with activationDidCompleteWith, didReceiveMessage, didReceiveApplicationContext
- On receive: decode [TimerSnapshot] and update WatchTimerStore
- sendCommand(_ command: WatchTimerCommand) method for: snooze, dismiss, pause, resume, complete
- WatchTimerCommand enum: snooze(id, minutes), dismiss(id), pause(id), resume(id), complete(id)
- Reachability tracking with fallback to App Group polling
- Wire into WatchTimerStore.init() — activate session
3.2 Action buttons on WatchTimerDetailView
File: Update Views/WatchTimerDetailView.swift
Add action buttons at bottom of ScrollView:
- When state == .firing: "Snooze 5m" button + "Dismiss" button
- When state == .active: "Pause" button
- When state == .paused: "Resume" button
- When state == .snoozed: "Snooze again" + "Dismiss"
- All actions go through WatchSessionManager.sendCommand()
- Haptic feedback (WKInterfaceDevice.current().play()) on each action
3.3 Haptic cascade warnings
File: Update WatchTimerStore.swift
In tick(), when a warning fires (nextWarningTime reached):
- Play .notification haptic
- If urgency == .critical: play 3x haptic sequence (notification + 0.3s delay + notification)
- Update the timer's firedWarnings count
- Schedule local notification via UNUserNotificationCenter
3.4 Local notifications on Watch
File: WatchNotificationHandler.swift (~50 lines)
- UNUserNotificationCenter.requestAuthorization on app launch
- Schedule notification when timer is about to fire (from WatchTimerStore)
- Custom notification categories with "Snooze" and "Dismiss" actions
- UNNotificationCategoryIdentifier: "CHRONOMIND_TIMER_FIRED"
3.5 Routines view (optional, stretch)
File: Views/WatchRoutineView.swift (~80 lines)
- Read active routine from SharedTimerDataManager
- Show current step name + progress
- "Next Step" button to advance
Estimated new code: ~350 lines across 3 new files + 2 updated files
4. ChronoMind macOS — 45% → 100%
Repo: learning_ai_clock
Directory: ios/ChronoMindMac/
Shared code: ios/ChronoMind/Shared/ (same as iOS — TimerEngine functions are pure Swift)
What EXISTS (5 files, ~520 lines)
| File | LOC | Status |
|---|---|---|
ChronoMindMacApp.swift |
40 | Complete — MenuBarExtra with timer label |
MacTimerStore.swift |
181 | Complete — CRUD, tick, notifications, App Group persistence. Uses Shared/ engine functions directly |
Views/MacSettingsView.swift |
101 | Complete — General/Data/About tabs |
ChronoMindMac.entitlements |
— | Present |
What's MISSING — implement these
4.1 MenuBarPopover.swift (~200 lines)
File: Views/MenuBarPopover.swift
This is the main UI that appears when clicking the menu bar icon.
Layout:
- Header: "ChronoMind" + gear icon (opens Settings)
- If no timers: empty state with "Create Timer" button
- Next-up card: large countdown + urgency color + label + target time
- Timer list: compact rows for remaining active timers
- Quick actions row: preset buttons (5m, 10m, 25m Pomodoro, Custom)
- "Custom Timer" button opens CreateTimerSheet
Each timer row has:
- Urgency dot + label + countdown
- Right-click context menu: Pause, Resume, Snooze 5m, Dismiss, Delete
Footer:
- "x active timers" label + "Quit" button
4.2 CreateTimerSheet.swift (~120 lines)
File: Views/CreateTimerSheet.swift
Sheet presented from MenuBarPopover:
- TextField for timer label
- Picker: Countdown / Alarm / Pomodoro
- If Countdown: duration picker (hours/minutes stepper)
- If Alarm: DatePicker for target time
- If Pomodoro: rounds stepper (default 4) + work/break duration
- Urgency picker (5 levels)
- Cascade preset picker
- "Create" button → store.addCountdown/addAlarm
4.3 Keyboard shortcut handler (~40 lines)
File: Update ChronoMindMacApp.swift
Add .keyboardShortcut modifiers or NSEvent.addLocalMonitorForEvents:
- ⌘N: Create new timer (open CreateTimerSheet)
- ⌘,: Open Settings
- Space: Pause/resume next firing timer
- ⌘Q: Quit app
Add .commands { } modifier to the App scene.
4.4 MenuBarState.swift (~30 lines)
File: MenuBarState.swift
@MainActor ObservableObject:
- @Published var showCreateSheet = false
- @Published var showTimerDetail: String? = nil // timer ID
4.5 Launch at Login
File: Update Views/MacSettingsView.swift
Wire the "Launch at Login" toggle to SMAppService.mainApp:
- import ServiceManagement
- SMAppService.mainApp.register() / unregister()
Estimated new code: ~390 lines across 3 new files + 2 updated files
5. JarvisJr watchOS — 25% → 100%
Repo: learning_ai_jarvis_jr
Directory: ios/JarvisJrWatch/
Shared code: ios/JarvisJr/Shared/ (Models, Store, Engine, Voice, Theme, AppGroup)
What EXISTS (5 files, ~230 lines)
| File | LOC | Status |
|---|---|---|
JarvisJrWatchApp.swift |
13 | Minimal — no store injection |
WatchContentView.swift |
85 | Basic — agent list from SharedAgentData, streak banner, links to QuickSessionView |
QuickSessionView.swift |
exists (in JarvisJrWatch/) | Referenced but need to verify |
ComplicationProvider.swift |
exists (in JarvisJrWatch/) | Referenced in AGENTS.md |
WatchTimerStore.swift |
— | NOT present |
What's MISSING — implement these
5.1 WatchAgentStore.swift (~80 lines)
@MainActor ObservableObject:
- @Published var agents: [WatchAgent] — read from SharedAgentData (App Group)
- @Published var streak: Int
- @Published var activeSession: WatchSession?
- struct WatchAgent: id, name, role, accentColor, sessionLength
- struct WatchSession: agentId, startedAt, messages: [(role, text)]
- loadFromSharedData() — decode from App Group UserDefaults
- Inject into WatchApp via @StateObject
5.2 QuickSessionView.swift (~150 lines)
If this file doesn't exist or is a stub, implement:
- Agent name + role header
- "Start Session" button (text-based on Watch, voice is stretch)
- Once started:
- Scrollable message list (alternating user/agent bubbles)
- Text input via dictation (TextField with .watchDictation modifier or voice button)
- "End Session" button
- On end: summary card (duration, message count)
- Send session data back to iPhone via WCSession
5.3 WatchSessionManager.swift (~100 lines)
WCSessionDelegate:
- Receive agent list updates from iPhone
- Receive streak updates
- Send session transcripts back to iPhone
- Reachability handling
5.4 Complications (~120 lines)
File: Complications/WatchComplications.swift
WidgetKit complications (same pattern as ChronoMind):
- AppIntentTimelineProvider reading from SharedAgentData
- Circular: streak count or agent initial
- Rectangular: "Coach — 5-day streak" or "JarvisJr — Ready"
- Inline: "🔥 5 streak" or agent name
- Corner: streak number with "JarvisJr" label
- 4 supported families: accessoryCircular, accessoryRectangular, accessoryInline, accessoryCorner
5.5 Update WatchApp entry point
Update JarvisJrWatchApp.swift:
- @StateObject var agentStore = WatchAgentStore()
- @StateObject var sessionManager = WatchSessionManager()
- Inject both as environmentObjects
- Activate WCSession in init()
Estimated new code: ~450 lines across 4 new files + 2 updated files
6. JarvisJr macOS — 40% → 100%
Repo: learning_ai_jarvis_jr
Directory: ios/JarvisJrMac/
Shared code: ios/JarvisJr/Shared/
What EXISTS (5 files, ~340 lines)
| File | LOC | Status |
|---|---|---|
JarvisJrMacApp.swift |
39 | Complete — MenuBarExtra + Settings |
MacAgentStore.swift |
119 | Good — agent CRUD, persistence, notifications, 6 default templates |
MacMenuBarState.swift |
33 | Basic — isExpanded, showQuickSession, selectedAgentId |
Views/MacSettingsView.swift |
111 | Complete — General/Agents/About tabs |
What's MISSING — implement these
6.1 MenuBarPopover.swift (~180 lines)
Main popover content (referenced in JarvisJrMacApp but not implemented):
- Agent card grid (2 columns): avatar circle + name + role
- Click agent → startQuickSession
- Streak banner at top
- "Talk to [Agent]" button for default agent
- If activeSession: show session view (text chat)
Agent card:
- Colored circle with initial
- Name (body bold)
- Role (caption)
- Total sessions badge (caption2)
Session view (inline, replaces agent grid):
- Agent name header
- Message scroll view
- TextField for text input
- End session button
6.2 MacTextSessionView.swift (~120 lines)
Text-based coaching session in the popover:
- Agent name + role header
- Scrollable message list (bubble style)
- TextField + Send button at bottom
- "End Session" button in toolbar
- On end: increment totalSessions, save via MacAgentStore
- Timer showing session duration
6.3 Keyboard shortcut
Update JarvisJrMacApp.swift:
- ⌥⇧J: Start session with default agent (already mentioned in settings)
- Register as NSEvent.addGlobalMonitorForEvents
- ⌘,: Settings
Estimated new code: ~300 lines across 2 new files + 1 updated file
7. PeakPulse watchOS — 30% → 100%
Repo: learning_ai_peakpulse
Directory: ios/PeakPulseWatch/
Shared code: ios/PeakPulse/ (Models, Services, Theme, Utils)
What EXISTS (3 files, ~160 lines)
| File | LOC | Status |
|---|---|---|
PeakPulseWatchApp.swift |
11 | Minimal stub |
WatchContentView.swift |
145 | Functional — activity picker (hike/ski), tracking view with stats grid, start/stop. Uses local Timer (NOT real sensors) |
PeakPulseWatch.entitlements |
— | Present |
What's MISSING — implement these
7.1 Real sensor integration
File: WatchLocationService.swift (~100 lines)
CLLocationManager on watchOS:
- requestWhenInUseAuthorization()
- Start updating location (desiredAccuracy: .bestForNavigation)
- Publish: currentSpeed, currentElevation (altitude), totalDistance, elevationGain
- Calculate distance between consecutive CLLocations
- Track elevation gain (only count positive deltas)
- Wire into WatchContentView replacing the mock values
7.2 HealthKit workout session
File: WatchWorkoutManager.swift (~120 lines)
HKWorkoutSession + HKLiveWorkoutBuilder:
- Start workout session when tracking begins
- Activity type: .hiking or .downhillSkiing based on selection
- Collect: heart rate, active energy, distance
- End workout and save to HealthKit when tracking stops
- Request HealthKit authorization for: .heartRate, .activeEnergyBurned, .distanceWalkingRunning
7.3 WatchConnectivity sync
File: WatchSessionManager.swift (~80 lines)
- Send completed session data to iPhone via WCSession
- Receive recent session summaries from iPhone for display
- Transfer TrackPoint arrays via transferUserInfo (large data)
7.4 WidgetKit complications
File: Complications/WatchComplications.swift (~120 lines)
Same pattern as ChronoMind:
- Circular: elevation or distance icon
- Rectangular: "Last hike: 5.2km, +450m" or "Tracking: 45min"
- Inline: "🥾 5.2km +450m"
- Corner: distance with "PeakPulse" label
- Read from App Group UserDefaults (last session summary)
7.5 Session summary view
File: Views/WatchSessionSummaryView.swift (~80 lines)
Shown after stopping a session:
- Duration
- Distance
- Elevation gain/loss
- Average speed
- Max speed
- Activity type icon
- "Save" button (saves to HealthKit + syncs to iPhone)
- "Discard" button
7.6 Recent sessions list
File: Views/WatchSessionListView.swift (~60 lines)
Tab or navigation destination:
- List of recent sessions from App Group
- Each row: date, activity type, distance, duration
- Tap for detail view (read-only summary)
7.7 Update WatchApp and ContentView
- Add @StateObject for WatchLocationService, WatchWorkoutManager
- Add tab navigation: Tracking | Sessions | (complications handled separately)
- Wire real sensor data into tracking stats grid
- Add heart rate display if workout session active
Estimated new code: ~560 lines across 5 new files + 2 updated files
8. NomGap watchOS — 55% → 100%
Repo: learning_ai_fastgap
Directory: watch/NomGapWatch/
Shared code: watch/Shared/ (FastingState, ColorExtension)
What EXISTS (9 files, ~770 lines) — MOST COMPLETE
| File | LOC | Status |
|---|---|---|
NomGapWatchApp.swift |
20 | Complete |
ContentView.swift |
17 | Complete — TabView with 3 pages |
FastingTimerView.swift |
324 | Excellent — timer ring, stage badge, Digital Crown, haptic cascade, controls, next stage countdown |
HydrationView.swift |
71 | Complete — water tracking with progress bar |
StatsView.swift |
exists | Need to verify content |
WatchSessionManager.swift |
134 | Good — WCSession delegate, command queue, offline queue |
ComplicationProvider.swift |
204 | Complete — CLKComplicationDataSource with 9 families |
Shared/FastingState.swift |
exists | Shared model |
Shared/ColorExtension.swift |
exists | Color init(hex:) |
What's MISSING — implement these
8.1 StatsView implementation
File: Update StatsView.swift (~80 lines)
Read from App Group (NomGapAppGroup):
- Current streak (days)
- Total fasts completed
- Average fast duration
- Longest fast
- Total fasting hours
Layout:
- Streak flame at top
- Stats in a 2-column grid (similar to PeakPulse)
- "Last 7 days" mini bar chart (optional)
8.2 Migrate complications from ClockKit → WidgetKit
File: Update or replace ComplicationProvider.swift (~150 lines)
CLKComplicationDataSource is deprecated since watchOS 9.
Migrate to WidgetKit:
- AppIntentTimelineProvider (same pattern as ChronoMind)
- 4 accessory families: circular, rectangular, inline, corner
- Read from NomGapAppGroup.loadState()
- Show: stage emoji, elapsed time, progress gauge
- Keep backward compat: leave CLK version but add WidgetKit version
8.3 Local notifications
File: WatchNotificationHandler.swift (~50 lines)
- Stage transition notifications (entering ketosis, autophagy)
- Hydration reminders (every 2 hours during active fast)
- UNUserNotificationCenter on watchOS
8.4 WCSession ↔ Expo React Native bridge verification
The WatchSessionManager sends/receives via WCSession, but the iPhone side is React Native (Expo).
Verify that the Expo plugin (plugins/withWatchApp.js) properly:
1. Registers the WCSession delegate on the RN side
2. Handles incoming WatchCommand messages
3. Sends FastingState updates to the watch via updateApplicationContext
If the bridge doesn't exist, create:
- ios-extensions/NomGapWatchBridge/WatchBridge.swift — native module
- Expo config plugin to register the bridge
8.5 Fix print() usage
WatchSessionManager.swift line 43 uses print() — replace with os.Logger
Estimated new code: ~280 lines across 2 new files + 3 updated files
9. ByteLyst Auth watchOS — 40% → 100%
Repo: learning_ai_auth_app
Directory: ios/ByteLystAuthWatch/
What EXISTS (3 files, ~215 lines) — surprisingly functional
| File | LOC | Status |
|---|---|---|
ByteLystAuthWatchApp.swift |
17 | Complete — uses os.Logger |
WatchContentView.swift |
196 | Good — polls /auth/mfa/push/pending, approve/deny UI, loading/error/empty states, 10s auto-refresh |
Info.plist |
— | Present |
What's MISSING — implement these
9.1 Push notification handling
File: WatchNotificationHandler.swift (~60 lines)
UNUserNotificationCenter for push MFA:
- Register for remote notifications in WatchApp init
- Handle incoming push with approval request data
- Create actionable notification with "Approve" and "Deny" buttons
- UNNotificationCategory: "MFA_APPROVAL"
- On action: call respond(to:approved:) API
9.2 Haptic feedback
File: Update WatchContentView.swift
Add haptics for:
- New approval received: .notification
- Approve action: .success
- Deny action: .failure
- Error state: .retry
9.3 WidgetKit complication
File: Complications/AuthComplication.swift (~100 lines)
AppIntentTimelineProvider:
- Circular: shield icon (green if no pending, orange if pending)
- Rectangular: "ByteLyst Auth — 2 pending" or "All clear"
- Inline: "🛡️ 2 pending" or "🛡️ All clear"
- Corner: pending count with shield label
- Read pending count from App Group (set by main app or watch polling)
- Timeline refresh: every 5 minutes, or .after(nextPoll)
9.4 Offline/no-auth state improvement
File: Update WatchContentView.swift
When no token is available:
- Show QR code prompt: "Scan from iPhone to pair"
- Or: instruction to open ByteLyst Auth on iPhone
- Add a "Refresh" button that re-checks App Group keychain
When offline:
- Show last-known pending count from App Group cache
- Badge: "Last updated: X minutes ago"
9.5 WCSession for token sync
File: WatchSessionManager.swift (~60 lines)
The main app should push the access token to the Watch via WCSession.
On the Watch side:
- Receive token via didReceiveApplicationContext
- Store in shared Keychain (App Group)
- Trigger approval refresh
Estimated new code: ~220 lines across 3 new files + 1 updated file
10. Cross-Cutting Tasks
10.1 XcodeGen project.yml updates
For repos that use XcodeGen (project.yml), ensure the companion targets are properly declared:
- ChronoMind:
ios/project.yml— verify ChronoMindWatch and ChronoMindMac targets include all new files - JarvisJr:
ios/project.yml— verify JarvisJrWatch and JarvisJrMac targets - PeakPulse:
ios/project.yml— verify PeakPulseWatch target
Each watchOS target needs:
targets:
ProductWatch:
type: application
platform: watchOS
deploymentTarget: '10.0'
sources:
- path: ProductWatch
- path: Product/Shared # shared code from iOS app
settings:
INFOPLIST_FILE: ProductWatch/Info.plist
PRODUCT_BUNDLE_IDENTIFIER: com.saravana.product.watchkitapp
WATCHOS_DEPLOYMENT_TARGET: '10.0'
dependencies:
- target: ProductWidgets # if WidgetKit complications
10.2 App Group entitlements
Verify every companion target has the correct App Group in its entitlements:
| Product | App Group |
|---|---|
| ChronoMind | group.com.chronomind.shared |
| JarvisJr | group.com.saravana.jarvisjr |
| PeakPulse | group.com.saravana.peakpulse |
| NomGap | (defined in Expo app.json or withWatchApp plugin) |
| Auth | group.com.bytelyst.auth |
10.3 Shared helper: formatTime() global function
Several watch views reference a formatTime(_:) free function. Ensure it exists in a shared utility file accessible to the watchOS target:
func formatTime(_ date: Date) -> String {
let formatter = DateFormatter()
formatter.timeStyle = .short
return formatter.string(from: date)
}
10.4 Theme color access from companion targets
Each companion target needs access to the product's theme colors. Options:
- Add the theme file (e.g.,
ChronoMindTheme.swift) to the Watch target's sources in project.yml - Or create a lightweight
WatchTheme.swiftwith just the needed colors
11. Acceptance Criteria
For EACH companion target, the implementation is 100% when:
watchOS targets
- App launches in watchOS Simulator without crashes
- Main content view shows real data from App Group
- At least one bidirectional action works (Watch → iPhone command)
- WCSession activates and receives data
- WidgetKit complications render in all 4 accessory families
- Haptic feedback fires on key actions
- Local notifications schedule correctly
- No
print()statements — allos.Logger - All colors from theme — no hardcoded hex in views
- Builds clean with
xcodebuild -scheme ProductWatch -destination 'platform=watchOS Simulator,name=Apple Watch Series 10 (46mm)' build
macOS targets
- App launches as menu bar app
- Menu bar icon shows relevant live data (countdown / agent name)
- Popover opens with correct content
- Create/interact actions work (create timer / start session)
- Settings window opens with ⌘,
- Launch at Login toggle works via SMAppService
- App Group syncs data from iOS app
- Notifications fire correctly
- No
print()statements - Builds clean with
xcodebuild -scheme ProductMac -destination 'platform=macOS' CODE_SIGNING_ALLOWED=NO build
12. Build Verification Commands
Run after implementing each target:
# ── ChronoMind ─────────────────────────────────────
cd /path/to/learning_ai_clock/ios
# watchOS
xcodebuild -scheme ChronoMindWatch \
-destination 'platform=watchOS Simulator,name=Apple Watch Series 10 (46mm)' \
build
# macOS
xcodebuild -scheme ChronoMindMac \
-destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO build
# ── JarvisJr ──────────────────────────────────────
cd /path/to/learning_ai_jarvis_jr/ios
xcodebuild -scheme JarvisJrWatch \
-destination 'platform=watchOS Simulator,name=Apple Watch Series 10 (46mm)' \
build
xcodebuild -scheme JarvisJrMac \
-destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO build
# ── PeakPulse ─────────────────────────────────────
cd /path/to/learning_ai_peakpulse/ios
xcodebuild -scheme PeakPulseWatch \
-destination 'platform=watchOS Simulator,name=Apple Watch Series 10 (46mm)' \
build
# ── NomGap ────────────────────────────────────────
# NomGap watchOS requires an Xcode project (may need manual setup
# since the main app is React Native/Expo)
cd /path/to/learning_ai_fastgap
# Verify via Expo custom dev client or standalone Xcode project
# ── ByteLyst Auth ─────────────────────────────────
cd /path/to/learning_ai_auth_app/ios
xcodebuild -scheme ByteLystAuthWatch \
-destination 'platform=watchOS Simulator,name=Apple Watch Series 10 (46mm)' \
build
Summary: Total New Code Estimate
| Target | New Files | New LOC | Updated Files |
|---|---|---|---|
| ChronoMind watchOS | 3 | ~350 | 2 |
| ChronoMind macOS | 3 | ~390 | 2 |
| JarvisJr watchOS | 4 | ~450 | 2 |
| JarvisJr macOS | 2 | ~300 | 1 |
| PeakPulse watchOS | 5 | ~560 | 2 |
| NomGap watchOS | 2 | ~280 | 3 |
| Auth watchOS | 3 | ~220 | 1 |
| TOTAL | 22 | ~2,550 | 13 |
Recommended execution order: ChronoMind (watch + mac) → PeakPulse (watch) → JarvisJr (watch + mac) → NomGap (watch) → Auth (watch)
This order prioritizes the most feature-complete iOS apps first, ensuring the Shared/ code they depend on is already proven.