Cycling Coach:本地运行的 AI 骑行训练应用,接入 Garmin 与 Anthropic API
rudolphsam-GIt/Cycling-Coach
Cycling Coach 是一款在本地电脑运行的骑行训练应用,可从 Garmin 或 Strava 拉取骑行数据,跟踪体能(CTL)与疲劳(ATL),并内置可对话的 AI 教练,训练历史全部保存在本地数据库、不上传云端。
Cycling Coach is a training app that runs on your own computer. It pulls in your rides from Garmin (or Strava), tracks your fitness and fatigue, and keeps a training calendar.
It also has an AI coach you can chat with. The coach sees your real training numbers, so it can plan workouts, review rides and help you prepare for races.
Your training history stays in a local database on your machine. Nothing is stored in the cloud by this app.
New to structured training?
You do not need to know any of the jargon to start. Here are the five ideas the app is built on, in plain words.
- FTP is the most power you can hold for about an hour. It is your yardstick. If you do not know it, the app starts with an estimate and can suggest a better one from your best 20 minutes, or plan a guided test.
- Zones are effort bands based on your FTP. Zone 2 is steady, comfortable riding and should make up most of your time. Higher zones are harder and make you faster, but only a little of your riding should be there.
- TSS (training stress score) is one number for how big a ride was, counting both how long and how hard. One hour at your FTP is 100. It lets you add up a week and see how much you are asking of your body.
- Fitness and fatigue. Fitness (CTL) is your training load averaged over about six weeks. It rises when you train consistently. Fatigue (ATL) is the same over about a week, so it jumps after hard days.
- Form is fitness minus fatigue. Slightly negative is normal and productive while you train. You want to be positive when you race, and very negative for weeks is a warning.
How the app helps you learn.
- Help icons and tooltips. Look for the small question mark icons and the hover tips next to numbers and charts. Each one says what it is, why it matters, and what your own number means right now.
- Your coach explains the why. Every workout the coach plans says what it is for in terms of your goals, what to focus on, and how it should feel (effort out of 10 and a talk test). Every block explains what each phase is building. On the calendar, hover or open a workout to read it. The same text goes to your Garmin if you send the workout.
- Getting started checklist. On the Today page, a short list of the steps to set up, which ticks itself off from your data.
- Build my first block. One button that asks the coach for a gentle four week starting block. Setup asks for your goals in your own words (with examples to get you thinking), how many hours a week and how many days a week you can train, and the plan is built to fit them. You can change all three later in Settings.
- Help finding your FTP, with no pressure. Not knowing your FTP is completely normal, so setup gives you three choices. 1) I know it, and you type it in. 2) I don't know it, but I'm happy to do a test. 3) I don't know it and would rather not test, so please estimate it for me. For the last two, three short questions pick a typical starting range for someone like you: what kind of rider you are (new to cycling, ride without a plan, followed a training plan, or race), how active you are, and your gender (Woman, Man, Non-binary or Prefer not to say), because typical power per kilo is lower for women than for men (about 15 percent at the beginner level, which is in line with the published Allen and Coggan tables). It is used only to pick typical power ranges. Non-binary and Prefer not to say use an average of the two, and anyone can choose either reference table on the Progress power profile. Gender and age sit on one line. Your weight is asked for anyway. Age is optional. Power drops by roughly 1 percent a year after about 35, so a 55 year old starts about 15 percent lower than someone in their thirties, and a younger rider under 18 a little lower too. Age also sets your starting threshold heart rate. Only your birth year is stored, so your age stays current. Activity is spelled out so nobody has to guess (for example moderately active is 3 to 4 sessions and about 3 to 5 hours a week with some harder efforts). A newcomer might see 85 to 125 watts, and the app starts you in the middle. If you choose the test, your first training block includes it, described for newer riders as a steady pace with no pass or fail. If you choose the estimate, no test is scheduled and the estimate is refined from your rides. Either way, once rides are in, the Today page and Settings offer 95% of your best 20 minutes, and you can add the test to your plan whenever you like. The card on Today only appears when your best 20 minutes would raise your FTP, and it has three buttons: use the suggestion, plan a test, or Not now, which hides it for 14 days. Enter it myself opens a small box to type your own number. Settings always shows the suggestion, including when it is lower than your current FTP, with an explanation.
- Pounds or kilograms, miles or kilometers. A lb and kg switch is in setup and Settings, and every page that takes a weight (including Strength) uses it. A mi and km switch sets distance everywhere: setup, Settings, and the filter bar on the Progress page. Choosing miles also shows climbing in feet and speed in mph, and applies to the calendar hover, ride tables, the ride analysis, the Progress tiles and charts, race distances and the pacing planner. Both choices are remembered, and your coach is told so it speaks in the same units.
What you need
- A Mac or Linux computer.
- Python 3.12. You do not need to install it yourself, because
setup.shinstalls it for you using a tool called uv. It does not touch the Python that came with your computer. - An Anthropic API key. This is what powers the coach. See "Getting an Anthropic API key" below.
- A Garmin Connect account if you want rides and recovery data to sync automatically. This is optional and you connect it after the app is running.
Setup
-
Open a terminal and go to the project folder.
-
Run the setup script. It needs an internet connection and takes a minute or two.
bash setup.sh -
Open the new file called
.envin a text editor. Find the line that starts withANTHROPIC_API_KEY=and paste your key after the equals sign, replacing the placeholder text. Save the file. -
Start the app.
bash start.sh -
Your browser should open on its own. If it does not, open the address the terminal prints, which is normally http://localhost:8501.
The app opens as soon as the Anthropic key is in place. Garmin and Strava are connected afterward from the Settings page. The Strava lines in .env are optional and only matter if you want to use Strava. The Garmin email and password lines in .env are also optional. If you fill them in, Settings pre fills the Garmin sign in form for you.
To stop the app, press Control and C in the terminal. Next time, you only need bash start.sh.
Getting an Anthropic API key
The coach talks to Anthropic's API directly using your own key. It does not use a Claude subscription, so a Claude.ai plan will not work here and API use is billed to your key.
- Go to https://console.anthropic.com and create an account or sign in.
- Add a payment method or credit to the account if the console asks for one.
- Open the API Keys section and create a new key.
- Copy the key right away, because the console will not show it again. Paste it into
.envas described above.
You pay for what you use, based on how much text goes back and forth. Short questions cost little. Long conversations, screenshots, and building a multi week plan cost more, because the coach reads a lot of your training data each time. Check the pricing page in the console for current rates, and consider setting a monthly spend limit there so you never get a surprise. To keep costs down, short routine jobs (the ride review and turning a workout into Garmin steps) run on a cheaper model, and the weekly check in uses medium effort. Planning, plan edits and chat use the strongest model. Anything you do not use the coach for (the calendar, charts, strength logging, .fit export) costs nothing.
Connecting Garmin
You do this once, from the Settings page, after the app is running.
- Open Settings and choose the Connections tab.
- Under Garmin, enter your Garmin Connect email and password and press Connect Garmin.
- If your Garmin account uses two step verification, Garmin sends you a code by email or text. Enter it and press Verify. If the code expires, press Cancel and start again.
- The app pulls your last 90 days of rides and recovery data.
After that, new rides and recovery data sync on their own whenever you open the app and it has been a few hours since the last sync. You can also press "Sync Garmin now" in Settings.
What syncs from Garmin is your cycling activities (duration, distance, elevation, heart rate and power) plus sleep, heart rate variability, resting heart rate, readiness and body battery. Not every watch records all of these, and anything missing is simply skipped.
Your password is only used to sign in. After that the app keeps sign in tokens in a folder called .cycling_coach_garmin in your home folder, and it does not need your password again. Pressing Disconnect Garmin in Settings deletes the token file.
If connecting from the app does not work, you can do the same thing from the terminal. From the project folder run:
venv/bin/python scripts/garmin_setup.py
It asks for your email, password and verification code, saves the tokens in the same place, and pulls 90 days of history.
If you do not use Garmin, you can connect Strava instead on the same Connections tab (it needs the Strava keys in .env), or import .fit and .csv files by hand from the "Import .fit or .csv files by hand" section under Garmin.
First run
The first time you open the app after setup, a short welcome form asks about you.
- Your name.
- Your main goals. You can pick more than one.
- Your training experience.
- How many hours a week you can train.
- Your weight.
- Your FTP and threshold heart rate, if you know them. If you do not, the app estimates a starting point from your experience level and refines it as you train.
- Optionally, a race you are training for.
You can change all of this later in Settings under Profile. It is worth setting your real FTP there as soon as you know it, because training stress scores and zones are based on it.
A guide to each page
Today
Your daily screen. It shows today's planned workout, last night's recovery from Garmin (if your watch has not synced to Garmin Connect for more than a day, the card shows the date of the last data and tells you to open the Garmin Connect app, instead of looking like the connection is broken), and a quick check in where you rate how your legs and energy feel. Below that are your fitness, fatigue and form numbers, your coach's review of your latest ride, and a summary of planned versus actual training stress for the week. Further down are your recent rides, with Analyze this ride and a See all rides button that opens the Rides tab on Progress. If Garmin is connected, Sync now at the top pulls new rides and recovery straight away and shows when the last sync ran. On Saturday to Monday a card offers the weekly check in and opens it on the Plan page in one click. The full fitness chart and zones live on Progress.
Fitness, fatigue and form are calculated the way TrainingPeaks does it. Fitness (CTL) is a 42 day exponentially weighted average of daily training stress. Fatigue (ATL) is the same with a 7 day window. Form is yesterday's fitness minus yesterday's fatigue. Positive form means you are fresh and a very negative form means you are carrying a lot of fatigue.
Plan
The Plan page has three tabs.
Calendar. A month grid of everything planned and everything you did. Hover over a day to see details, drag an upcoming workout to another day, and click a workout to open it and edit it. Under the grid, a Plan impact panel shows how the plan changes your fitness, fatigue and form. See "Using the calendar" below.
Coach. Chat with your AI coach. It can propose single workouts or a whole block of weeks, including strength sessions, and plan a multi month program such as the off season, which you review, download as a PDF and then add to your calendar. It also holds your coach memory and the weekly check in, which sits open at the top from Saturday to Monday until you run it. See "Chatting with the coach" below.
Manage. Lists of this week's workouts and everything upcoming. From here you can send a whole week to Garmin or download a whole week as .fit files. Quick Generate is also here. It builds a training block toward a race from your current fitness and a target peak fitness, without any conversation. It adds workouts straight to your plan, and you can edit or remove them afterward.
Progress
Charts and your ride list for any date range, in the spirit of the TrainingPeaks dashboard. Pick a range at the top (7 days up to a year, all time, or custom dates), and optionally search or filter rides. Summary tiles show rides, time, distance, climbing, training stress, work, average intensity factor and average efficiency factor, each compared with the period of the same length just before. Below that are five tabs.
- Load. The performance chart (fitness, fatigue, form and daily training stress), weekly volume as training stress, hours, distance or climbing, and planned versus done per week.
- Rides. Search and filter your rides. Type words from a ride name (every word has to match, in any order), and use More filters for ride type (road, indoor, gravel, mountain), training stress, intensity factor, moving time, distance, and only rides with power or heart rate. Select a row to open the ride, press Analyze this ride for the full analysis, or download the list as a CSV file. Clear resets everything except the date range.
- Power. Your peak power curve (best 5 seconds up to 2 hours) against the period before or your all time best, a table of key durations in watts and W/kg, power and intensity per ride, efficiency factor over time, FTP history and time in zones.
- History. Fitness history tables like the ones in TrainingPeaks, one for peak power and one for peak heart rate. Rows are the current week and the three before it, the current month and the twelve before it, and an All time row. Columns are moving time, distance (switch between km and mi), training stress, work in kJ, and your best 5 seconds, 1, 5, 20 and 60 minutes. The week and month still in progress are in grey. Below them is your power profile, your best power per kilo at those durations placed on the Allen and Coggan categories from Untrained up to World class, for the selected dates or all time, on the men's or women's chart.
- Recovery. HRV, resting heart rate, sleep and readiness from Garmin, with form behind them so you can read recovery against load.
The search and filters change the tiles and the ride charts. Fitness, fatigue and form always count every ride, since all of it is load. The page only loads when you open it, and each tab only draws when you select it.
Peak power comes from Garmin's ride summaries. Peak heart rate is worked out from each ride's file, which the app downloads from Garmin, with stops cut out the way TrainingPeaks does it. New rides get both when they sync. For older rides, open Settings, Connections, and use Load peak power and heart rate history. It fills in the last year for rides already in the app, adds no rides, and takes a minute or two the first time. .fit files you import by hand get both too. Rides that only came from Strava have neither.
Zooming charts. On any chart over time, drag across the dates you want to look at and the chart zooms to them. Only the dates zoom, so the vertical scale stays the same. Press Reset zoom above the chart, or double click the chart, to see the full range again.
Strength
Gym plans for cyclists, in three phases (off season and base, build, and race season maintenance). Pick a phase to see the sessions and exercises, then log a session you completed with the weights you used.
If your coach plans a strength session for you in the chat, it shows up at the top as "Planned by your coach". Open it, enter the duration and the weights you lifted, and save. Logging it counts the session toward your progress and marks it done on the calendar.
The Strength Progress chart at the bottom shows the weight you lifted over time for each exercise you have logged weights for.
Races
Your race calendar and race tools. It has four tabs.
- Race Day Plan. The coach builds a day by day taper, race morning routine, pacing targets and fueling plan for a race you pick.
- Calendar. Add races, either by picking one from the OBRA schedule (Oregon Bicycle Racing Association) or by entering your own, and log results afterward. Races show up on the Plan calendar too.
- Taper. A taper planner that can add taper workouts to your plan.
- Pacing. A pacing and nutrition calculator for a course you describe.
Competitors
Scouting for races on the OBRA calendar. You load a field of riders from an OBRA event (or paste names), and the app looks up their public race results. It then writes a tactics brief that points to the specific results behind each claim. It is built around OBRA, so it is most useful if you race in that region.
Settings
Three tabs.
- Profile. Your goals, FTP, threshold heart rate, weight and starting fitness.
- Connections. Connect and sync Garmin and Strava, import
.fitor.csvfiles by hand, and load peak power and heart rate history from Garmin. - Data tools. Recalculate training stress for every ride (this also runs on its own when you save a new FTP or threshold heart rate) and remove duplicate rides that came in from both Garmin and Strava.
Using the calendar
The Calendar tab on the Plan page shows one month at a time. Use the arrows to change months.
What the colors mean
| Marker | Meaning |
|---|---|
| Planned | A workout is planned for today or a future day. |
| Done | A past planned workout and you rode that day. |
| Short of plan | You rode, but your actual training stress was under 70 percent of what was planned. |
| Missed | A past planned workout and no ride that day. |
| Unplanned ride | You rode on a day with nothing planned. |
Strength sessions and races also get their own markers on the day they happen. Today has an outline around it. Days with nothing planned and no ride are left plain.
Looking at a day. On a computer, hover over a day to see what was planned or done. This includes the workout name and description, and for a ride the duration, distance, power and training stress. On a phone or tablet, tap the day. If you would rather not use the grid, there is also a date picker with Previous, Next and Today buttons right under it.
Moving a workout. Drag an upcoming workout (or planned strength session) from one day to another. It moves right away and a bar under the calendar offers Undo. Workouts planned for today or later can be dragged to today or later. A workout you skipped (its day passed and it was not marked done) can be moved too. Drag it to a day that has not happened yet, or click it and pick any date, such as the day you really rode it, then edit it and mark it done. Workouts marked done stay where they are until you undo that. If the workout was already sent to Garmin, the old Garmin copy is removed and the workout shows as needing a send again, so send it for the new day. Dragging does not work on a touch screen. Tap the workout instead and change its date in the window that opens.
Opening a workout. Click a workout on the grid, or use Edit in the Manage tab, to open it in a window. Change the name, type, date, planned training stress or description, then save. Before you save, the window shows what the change would do to your fitness, fatigue and form, and flags problems such as back to back hard days or a big jump in weekly training stress. You can also mark the workout done, remove it, send it to Garmin or download it as a .fit file from there.
Analyzing a ride you have done. Click a ride you did (the green entries on past days) and a window opens with that ride. At the top are the numbers (time, distance, climbing, TSS, average and normalized power, intensity, variability, heart rate, work and efficiency) and a note on pacing, which compares your power to heart rate ratio in the first and second half of a long ride. Below are tabs. Timeline charts power, heart rate, speed, cadence and elevation, with smoothing you can choose and drag to zoom. The top and bottom of the chart are marked in miles or kilometers (the bottom also shows the clock time), so you can see where on the road each effort happened, and the marks re-scale as you zoom in. Zones and efforts shows your time in each power and heart rate zone and lists the hard stretches. Power curve compares this ride's best power with your best ever. Plan shows what was planned that day next to what you rode, with the purpose and how it should feel. Coach reads the ride against your plan and recovery. The charts need second by second data, which the app fetches from Garmin or Strava the first time you open a ride (or reads from a .fit file you imported) and keeps, so each ride is only fetched once. Speed is included, as average and maximum speed in the numbers and as its own row on the timeline. Zoom in on part of the ride. Drag across the timeline and the popup zooms to that section and locks it in for everything at once: the timeline itself, the numbers at the top (time, distance, climbing, TSS, power, speed, cadence, heart rate and the rest), the pacing note, the zones and efforts, and the power curve. A banner says exactly which minutes you are looking at and how that compares with the whole ride. Drag again inside it to go deeper, as many times as you like. Back goes up one level and Whole ride returns to the full ride. If something is off, press Edit ride under the numbers (for example after a power meter dropout, or an indoor ride logged without power). You can correct the name, time, distance, climbing, average and normalized power, heart rate and TSS. If you change the time, power or heart rate, TSS is worked out again unless you type your own. Your fitness, fatigue and form numbers update, and your changes are kept when the ride syncs again. Use the calculated TSS puts a typed TSS back. Without second by second data you still get the numbers and estimated zones. The same window opens from Today and from the Rides tab on Progress with Analyze this ride.
Removing strength sessions. Open a strength session on the calendar (or from the day panel, the Strength page, or the planned session list) and press Remove. A session you already logged asks you to tick a box first, because the weights you recorded go with it.
Plan impact. The panel under the calendar projects your fitness (CTL), fatigue (ATL) and form (TSB) up to your next race, or four weeks out if no race is coming up. It assumes you ride the plan exactly as written, so it is a projection and not a prediction. Only workouts still to come count, so a ride you already did today never looks like the plan. If nothing is planned from today on, the panel says so instead of projecting a drop in fitness. If your plan stops well before that day, the panel says so, because the numbers then assume rest after the last planned workout. After you move a workout, the cards show what that move changed and the chart shows the before and after. It uses the same method as TrainingPeaks, so the numbers match the Today page. Strength sessions are not counted in training load.
Working with a day. Click a day to open it below the calendar. From there you can do the following.
- Open a planned workout to edit it or remove it. Removing a workout that was sent to Garmin also removes it from Garmin.
- Mark a workout done, and undo that if you tapped it by mistake.
- Send a workout to Garmin, or download it as a
.fitfile. - Add a workout on that day. Pick the date, type, and training stress, and write a description.
One thing to know. The calendar matches planned workouts to rides by date only. If you planned a workout for Tuesday and rode on Tuesday, it counts as done, even if the ride was a different workout. Planned workouts are not tied to specific rides. If you do two rides in one day, both count toward that day's total. The status colors are worked out when you look at the calendar and are never saved, so they always reflect the latest ride data.
Chatting with the coach
The Coach tab is where most of the planning happens.
- Use the starter questions if you are not sure where to begin. They change depending on whether you have a race coming up.
- Be specific about your week. Tell the coach which days you can ride, how long you have, and what your goal is. If you have a race, say so, or add it on the Races page first and the coach will know about it.
- Ask for a block. For example, "Build me a six week block toward my race with two strength sessions a week." The coach proposes the rides and strength sessions together.
- Your coach can change your calendar and plan. Ask it to move a workout, shorten or rename one, skip a day, or drop a strength session ("I'm travelling Thursday, can you rearrange the week?"). It looks up what is on your plan, then shows a list of proposed changes with the reason for each. Nothing changes until you press Apply changes. Anything not marked done can be changed, including a workout you skipped on a day that has passed, which the coach can move to a later day. A workout that was already sent to Garmin has its old copy removed so you can send it again for the new day.
- Nothing is saved until you say so. Proposed workouts appear in a card right under the reply. Read them, then either add them all to your plan or discard them. If something is off, tell the coach what to change and it will propose again. You can open them on the calendar afterward to see where they landed.
- Attach a screenshot. You can attach an image of a workout, a training plan or a chart with your message, and the coach will read it. The image is used for that message only and is not kept in the chat history.
- Tell the coach about injuries, your schedule or your preferences once. It saves a note in its memory. Open "What your coach remembers" to read the notes and delete any you do not want kept.
- Run the weekly check in. The coach looks over your week and drafts the next seven days for you to confirm. Past check ins are kept so you can look back.
- Clear the chat when you want a fresh start. This removes the saved conversation but keeps your plan, your memory notes and your ride data.
The coach can look up your full ride history, weekly totals, check ins and FTP history on its own when a question needs it, so you do not need to paste numbers in.
Planning a multi month program, like the off season
For anything longer than a block, use the buttons at the top of the Coach tab: Let's discuss the off season, Plan toward a goal or race, or Something else. It works in four steps.
- A short conversation. The coach asks one question at a time, using what it already knows about you (recent weeks, FTP history, races, your notes) so it only asks what it needs. Typical topics are how the season went, whether you want a proper break, how many hours and which days you have, gym work, and what you want from next season.
- A draft program. The coach saves a draft that appears as a card above the chat. It has your goal, how the program is shaped and why, a chart of weekly training load with your projected fitness, each phase with its typical week and what every session is for and how it should feel, strength work, checkpoints such as an FTP test, and the lighter weeks. Nothing is on your calendar yet.
- Discuss and change it. Tell the coach what to change ("make the break one week", "I can only ride Tuesday and Saturday") and the draft updates in place. The card shows the version number.
- Download and add. Download PDF gives a printable copy: the idea on one page, the chart, every phase, the checkpoints and a week by week table. Add to my calendar turns the program into dated workouts and strength sessions, each with its purpose and feel. If you already have workouts planned on those dates, a box (ticked by default) replaces them so days are not double booked. Rides you have already done are never touched. A Discard draft button throws it away. If a week's load looks wrong, open Adjust the weekly load on the draft, type a different TSS for that week (0 for a week off) and save. The chart, PDF and calendar follow your numbers, and the coach keeps them when it revises the draft.
After that, the program stays on the Coach tab with its PDF, and the coach knows which week and phase you are in. You can ask it to move or change individual sessions like any other part of your plan. Starting a new program archives the old one, and the workouts already on your calendar stay.
Getting your plan into TrainingPeaks, Zwift and Garmin
TrainingPeaks, the easy way (needs TrainingPeaks Premium). Open Settings, Connections, tick the box that says you understand it is unofficial, and press Sign in to TrainingPeaks. A Chrome window opens on the TrainingPeaks sign in page. Sign in as you normally would (the app never sees your password) and the window closes itself. From then on every upcoming ride in your plan, however far out, goes onto your TrainingPeaks calendar on its own: whenever the plan changes (the coach adds a week, you move, edit or delete a ride) the app syncs in the background and shows a short note when it is done. Unchanged rides are skipped and changed ones replaced, so nothing is ever there twice. The first time a ride is sent, a planned workout with the same name on that day (for example one you dragged in from the download) is replaced by the synced copy. Workouts with a ride recorded against them, and anything with a different name, are never touched. A ride you mark done stays on TrainingPeaks so it still shows planned against done. It also syncs once a day. The Plan calendar shows when it last synced and has a Sync now button. When TrainingPeaks eventually signs you out, the app first tries to sign back in quietly with the same Chrome profile. If that does not work, syncing pauses and the Plan page asks you to sign in again. Free TrainingPeaks accounts can only hold planned workouts for today and tomorrow, so on a free account only those two days sync. Use Download for TrainingPeaks below instead. The sign in window needs Google Chrome and the playwright package (in requirements.txt). Without Chrome, Settings still lets you paste the Production_tpAuth cookie by hand.
Open Plan, then Manage. Export your plan at the top sends a whole range of rides at once: this week, the next 4 or 12 weeks, your current program, or dates you pick. The Export button on your program card opens it on the program's dates.
The first time, press Prepare steps. The coach turns each written workout into steps (warm up, intervals with power targets from your FTP, cool down), a few at a time, and keeps them. After that, every route below is instant and free until you edit a workout. A workout that can't be converted is listed with the reason, never silently left out.
| Route | What you get | Setup |
|---|---|---|
| Download for TrainingPeaks | Zwift workout files (.zwo) with the date at the start of each title. In TrainingPeaks open the Workout Library, make a folder, choose Import from its menu and select them all. They list in date order, then you drag each onto its day. |
None. This is the official TrainingPeaks route and always works. |
| TrainingPeaks calendar | Each ride on its date in TrainingPeaks, with its structure, kept in step automatically as described above. Moved or edited rides are updated and removed ones deleted. Zwift shows TrainingPeaks workouts on their day when the two are linked. | Optional and unofficial, needs TrainingPeaks Premium. TrainingPeaks has no public API for athletes, so this uses the connection their website uses (like the open source tp2intervals tool). It can stop working whenever TrainingPeaks changes its site and may go against their terms. Press Sign in to TrainingPeaks in Settings. |
| Sync to intervals.icu | Each ride on its date in intervals.icu (free), which passes them to Zwift on every computer you ride on, under Custom Workouts, intervals.icu, and to Garmin. Run it again after changes. | Paste your intervals.icu API key in Settings (intervals.icu Settings, Developer Settings), then connect Zwift in intervals.icu. This is an official API. |
| Download all files | .zwo for Zwift and TrainingPeaks, .fit for Garmin, Wahoo and other bike computers, plan.csv listing every ride, and how to import each. |
None. |
Removing a ride in the app also removes it from intervals.icu and the TrainingPeaks calendar if it was sent there.
Garmin directly. With Garmin connected in Settings, use Send to Garmin on a workout or send a whole week from the Manage tab. You see a preview of the steps first. When you confirm, the workout is uploaded to Garmin Connect and scheduled on its date, so it syncs to your watch or bike computer. If you edit or delete the workout later, the Garmin copy is updated or removed to match. A workout changed after sending shows as needing a resend.
One workout as a file. The Download .fit button on a workout, or Download week as .fit in Manage, still gives you .fit files for a bike computer. TrainingPeaks imports .zwo, not .fit, so use the export panel for TrainingPeaks.
Data and privacy
Where things are kept.
- Your rides, plans, settings, chat history and coach memory are in
data/cycling.dbinside the project folder. This file is listed in.gitignore, so it is never committed to git. - Your API keys are in
.env, which is also in.gitignore. - Your Garmin sign in tokens are in
.cycling_coach_garminin your home folder, outside the project. - An intervals.icu API key or TrainingPeaks cookie, if you add one, is kept in
data/cycling.dband only ever sent to that service. The TrainingPeaks sign in window keeps its own Chrome profile indata/tp_browser, also in.gitignore. Turn off in Settings deletes it.
What leaves your computer.
- When you use the coach, a summary of your training (FTP, weight, fitness numbers, recent rides, races, goals), your chat messages, your coach memory notes and any screenshots you attach are sent to the Anthropic API. The same goes for ride reviews, weekly check ins, race plans and sending workouts to Garmin, which also use the coach.
- Sync talks to Garmin or Strava. Race features fetch public pages from the OBRA website. If you use them, the export panel sends the rides you choose (date, name, steps, purpose and feel) to intervals.icu or TrainingPeaks.
- Nothing else is uploaded. If you never press a coach button and never send a chat message, no training data goes to Anthropic.
To back up your data, stop the app and copy data/cycling.db somewhere safe. To restore, put the copy back in the same place.
To delete your data, stop the app and delete data/cycling.db. To forget your Garmin login, press Disconnect Garmin in Settings or delete the .cycling_coach_garmin folder in your home folder. To revoke the coach's access, delete the API key in the Anthropic console and remove it from .env.
Trying the app on demo data. You can run the app against a fake database and leave your real data alone. This builds about three months of made up rides, plans, strength sessions and a race.
venv/bin/python scripts/seed_demo_db.py /tmp/demo.db
CYCLING_COACH_DB=/tmp/demo.db bash start.sh
Add --empty to the first command to get a database with settings but no rides or plans. The setting CYCLING_COACH_DB works with any file path, so it is also a handy way to keep a separate database for a second athlete. You still need an Anthropic key in .env to open the app, but nothing is spent unless you use the coach.
Troubleshooting
The setup page will not go away. The app only needs ANTHROPIC_API_KEY in .env. Check that the file is named exactly .env (not .env.txt or .env.example), that it sits in the project folder next to app.py, that there are no spaces around the equals sign, and that the key is not still the placeholder text. Then stop the app with Control and C and start it again, because .env is only read at startup.
Garmin says it is limiting requests. Garmin blocks sign in and sync attempts that come too often. Wait about an hour and try again. Do not keep retrying, which can extend the wait.
Garmin does not accept my login or code. Check your email and password by signing in at connect.garmin.com. If you use two step verification, enter the newest code quickly because codes expire, and start over with Cancel if one fails. If it worked before and stopped, press Connect Garmin again to sign in fresh. As a fallback, run venv/bin/python scripts/garmin_setup.py from the project folder, or import .fit files by hand in Settings.
The coach shows an error. An invalid or revoked key shows an authentication error. Check the key in .env against the Anthropic console, fix it, and restart the app. Errors about credits or limits mean the Anthropic account needs more credit or has hit a spend limit. A rate limit or "overloaded" message usually clears up within a minute, so try again. Your message is not lost when a reply fails.
The calendar is empty. The calendar shows what is in your plan and your synced rides. If you have not connected Garmin or Strava yet, connect one in Settings, or import files by hand. If you have no planned workouts yet, ask the coach for a plan or add a workout from a day on the calendar. Also check that you are looking at the right month.
My numbers differ a little from TrainingPeaks. Training stress (TSS) is calculated by this app from your power or heart rate and your FTP or threshold heart rate, not copied from TrainingPeaks or Garmin. Small differences in FTP, in how normalized power is smoothed, and in the starting fitness value all change the totals. Set your real FTP and threshold heart rate in Settings and press Save profile, which recalculates every ride. Setting Starting CTL to your fitness at the beginning of your history brings the fitness line closer to what you are used to.
A ride shows up twice. Press Remove Duplicates under Settings, Data tools. It keeps the version with more data.
Under the hood
Python, Streamlit, SQLite, Plotly, and the Anthropic Claude API (claude-opus-5-5 for chat, plans and race briefs, and the cheaper claude-sonnet-5-5 at low effort for ride reviews and Garmin workout steps, set in claude_client.py). The app is built for one person per copy, so each athlete runs their own copy with their own .env and database.
app.py Entry point, setup and welcome gates, navigation
pages/ Today, Plan, Progress, Strength, Races, Competitors, Settings
planning.py Training block generator used by Quick Generate
programs.py Multi month programs: checks, weeks and dates, saving and adding to the calendar
program_pdf.py The program as a PDF
exporters.py Zwift workout files and the export zips
sync.py Removing rides from intervals.icu and TrainingPeaks when removed here
auth/intervals.py Intervals.icu sync (official API)
auth/trainingpeaks.py TrainingPeaks calendar sync, automatic in the background (unofficial, optional)
auth/tp_login.py The Chrome sign in window for TrainingPeaks
plan_changes.py Moves, edits and removals of planned workouts, shared by the coach and the buttons
garmin_workouts.py Turns workouts into Garmin steps and .fit files
claude_client.py Claude calls, streaming, tool loop, error handling
coach_tools.py Tools the coach can call over your data
coach_context.py Coach persona and athlete snapshot
coach_reports.py Ride review, weekly check in and race plan prompts
db/ SQLite schema and queries
auth/ Garmin and Strava sign in and sync, .fit and .csv import, ride data fetching
metrics/training_load.py Fitness, fatigue and form (CTL, ATL, TSB)
metrics/plan_impact.py What a change to the plan does to those numbers, plus plan warnings
metrics/zones.py Power and heart rate zone estimates
metrics/analysis.py Search filters, totals, weekly volume, efficiency, peak power curve, history and power profile
metrics/peaks.py Best average power and heart rate by duration from a ride file
metrics/streams.py Second by second ride data: smoothing, zones, efforts, pacing
metrics/explain.py All the plain language wording, in one place
research/ OBRA schedule and race results
components/ Shared interface pieces
components/calendar.py Calendar data, moves and undo for the Plan page
components/calendar_dnd.py The interactive grid (drag, click, hover)
components/plan_impact_ui.py The Plan impact panel and undo bar
components/explain.py Help icons and tooltips that explain a number in plain words
components/ftp_help.py FTP estimate note, suggestion from best 20 minutes, guided test
components/ride_analysis.py The ride analysis window
components/plan_export.py Export your plan to TrainingPeaks, Zwift and Garmin
components/program_ui.py The program draft card, PDF button and starter buttons on the Coach tab
components/checklist.py Getting started checklist on Today
components/data_filters.py Date range, search and filters for the Progress page
components/ride_detail.py Rides table and ride detail used by Today and Data
components/history_table.py The fitness history tables on the Progress page
components/charts.py Chart styling, drag to zoom and Reset zoom
scripts/garmin_setup.py Terminal fallback for connecting Garmin
scripts/seed_demo_db.py Builds a demo database
tests/ Tests for the calendar, moves, plan impact, analysis, peaks, history and wording (python -m unittest discover -s tests)
.streamlit/config.toml Dark theme
The coach can only read your data through a small set of read only tools. The one thing it can write, proposed workouts, takes effect only after you confirm in the app.
License
MIT. See LICENSE.
来源:GitHub · github.com