A static WidgetKit accessory widget (launcher only — no data sharing,
App Group, or entitlements). Tapping any accessory widget opens its
containing app, so this is enough to place a Workouts button on the
watch face. Supports the circular, corner, inline, and rectangular
accessory families.
New 'Workouts Watch Widget' app-extension target embedded in the watch
app via project.yml.
The propped-up iPhone now runs the real ExerciseProgressView for a live
watch workout instead of a read-only mirror, and the live-run channel is
symmetric — either device can drive the flow and the other follows.
Each page transition is classified human / auto / remote: only human
transitions (swipe, Start, One More, swipe-back reset) are broadcast and
recorded by the actor; auto-advances (rest / timed-work countdown) record
locally but aren't sent, since both devices reach them independently off
the shared wall-clock anchors; an applied remote frame jumps the page
without re-recording or re-broadcasting. That rule is also what stops an
echo loop.
- PhoneConnectivityBridge gains sendLiveProgress/sendLiveEnded (the
missing phone->watch direction); WatchConnectivityBridge receives
frames into an observable liveIncoming via a new didReceiveMessage
route. Both share one increasing per-run version sequence so the
stale-frame guard works across the two devices' counters.
- Both ExerciseProgressViews gain an incomingFrame input + applyIncoming
(syncing setCount for a remote One More); the iPhone one gains the
liveSnapshot/broadcast machinery the watch already had.
- New LiveRunCoverView wraps the real driver for the cover (resolves the
workout, persists via SyncEngine, wires the live channel + close);
ContentView presents it; LiveProgressMirrorView is removed.
Claude-Session: https://claude.ai/code/session_01SCv7zvGFcKy47KSTnTLxRe
Move the idle-timer disable out of ExerciseView/ExerciseProgressView and
up to the app scene, re-asserting it whenever the scene becomes active
(iOS clears the flag on background). A propped-up phone now stays lit for
the entire workout, not just while an exercise is open.
Claude-Session: https://claude.ai/code/session_01SCv7zvGFcKy47KSTnTLxRe
Add an ephemeral live-run presence channel (separate from the durable
iCloud progress sync) so a propped-up iPhone can mirror the Watch's
Ready → work/rest → Finish flow in real time as the user swipes.
Watch drives, phone mirrors (read-only), so there's no echo loop:
- Watch's ExerciseProgressView broadcasts a LiveProgress frame on every
phase transition (and an ended signal on leave) via sendMessage,
reachable-only — throwaway presence, never written to iCloud.
- Timers ride as wall-clock anchors (Date kept native in the WC dict to
preserve sub-second precision), so both devices count independently
off shared start times and stay in lockstep without streaming ticks.
- Phone holds a transient LiveRunState; ContentView auto-presents a
read-only LiveProgressMirrorView full-screen cover while a run is live.
Claude-Session: https://claude.ai/code/session_01SCv7zvGFcKy47KSTnTLxRe
Publish an exclusive-edit lock (editingWorkoutID / editingSplitID) in the
phone→watch application context. While the phone has a workout's exercise
(ExerciseView) or a split (SplitDetailView) open in an editor, the watch pops
out of that run, blocks re-entry, and shows it as "Editing on iPhone" — so the
two devices never drive the same run at once and the watch can't clobber the
phone's edit with a stale optimistic write. The lock clears when the editor
closes; absent keys in the latest-wins context mean "not editing".
Claude-Session: https://claude.ai/code/session_01SCv7zvGFcKy47KSTnTLxRe
Populate the previously-empty AccentColor asset (iOS + watch) with the
logo purple — a deep shade in light mode, brightened for dark mode and
the watch's black background. The exercise Done check now uses that
accent color and the in-progress indicator reads as a neutral gray, on
both iPhone and Apple Watch.
Derive entries from the git log, rewritten for end users: one
blank-line-separated paragraph each (no dash markers, which the
in-app Apple inline-Markdown renderer doesn't style), keeping only
user-significant changes, splitting multi-change commits and
collapsing duplicates. Extends coverage back to the January 2026
pre-2.0 history so the CloudKit -> iCloud Drive arc is visible.
Claude-Session: https://claude.ai/code/session_01A9CfUa4E9Zd5swfoNsYPs7
Tapping an exercise now opens ExerciseProgressView -- the watch's Ready -> work/rest -> Finish flow on iPhone, with rep sets counting up, timed sets and rests counting down and auto-advancing, a work-set dot row (dash on the active set, gap widening at the current rest), and capsule Start/Done/One More buttons. The detail/edit screen moves behind a trailing Edit swipe (leading swipe still completes). Swiping back to the Ready page resets the run.
- iPhone: disable the idle timer while the exercise detail screen is open,
so the display no longer sleeps mid-set.
- Watch: the work/rest timers counted on a run-loop Timer that watchOS
throttles in the Always-On (wrist-down) state, so they froze. Anchor both
to a wall-clock Date rendered with SwiftUI's self-updating timer text;
rest haptics + auto-advance now derive from the end time so they catch up
after a stall instead of stalling.
Set TARGETED_DEVICE_FAMILY to 1 for the iOS target — it was universal (1,2) but
isn't an iPad experience, which forced an iPad screenshot requirement at
submission. The Apple Watch app is a separate target (family 4) and is unaffected.
Removes the iPad screenshot set from the listing metadata.
Claude-Session: https://claude.ai/code/session_018gg69MaUetDNzWzBXisfMV
DEBUG-only screenshot support (seeded sample data via ScreenshotSeed, per-screen
launch args, screenshot roots for both apps) so iPhone + Apple Watch App Store
shots can be captured deterministically from the simulator — all excluded from
release builds. Also seed ExerciseView's set-grid progress in init so it renders
correctly on the first frame. Adds Scripts/metadata/ as the listing source of
truth (copy, URLs, review notes, and the captured screenshots).
Claude-Session: https://claude.ai/code/session_018gg69MaUetDNzWzBXisfMV
ExerciseView now observes workout.updatedAt and pulls the latest doc/progress
from the cache, mirroring WorkoutLogListView. A set completed on the watch now
advances the iPhone set grid in real time instead of only on re-entry.
Claude-Session: https://claude.ai/code/session_018gg69MaUetDNzWzBXisfMV
ingestFromWatch now upserts the SwiftData cache directly after writing the file,
instead of relying on the NSMetadataQuery observer — a same-process file
overwrite doesn't reliably emit a modified event, so watch progress never reached
open iPhone screens. iCloud Drive stays the source of truth (file written first);
the observer re-applies idempotently if it fires.
Claude-Session: https://claude.ai/code/session_018gg69MaUetDNzWzBXisfMV
Completing a work phase advances the set count to the iPhone, and a finished
set is never un-counted — a transient paged-TabView snap to page 0 can no longer
overwrite progress with 0. Reopening an exercise now jumps to the first
unfinished set's work page (re-asserted after first layout) instead of starting
back at set 1.
Claude-Session: https://claude.ai/code/session_018gg69MaUetDNzWzBXisfMV
- Redesign the watch app into an active-workout runner: a root gate shows the
in-progress workout's exercises or prompts to start one on iPhone, and each
exercise runs as a horizontally-paged HIIT cycle (count-up work, count-down
rest with final-three-second haptics + auto-advance, One More / Done on the
last set). Replaces the old history list.
- Add a configurable rest-between-sets duration in iPhone Settings (default 45s),
synced to the watch over WatchConnectivity.
- Launch the watch app into the session when a workout starts on the phone via
HealthKit (startWatchApp); the watch runs an HKWorkoutSession for foreground
runtime and ends it when the workout finishes. Adds the HealthKit entitlement +
Health usage strings on both targets and WKBackgroundModes on the watch.
Claude-Session: https://claude.ai/code/session_018gg69MaUetDNzWzBXisfMV
Replace the bodyweight-catalog-derived seed (hardcoded 3x10, weight 0) with an
explicit curated machine-based routine: Upper Body, Core, and Lower Body at 4x10
with starting weights taken from real workout logs. Decoupled from the shared
exercise catalog YAML (still used by the exercise picker).
A row tap pushed twice: a value-based navigationDestination(for: String.self)
collided with the row's NavigationLink(value:), surfacing a duplicate split list
over the hidden exercise detail. Rows now use a destination-based NavigationLink,
leaving navigationDestination(item:) as the view's only destination.
Replace the teal circular mark with a full-bleed purple gradient and a
larger tilted dumbbell, applied across all iOS sizes and the Watch icon.
Icons are alpha-free RGB for App Store compliance.
Replace Core Data + NSPersistentCloudKitContainer + App-Group store +
WatchConnectivity dictionary sync with the QuickRabbit iCloud-documents
architecture:
- iCloud Drive JSON documents are the sole source of truth (one file per
aggregate: Splits/<ULID>.json, Workouts/YYYY/MM/<ULID>.json), with a
rebuildable SwiftData cache populated only by an NSMetadataQuery observer
and a connect-time reconcile. Soft-delete tombstones; hard iCloud gate.
- Shared model layer (ULID, Codable *Documents + stateless mappers, @Model
cache entities, SwiftData container) compiled into both targets.
- New iPhone<->Watch bridge over WatchConnectivity keyed by ULIDs; the phone
is the sole writer of iCloud Drive, the watch round-trips documents.
- AppServices DI + iCloud-required root gate; Swift 6 strict concurrency.
- Starter splits generated on demand from the bundled YAML catalogs.
- Migrate to XcodeGen (project.yml), iOS 26 / watchOS 26; CloudDocuments
entitlement (drop CloudKit/App Group/aps-environment).
- Duration stored as Int seconds (was a Date epoch hack); fix workout
end-on-create, undismissable delete dialog, toolbar-hiding nav stacks,
and the Settings placeholder.
- Add README/CHANGELOG/LICENSE, .gitignore, refreshed REQUIREMENTS, and the
Scripts/ TestFlight pipeline (release.sh + ASC API scripts).
MARKETING_VERSION 2.0.