💙 Support SparkyFitness
If SparkyFitness has been useful to you & your family, please consider sponsoring on GitHub or supporting via Ko-fi. Your support helps cover recurring costs such as AI coding tools, development infrastructure, and Apple & Google Developer memberships to keep the project actively maintained.
Planning to buy an Android phone for app development and testing 📱 Your sponsorship helps cover the cost. Thank you for your support! 🙏
Important
💾 Upgrade Notice: Always remember to back up your database and environment before upgrading to a new version.
👍 Community Prioritization: Want to see a specific feature or fix in the next release? Add a 👍 reaction to open Issues to help us prioritize what to build next!
🚀 Key Highlights
- Adaptive calorie budgets: Dynamic Goal and Percentage Earn-Back no longer add activity calories or optional BMR credit to an Adaptive target a second time. Remaining calories may be lower after upgrading because these duplicate credits are removed. Recorded activity remains visible, and Manual targets retain their existing earn-back behavior.
- Use Testflight app for the latest App as the live PROD is usually outdated.
What's Changed
Features
- feat(mobile): daily mood check-in reminders by @Bubbles840 in #3028
- feat(symptoms): track impact over time next to severity by @DUC750 in #3031
- feat(mobile): time-weighted daily heart rate average on Health Connect by @DUC750 in #3034
- feat(mobile): read mindfulness sessions from Health Connect by @DUC750 in #3042
- feat(server): compare any two tracked metrics (statistics + endpoint) by @Bubbles840 in #3058
- feat(calories): separate daily activity from adaptive baseline by @Bl4nk24 in #3061
- feat(mobile): show running cadence and stride for watch runs, the run summary and trends by @Jerrys-modz in #3069
- feat(mobile): add photo attachments to Sparky chat by @romanchenkop in #3068
- feat(routes): generate routes with a routing provider by @Jerrys-modz in #3071
- feat(mobile): add Wear OS companion app and Android watch-connectivity bridge by @vcdx71 in #3052
- feat(mobile): compare any two tracked metrics (Compare screen) by @Bubbles840 in #3076
- feat(foods): support arithmetic in quantity inputs by @Bl4nk24 in #2935
- feat(exercise): store workout effort from the watch and Apple Health by @Jerrys-modz in #3065
- feat(mobile): route editor with satellite view, draggable points and per-stretch snapping by @Jerrys-modz in #3077
- feat: set your own heart rate zones (max and resting heart rate, zone method) by @Jerrys-modz in #3078
- feat(symptoms): show and record the effect on the day over an episode on the web by @DUC750 in #3073
- feat: compare an outcome before and since a habit started by @Bubbles840 in #3084
- feat(mobile): read mindfulness sessions from Apple Health by @Jerrys-modz in #3091
- feat(watch): follow a saved route on Apple Watch by @Jerrys-modz in #3090
- feat(ai): ask Compare questions from the chat and MCP (sparky_compare_metrics) by @Bubbles840 in #3089
- feat(goals): support weekly weight change targets by @Bl4nk24 in #3067
- feat(healthkit): attach overnight HRV and resting heart rate to sleep by @Jerrys-modz in #3100
- feat(mobile): keep sets when replacing an exercise of the same type by @Jerrys-modz in #3102
- feat(mobile): medication adherence overview, month calendar and dose log by @Jerrys-modz in #3103
- feat(run-program): realign the rest of a plan to finish on the goal day by @Jerrys-modz in #3109
- feat(ai): use user language preference for food photo estimates by @Bl4nk24 in #3115
- feat(frontend): Compare tab on the Reports page (day and week) by @Bubbles840 in #3108
- feat(exercise): stop a synced workout counting twice in the calorie balance by @Jerrys-modz in #3114
- feat(mobile): run splits table with pace bars, elevation and heart rate by @Jerrys-modz in #3135
- feat(routes): route options and route style by @Jerrys-modz in #3141
- feat(goals): keep past days' calorie targets when calorie settings change by @SisyphusMD in #3106
- feat(heart-rate): detailed heart rate reports with a range navigator by @CodeWithCJ in #3143
- feat: weekly running distance goal and race countdown by @Jerrys-modz in #3144
- feat(frontend): ask since-a-habit-started questions on the Compare tab by @Bubbles840 in #3116
- feat(frontend): enter sodium as grams of salt in the food editor by @surfnterd in #3150
- feat: guided running fitness tests that set training paces, outdoors or on a treadmill by @Jerrys-modz in #3154
- feat: fitness, fatigue and form curve, readiness score, estimated VO2 max and running power (server, mobile and web) by @Jerrys-modz in #3155
- feat(garmin): re-pull the last few days in the scheduled sync by @surfnterd in #3148
- feat(server): admin setting to turn off the GitHub release check by @surfnterd in #3149
- chore(deps): update dependencies within the release-age window by @CodeWithCJ in #3177
- feat(food): compare alternative barcode sources by @Bl4nk24 in #3126
- feat(watch): record a jump rope session from the wrist by @trash-panda-v91-beta in #3127
- feat: add Intervals.icu provider for activities and wellness by @cailloux in #3139
- feat(exercise): plate calculator with a plate inventory in Equipment by @Jerrys-modz in #3186
- feat(mobile): add a custom measurement category manager by @Jerrys-modz in #3194
- feat(watch): easier-to-read watch app, Medications with Skip, Up Next and exercise swap by @zelphir in #3191
- feat(mobile): add an opt-in guided check-in by @zeusal in #3197
- feat(mobile): pin the set to do now, quick exercise swap, and photo zoom by @zelphir in #3192
- feat(server): make the graceful shutdown timeout configurable by @SisyphusMD in #3204
- feat(running): Zone 2 base program with heart rate guidance by @Jerrys-modz in #3201
- feat(mobile): pick any start date and time when logging a symptom epi… by @Jerrys-modz in #3222
- fix(chat): split the usage footer into cached, uncached and output tokens by @SisyphusMD in #3225
- feat(mobile): make the Android widgets resizable by @zeusal in #3228
- feat(mobile): copy meals to family diaries by @Bl4nk24 in #3218
- feat(helm): mount existing claims for the server's uploads and backup volumes by @SisyphusMD in #3233
- feat(mobile): restyle the + menu as Quick Actions and let users arrange it by @Jerrys-modz in #3242
- feat(mobile): refresh What's New with running, routes, check-in, strength and heart rate cards by @Jerrys-modz in #3247
- feat(wearos): add Nutrition, Sleep Health, Medications, and Exercise tiles by @vcdx71 in #3250
Fixes
- fix(mobile): request new HealthKit types on iOS without a permission version bump by @SisyphusMD in #2998
- ci: run the real-database test files one at a time by @SisyphusMD in #3032
- test(mobile): align test expectations with updated Polish and Spanish translations by @nalvazhvu in #3053
- fix(server): detect a vanished holder of the startup schema lock by @SisyphusMD in #3035
- test(server): keep chat, food photo and check-in tool tests off the real database by @SisyphusMD in #3038
- fix(db): finish renaming duplicate custom categories before the uniqu… by @Jerrys-modz in #3044
- fix(health-data): keep fields the user edited when a workout is re-sent by @DUC750 in #3030
- fix(mobile): keep the granted metrics when Enable All misses a permission by @Bubbles840 in #3059
- test(server): avoid timeout from dynamic auth import by @mulatta in #3066
- fix(cycle): constrain cycle deletion flow clearing to bleed period by @nalvazhvu in #3057
- fix(training-programs): make program copy match the workouts by @Jerrys-modz in #3070
- fix(frontend): send stored values for workout fields the user left alone by @DUC750 in #3072
- fix(providers): validate Open Food Facts base URL and improve outbound request handling by @CodeWithCJ in #3079
- fix(external-providers): align select policy actor check with family delegation by @nalvazhvu in #3081
- fix(oura): normalize redirect URI and support client callback forwarding by @nalvazhvu in #3085
- fix(server): record each migration in the transaction that applied it by @SisyphusMD in #3086
- fix(ai): optimize Ollama vision with think:false, 1280px image cap, and gemma4 default by @nalvazhvu in #3087
- fix(ai): cap local vision images at 1280px and update Ollama default to gemma4 by @nalvazhvu in #3088
- fix(server): hide database and system error text in 5xx responses by @SisyphusMD in #3093
- fix(server): survive a database connection dropped while in use by @SisyphusMD in #3094
- fix(docker): run the server under tini so stopping the container shuts it down gracefully by @SisyphusMD in #3095
- fix(server): stop overlapping edits of a grouped workout from deadlocking by @SisyphusMD in #3096
- fix(mobile): complete background Health Connect recovery by @Bl4nk24 in #3098
- fix(mobile): initialize Health Connect in background sync and handle dead client reconnect for aggregations by @nalvazhvu in #3092
- fix(docker): bump Node.js base images to 24.22.1 for CVE-2026-111497 by @nalvazhvu in #3111
- fix(mobile): word a yes/no Compare difference as against the other days by @Bubbles840 in #3107
- fix(exercise): re-estimate calories when sets are added to an entry by @Jerrys-modz in #3105
- fix(garmin): parse strength workout sets and telemetry from FIT imports by @nalvazhvu in #3112
- fix(garmin): prevent coordinate shifts in activity metrics and filter GPS outliers by @nalvazhvu in #3117
- fix(caffeine): add relative dates to recent doses and clarify chart transitions by @nalvazhvu in #3122
- fix(frontend): restore YAZIO repository link in provider create and edit forms by @nalvazhvu in #3123
- fix(garmin): keep a pending MFA sign-in in a sealed token (a restart or second replica lost it, and a retried code was resent) by @SisyphusMD in #3119
- fix(server): retry database connections through a restart (every request in the window answered 500) by @SisyphusMD in #3124
- fix(server): hide database errors in hand-written 500 responses (33 route bodies still sent error.message) by @SisyphusMD in #3125
- fix(garmin): treat Garmin's -1 step weight as no weight in workout definitions by @RealHirn in #3129
- fix(server): wait for the database at startup (a server started before PostgreSQL exited and restarted with back-off) by @SisyphusMD in #3133
- fix(server): answer 503, not 401, when the session can't be checked (a database restart signed mobile users out) by @SisyphusMD in #3138
- fix(calories): show progress against the activity-adjusted food budget by @Bl4nk24 in #3140
- fix(exercise-stats): report personal record and course times for the exact distance by @Jerrys-modz in #3145
- fix(exercise): count the applied calories in chatbot totals and Reports by @Jerrys-modz in #3147
- fix(goals): pick each day's calorie rules by date, not by the database's text sort by @SisyphusMD in #3156
- fix(health-data): one Active Calories entry per user and day under concurrent imports by @SisyphusMD in #3158
- fix(measurements): one Daily or Hourly custom measurement reading per slot under overlapping writes by @SisyphusMD in #3164
- fix(heart-rate): show the person's own zones in the Heart Rate reports by @Jerrys-modz in #3165
- fix(symptoms): keep every severity and impact reading of overlapping edits (both edits started from the same old timeline) by @SisyphusMD in #3168
- fix(server): let responses finish when the server stops by @SisyphusMD in #3163
- fix(exercise): fill a workout edit's omitted fields from the locked entry (an upload or edit landing mid-edit was overwritten) by @SisyphusMD in #3170
- fix(exercise-entries): answer 404 for an unknown exercise_id (it surfaced as a 500) by @SisyphusMD in #3172
- fix(frontend): truncate long names in medicine cabinet list by @stoamandl in #3183
- fix(mobile): keep progress photo headers below the iOS status bar by @zeusal in #3190
- fix(frontend): prevent layout shift when opening selects and dialogs by @stoamandl in #3195
- fix(mobile): keep form screen headers below the iOS status bar by @SisyphusMD in #3200
- fix(compare): honest since answers for slow-moving outcomes by @Bubbles840 in #3120
- fix(sleep): count a night once when two sources record it by @Bubbles840 in #3180
- fix(goals): apply each weekly goal plan only to its own dates by @SisyphusMD in #3198
- fix: ask for the workout effort permission once by @Jerrys-modz in #3199
- fix(server): finish running jobs and release sync claims on shutdown by @SisyphusMD in #3203
- fix(helm): give the server a startupProbe so a long migration is not restarted by @SisyphusMD in #3206
- fix(auth): reset the mfa-factors limit when its window ends by @SisyphusMD in #3207
- fix(backup): build each backup in a private work directory and publish it whole (a crash or overlapping run left partial archives that retention counted as backups) by @SisyphusMD in #3208
- fix(helm): create the external database Secret from values (the server referenced a Secret the chart never made) by @SisyphusMD in #3209
- fix(server): stop provider syncs that lose their claim or stall by @SisyphusMD in #3213
- fix(mcp): say create_food nutrients are per quantity × unit by @benjamin-m-holden in #3214
- fix(backup): clear day-old .tmp work dirs when a backup starts by @SisyphusMD in #3215
- fix(ai): log the exact external food the lookup returned by @SisyphusMD in #3220
- perf(ai): cut Sparky chat token use by @SisyphusMD in #3224
- fix(watch): stop long exercise names being cut off, and make the larger text setting cover the whole watch by @Jerrys-modz in #3226
- fix(workout): remove exercise-level notes field from preset editor by @CodeWithCJ in #3227
- fix(ai): save foods at the serving the lookup quoted by @SisyphusMD in #3221
- fix(calories): use Garmin and Polar daily totals in Device Projection by @CodeWithCJ in #3231
- fix(watch): honor haptics setting, use GoalPalette macro colors, localize Apple Watch strings by @Jerrys-modz in #3230
- fix: save workout effort with a granted permission, and stop re-asking for routes by @Jerrys-modz in #3235
- fix(server): apply RLS policies at startup only when they changed by @SisyphusMD in #3239
- fix(sleep): keep a nap as its own sleep entry instead of merging it into the night by @CodeWithCJ in #3243
- fix(auth): share IP rate-limit budgets across server instances by @SisyphusMD in #3245
- fix(ai): require energy and all three macros before saving an Open Food Facts food by @SisyphusMD in #3249
Documentation
- docs(readme): add README translations and an inline language bar by @zeusal in #3043
- docs(install): update how long a lost server holds the startup lock by @SisyphusMD in #3097
- docs: document the Apple Watch and Wear OS companion apps by @Jerrys-modz in #3118
- Missing documentation by @lukyjay in #2660
- docs(agents): add issue and enhancement planning skills, shared planning rules, and tool-neutral agent conventions by @CodeWithCJ in #3171
- docs(mobile): add DESIGN.md describing the current mobile design system by @zeusal in #3182
- docs(agent-docs): list only needed changes in PR review reports by @CodeWithCJ in #3212
- docs(mobile): add watch apps section to DESIGN.md by @Jerrys-modz in #3219
- docs: keep limits and job status in the database, not server memory by @SisyphusMD in #3238
Other Changes
- chore(helm): update chart version to v1.9.0 by @github-actions[bot] in #3026
- chore(umbrel): update app package to v1.9.0 by @github-actions[bot] in #3027
- chore(i18n): sync translations from Weblate by @github-actions[bot] in #3051
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3054
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3055
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3062
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3074
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3075
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3080
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3082
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3101
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3146
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3151
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3152
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3153
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3162
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3169
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3173
- chore(nix): update pnpm deps hashes by @github-actions[bot] in #3179
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3193
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3241
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3246
- chore: sync db_schema_backup.sql with migrations by @github-actions[bot] in #3248
- chore(i18n): sync translations from Weblate by @github-actions[bot] in #3251
New Contributors
- @mulatta made their first contribution in #3066
- @surfnterd made their first contribution in #3150
- @trash-panda-v91-beta made their first contribution in #3127
- @cailloux made their first contribution in #3139
- @stoamandl made their first contribution in #3183
- @zelphir made their first contribution in #3191
Full Changelog: v1.9.0...1.10.0