macOS running coach: training plans, desktop widgets, Garmin/Strava sync and an AI coach powered by Claude Code, Codex or a local model
Swift
0
8 commits
updated Oct 5, 2026
A macOS app for planning and analysing your running training — with desktop widgets, Garmin/Strava sync and an AI coach that runs on your own machine through Claude Code, Codex or a local model (LM Studio).
The app speaks English and German. It follows your system language: German systems get German, every other language gets English. The coach answers in the same language.
Everything stays on your Mac: your training data lives in a folder you choose, logins stay with Garmin, Strava and the CLIs you already use. Pace Lab has no server, no account and no telemetry.
brew install python) and a Garmin
Connect accountgit clone git@github.com:themb94/pace-lab.git
cd pace-lab
cp Config/Signing.local.example.xcconfig Config/Signing.local.xcconfig
Edit Config/Signing.local.xcconfig — your Team ID and a bundle ID of your
own (this file is ignored by git):
DEVELOPMENT_TEAM = ABCDE12345
PACELAB_BUNDLE_ID = com.yourname.pacelab
Open PaceLab.xcodeproj, select the PaceLab scheme and run. To install,
build the Release configuration and copy Pace Lab.app to /Applications.
Pace Lab opens a setup window (also under Pace Lab → Setup …):
~/Documents/Pace Lab (or a folder you pick)
with an example plan, empty run log, a coach README and a git repository.README.md —
or just tell the coach and it fills them in.claude auth login, codex login).~/.garminconnect).Pace Lab.app ──reads/writes──▶ training folder (plan.json, analysis.json, completed.json, README.md, .git)
│ ▲
├── Coach: runs `claude -p` / `codex exec` / `lms chat` in that folder
├── Garmin: talks MCP (stdio) to garmin-mcp/server.py (read-only unless you approve an upload)
└── Strava: `claude -p` with only the two Strava read tools; the raw data is taken from the stream
README.md in your training folder — that's where
the rules, schemas and your athlete profile live. Adapt it to your liking.plan.json
(garmin-mcp/garmin_workouts.py), so what you see is what lands on the watch.PaceLab/ App (SwiftUI): Coach/, Planning/, Sync/, Project/ (git, JSON, MCP client), Setup/, Views/
PaceLabWidgets/ Widgets (WidgetKit)
Shared/ Models and calculations used by app and widgets, and the translations (Localizable.xcstrings)
Template/ Contents of a new training folder, per language: Template/en, Template/de (bundled into the app)
garmin-mcp/ Garmin MCP server (Python, bundled into the app)
Config/ Info.plists, entitlements, signing (Signing.xcconfig + your local override)
scripts/ Release build: signed, notarized DMG (release.sh)
The Debug build can render screenshots of all views without clicking:
"Pace Lab" -projectPath <copy-of-your-folder> -debugSnapshots <dir> -debugQuit YES.
Texts are written in English in the source and translated through a
String Catalog (Shared/Localizable.xcstrings,
shared by the app and the widgets). German is included. To add a language, add
its translations to the catalog in Xcode and create a matching folder
Template/<language> (coach README and example plan; the app falls back to
Template/en). The language the coach replies in follows the app language.
Your own data stays as you wrote it: plan texts, run analyses and the coach's notes in your training folder are not translated.
scripts/release.sh builds a DMG for distribution: signed with a Developer ID
Application certificate, notarized by Apple and stapled, so Gatekeeper opens it
without warnings on other Macs. It needs a paid Apple Developer Program
membership. Team and bundle ID come from Config/Signing.local.xcconfig, the
Apple credentials from your keychain — nothing personal lives in the repository.
xcrun notarytool store-credentials pacelab-notary --apple-id <you@example.com> --team-id <TEAMID>scripts/release.sh. The DMG lands in build/release/.
--no-notarize is a dry run, --upload attaches the DMG to the GitHub
release v<version>.Apps that were signed and notarized stay valid after the certificate expires. Only new releases need a renewed certificate.
Pace Lab is a personal training tool, not medical advice — talk to a doctor
about health questions. The Garmin integration uses the unofficial
garminconnect library
and may break when Garmin changes its login. Not affiliated with Garmin,
Strava, Anthropic or OpenAI.
macOS running coach: training plans, desktop widgets, Garmin/Strava sync and an AI coach powered by Claude Code, Codex or a local model
Swift
0
8 commits
updated Oct 5, 2026
A macOS app for planning and analysing your running training — with desktop widgets, Garmin/Strava sync and an AI coach that runs on your own machine through Claude Code, Codex or a local model (LM Studio).
The app speaks English and German. It follows your system language: German systems get German, every other language gets English. The coach answers in the same language.
Everything stays on your Mac: your training data lives in a folder you choose, logins stay with Garmin, Strava and the CLIs you already use. Pace Lab has no server, no account and no telemetry.
brew install python) and a Garmin
Connect accountgit clone git@github.com:themb94/pace-lab.git
cd pace-lab
cp Config/Signing.local.example.xcconfig Config/Signing.local.xcconfig
Edit Config/Signing.local.xcconfig — your Team ID and a bundle ID of your
own (this file is ignored by git):
DEVELOPMENT_TEAM = ABCDE12345
PACELAB_BUNDLE_ID = com.yourname.pacelab
Open PaceLab.xcodeproj, select the PaceLab scheme and run. To install,
build the Release configuration and copy Pace Lab.app to /Applications.
Pace Lab opens a setup window (also under Pace Lab → Setup …):
~/Documents/Pace Lab (or a folder you pick)
with an example plan, empty run log, a coach README and a git repository.README.md —
or just tell the coach and it fills them in.claude auth login, codex login).~/.garminconnect).Pace Lab.app ──reads/writes──▶ training folder (plan.json, analysis.json, completed.json, README.md, .git)
│ ▲
├── Coach: runs `claude -p` / `codex exec` / `lms chat` in that folder
├── Garmin: talks MCP (stdio) to garmin-mcp/server.py (read-only unless you approve an upload)
└── Strava: `claude -p` with only the two Strava read tools; the raw data is taken from the stream
README.md in your training folder — that's where
the rules, schemas and your athlete profile live. Adapt it to your liking.plan.json
(garmin-mcp/garmin_workouts.py), so what you see is what lands on the watch.PaceLab/ App (SwiftUI): Coach/, Planning/, Sync/, Project/ (git, JSON, MCP client), Setup/, Views/
PaceLabWidgets/ Widgets (WidgetKit)
Shared/ Models and calculations used by app and widgets, and the translations (Localizable.xcstrings)
Template/ Contents of a new training folder, per language: Template/en, Template/de (bundled into the app)
garmin-mcp/ Garmin MCP server (Python, bundled into the app)
Config/ Info.plists, entitlements, signing (Signing.xcconfig + your local override)
scripts/ Release build: signed, notarized DMG (release.sh)
The Debug build can render screenshots of all views without clicking:
"Pace Lab" -projectPath <copy-of-your-folder> -debugSnapshots <dir> -debugQuit YES.
Texts are written in English in the source and translated through a
String Catalog (Shared/Localizable.xcstrings,
shared by the app and the widgets). German is included. To add a language, add
its translations to the catalog in Xcode and create a matching folder
Template/<language> (coach README and example plan; the app falls back to
Template/en). The language the coach replies in follows the app language.
Your own data stays as you wrote it: plan texts, run analyses and the coach's notes in your training folder are not translated.
scripts/release.sh builds a DMG for distribution: signed with a Developer ID
Application certificate, notarized by Apple and stapled, so Gatekeeper opens it
without warnings on other Macs. It needs a paid Apple Developer Program
membership. Team and bundle ID come from Config/Signing.local.xcconfig, the
Apple credentials from your keychain — nothing personal lives in the repository.
xcrun notarytool store-credentials pacelab-notary --apple-id <you@example.com> --team-id <TEAMID>scripts/release.sh. The DMG lands in build/release/.
--no-notarize is a dry run, --upload attaches the DMG to the GitHub
release v<version>.Apps that were signed and notarized stay valid after the certificate expires. Only new releases need a renewed certificate.
Pace Lab is a personal training tool, not medical advice — talk to a doctor
about health questions. The Garmin integration uses the unofficial
garminconnect library
and may break when Garmin changes its login. Not affiliated with Garmin,
Strava, Anthropic or OpenAI.