···11+# CLAUDE.md
22+33+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
44+55+## Project Overview
66+77+Overrun is an iOS app (Swift/SwiftUI, iOS 17+) for trimming HealthKit workouts that weren't stopped in time. It creates a new trimmed workout preserving all associated data (samples, routes, events, metadata, effort scores), optionally uploads to Strava, then guides the user to delete the original.
88+99+## Build & Run
1010+1111+```bash
1212+# Build for simulator
1313+xcodebuild -scheme "WorkoutEditor" -destination "platform=iOS Simulator,name=iPhone 17 Pro" build
1414+1515+# Build, install, and launch on simulator
1616+./run.sh
1717+```
1818+1919+Open `WorkoutEditor.xcodeproj` in Xcode for full IDE support. No package managers (SPM/CocoaPods) — all frameworks are system-provided.
2020+2121+## Strava Setup
2222+2323+Copy `Secrets.xcconfig.template` to `Secrets.xcconfig` and fill in Strava API credentials. The xcconfig is gitignored.
2424+2525+## Architecture
2626+2727+All source lives in `WorkoutEditor/`. There is no test target.
2828+2929+### Key Files
3030+3131+- **WorkoutEditorApp.swift** — App entry point, handles `overrun://` deep links for Strava OAuth callback
3232+- **HealthKitManager.swift** — `@Observable` singleton managing all HealthKit reads/writes: workout loading (paginated, 50 at a time), sample fetching, workout creation with data migration, deletion, and live observation via `HKObserverQuery`
3333+- **StravaManager.swift** — `@Observable` singleton for Strava OAuth (tokens in Keychain), TCX file generation, multipart upload with status polling
3434+- **WorkoutListView.swift** — Main list with search, sort (date/longest/shortest), month/year grouping, infinite scroll, pull-to-refresh
3535+- **WorkoutEditView.swift** — 3-step guided trim flow: (1) trim via range slider + activity graph, (2) optional Strava upload, (3) remove original
3636+- **ActivityGraphView.swift** — SwiftUI Charts area+line graph for heart rate/energy/distance with dimmed trim regions
3737+- **RangeSliderView.swift** — Dual-handle range slider component
3838+3939+### Data Flow
4040+4141+1. App requests HealthKit authorization → loads workouts → starts observer for external changes
4242+2. User selects workout → fetches intensity samples (heart rate, energy, distance) for graph
4343+3. User adjusts range slider → saves trimmed copy with migrated samples, routes, events, metadata, activities, and effort scores (iOS 18+)
4444+4. Optionally uploads to Strava via OAuth + TCX
4545+5. User deletes original in Apple Fitness (or auto-deleted if Overrun-created)
4646+4747+### Patterns
4848+4949+- **Logging**: `os.Logger` with subsystem `"com.overrun"`, one category per feature
5050+- **Async**: Modern async/await throughout; `withCheckedThrowingContinuation` bridges legacy `HKWorkoutRouteQuery`
5151+- **Debug mode**: `#if DEBUG` auto-generates 200 sample workouts on first launch
5252+- **Localization**: Xcode String Catalogs (`.xcstrings`) — all UI strings are localization-ready
5353+5454+### HealthKit Constraints
5555+5656+- Cannot modify workouts in place — must create new + delete original
5757+- Can only delete workouts the app created — others require manual deletion
5858+- Estimated effort scores are system-computed and not copyable; only user-entered effort (iOS 18+) can be migrated