Apple Fitness workout fixer + Strava uploader
Swift 70.9%
Shell 0.5%
Other 28.6%
20 1 0

Clone this repository

https://tangled.org/burrito.space/overrun https://tangled.org/did:plc:7r5c5jhtphcpkg3y55xu2y64/overrun
git@tangled.org:burrito.space/overrun git@tangled.org:did:plc:7r5c5jhtphcpkg3y55xu2y64/overrun

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

Overrun#

An iOS app for trimming and managing HealthKit workouts. Built for the common problem of forgetting to stop recording — leaving you with an 8-hour "run" that wrecks your stats.

Workout list grouped by month      Detail view showing a forgot-to-stop workout

Features#

Workout List#

  • Animated gradient header with icon colors (cyan, lime green, hot pink)
  • Workouts grouped by month/year with section headers
  • Search by activity type name (case-insensitive)
  • Sort by date (default), longest duration, or shortest duration — useful for quickly finding forgot-to-stop workouts or accidental recordings
  • Paginated loading (50 at a time) with infinite scroll
  • Pull-to-refresh and automatic refresh via HealthKit observer (updates when workouts are added or deleted externally)

Guided Trim Flow#

The workout detail view walks you through a step-by-step process:

  1. Trim and save — Activity graph showing heart rate, active energy, or distance over time. Range slider to select the portion to keep, with live-updating start/end times, duration, and activity type picker. Explainer text describes what data is preserved and what is lost.
  2. Upload to Strava (optional) — Upload the trimmed workout directly to Strava via OAuth. Shown after saving, with connect/upload/status inline.
  3. Remove the original — Instructions to delete the original in Apple Fitness (swipe left → "Delete Workout & Data"), with an "Open Fitness" button. If the original was created by Overrun, it is automatically deleted.

Steps 2 and 3 are visible but dimmed before step 1 is complete, so you know the full process before you begin.

Data-Preserving Trim#

When you trim a workout, Overrun creates a new workout and migrates all associated data within the trimmed time range:

  • Heart rate, active/basal energy, distance, step count samples
  • Running dynamics — speed, power, stride length, vertical oscillation, ground contact time
  • VO2 max and physical effort samples
  • Workout effort scores (iOS 18+, user-entered only)
  • Workout routes (GPS/location data)
  • Workout events (laps, segments, etc.)
  • Metadata (indoor/outdoor flag, weather, timezone, METs, etc.)
  • Configuration — activity type, indoor/outdoor location type, swimming config

Strava Integration#

  • OAuth authentication via the Strava app (falls back to Safari if not installed)
  • Direct upload of workouts as TCX files with heart rate and GPS data
  • Upload status tracking with polling (uploading → processing → success)
  • Connect/disconnect from anywhere in the trim flow

Known Limitations#

HealthKit / Apple Platform#

  • Cannot modify workouts in place. HealthKit provides no API to change a workout's start/end dates, samples, or metadata. Trimming must create a new workout and delete the original.
  • Cannot delete workouts from other apps. HealthKit only allows an app to delete objects it created. Workouts from Apple Watch, Fitness+, or other apps must be deleted manually by the user (e.g., swipe left in Apple Fitness and choose "Delete Workout & Data").
  • Estimated workout effort is not copyable. estimatedWorkoutEffortScore is computed by Apple's algorithms and cannot be written by third-party apps. It may or may not be recomputed by the system for the new workout. User-entered effort scores (workoutEffortScore, iOS 18+) are migrated via relateWorkoutEffortSample.
  • Physical effort samples are system-generated. physicalEffort samples are computed by the OS and cannot be created or associated by third-party apps.
  • Activity icons in Apple Fitness are source-dependent. Even though we correctly set locationType (e.g., .indoor) and carry over HKMetadataKeyIndoorWorkout, Apple Fitness may display a generic icon for workouts from third-party sources instead of the specialized icon (e.g., indoor run icon) shown for Apple Watch workouts.
  • Apple Fitness may crash when sharing copied workouts. This is a known Apple bug where Fitness crashes when trying to view interval details or share workouts created by third-party apps via HKWorkoutBuilder. This is not specific to Overrun.
  • No deep link to specific workouts. Apple provides no URL scheme to open a specific workout in Fitness or Health. activitytoday:// opens Fitness to the activity rings view only.
  • Splits are not shown for third-party workouts. Since iOS 14, Apple Fitness only displays per-kilometer/mile splits for workouts created by Apple's native Workout app. The underlying distance samples exist in HealthKit, but Fitness will not render the splits table for workouts from any third-party source. There is no API or workaround.
  • Running dynamics may not be present. Running speed, power, stride length, vertical oscillation, and ground contact time are only recorded by Apple Watch Series 6+ / Ultra with watchOS 9+. Older devices or non-running workouts will not have these samples.

Strava#

  • Strava only imports workouts from Apple's native Workout app. Strava checks the sourceRevision bundle identifier on each HealthKit workout and only accepts workouts from Apple's Workout app and Apple Fitness+. Workouts written by any third-party app (including Overrun) are intentionally excluded from Strava's HealthKit import list, regardless of how complete the data is.
  • This is a Strava policy, not a data issue. The workout data we write is fully valid and appears correctly in Apple Health and Apple Fitness.
  • Direct upload works. Overrun bypasses the HealthKit import limitation by uploading directly to Strava's API via OAuth + TCX file upload.

Requirements#

  • iOS 17+
  • Xcode 15+
  • HealthKit entitlement

Building#

Open WorkoutEditor.xcodeproj in Xcode and run on a device or simulator. The app requires HealthKit authorization to read and write workouts and associated samples.

Strava Setup#

  1. Register an API application at strava.com/settings/api
  2. Set the Authorization Callback Domain to localhost
  3. Copy Secrets.xcconfig.template to Secrets.xcconfig and fill in your Client ID and Client Secret
  4. Secrets.xcconfig is gitignored and will not be committed

In debug builds, 200 sample workouts are auto-generated on first launch for testing.

Localization#

The app is set up for internationalization using Xcode String Catalogs (.xcstrings). All user-facing strings in SwiftUI views are automatically extracted by Xcode.

Contributing a Translation#

  1. Open the project in Xcode
  2. Go to Project Settings → Info → Localizations and add your language
  3. Xcode will create localized entries in Localizable.xcstrings and InfoPlist.xcstrings
  4. Open Localizable.xcstrings in Xcode's String Catalog editor and translate each string
  5. InfoPlist.xcstrings contains the app name and HealthKit usage descriptions — translate those too
  6. Activity type names (Running, Cycling, etc.) and all step/button labels are included in the catalog

Files#

  • WorkoutEditor/Localizable.xcstrings — all app UI strings
  • WorkoutEditor/InfoPlist.xcstrings — Info.plist strings (app name, permission descriptions)