Craft can record that a workout happened. It cannot run one.
CraftHealth.swift:280 builds an HKWorkout from a start, an end, an energy total and a distance the caller supplies, and saves it. Android does the same at CraftHealthConnect.kt.template:165 with ExerciseSessionRecord(startTime = …) into insertRecords. That is the right shape for importing a workout that happened somewhere else, and it is what an app syncing from Strava or TrainingPeaks needs.
It is the wrong shape for a workout the app is in the middle of. For that, iOS has HKWorkoutSession + HKLiveWorkoutBuilder, and Health Connect has a foreground exercise session. Neither exists here:
HKWorkoutSession 1 hit, a location-type lookup table in CraftScheduledWorkouts.swift
HKLiveWorkoutBuilder 0What an app loses without one
An app that wants to run a workout has to keep a timer alive and poll health data. On iOS that means:
- the OS can suspend it mid-workout. A workout session is the documented way to stay running;
enableBackgroundTasksand background audio are workarounds that do not survive a long session with the screen off. - heart rate arrives at whatever cadence a background read gives. A live builder streams it.
craft.heartRatealready hasstartRecording/readRecordingfor a Bluetooth strap, which is excellent — but it covers a strap the app connected to itself, not the watch on the person's wrist, and it does not make the OS treat the app as mid-workout. - nothing contributes to the Activity rings while it is happening. Rings are the measure most people actually check, and a workout saved afterwards does not move them the same way.
- the saved
HKWorkoutis assembled from numbers the app guessed rather than from samples the system collected during the session. - an Apple Watch app has nothing to attach to. Craft already ships
CraftWatchApp.swift.templateandWCSession, so the watch half exists — but a watch workout app without a session underneath is a stopwatch with a nice face.
Why it matters beyond one app
This is the capability that separates "an app you look at while training" from "the thing recording your training". Everything else Craft gives a fitness app — HealthKit reads, Bluetooth heart-rate straps, scheduled workouts, Live Activities, background audio for coaching — assumes the data arrives from somewhere else. A live session is how an app becomes a first-class source.
It also quietly gates Live Activities for workouts, which is one of the obvious uses of the Live Activity support already here: an activity whose app gets suspended mid-session stops updating, and the session is what prevents that.
Rough shape
craft.workout.start({ activityType, location })→ a session id, with the OS informed a workout is in progress- live samples surfaced as events, the way
craftHealthHeartRatealready is pause/resume/end, withendsaving theHKWorkoutbuilt from collected samples rather than from caller-supplied totals- Android: the equivalent foreground exercise session, ending in the
ExerciseSessionRecordthe insert path already writes - the existing post-hoc
saveWorkoutstays exactly as it is — importing a finished workout and running a live one are different jobs and both are needed
Raised from HQ.training, a training platform built on Craft: it syncs from Oura, WHOOP, Garmin, Fitbit, Apple Health and TrainingPeaks, charts PMC and reads Bluetooth straps, and still cannot be the app you press start on.