Zwift training coach program with gemini

Hi David and the community,

First of all, huge thanks to David for building such an amazing platform and keeping the API so open and developer-friendly. It really empowers us to build cool things!

I wanted to share a personal project I’ve been working on, called Aixle (pronounced “Axle”).

It is an open-source, automated coaching system running on Google Apps Script . It connects your Intervals.icu data with Google Gemini (AI) to generate a daily custom workout.

GitHub: https://github.com/kuukuu/Aixle

daily mail sample is here.

screen shot on zwift workout page. auto sync available(now windows only)

How it works:

  1. Fetches Data: It pulls your daily fitness data (TSB, CTL, recent load) via the Intervals.icu API.

  2. Analyzes: It calculates your training phase (Base/Build/Peak) based on your target race date.

  3. Generates: It sends a prompt to Gemini (Model: gemini-3-pro-preview) to design a specific Zwift workout (.zwo) for the day.

  4. Delivers: It saves the file to Google Drive (which syncs to Zwift) and emails you a summary.

Why I built it:
I wanted a logical, data-driven training plan that adapts to my daily fatigue, without the expensive monthly subscriptions of other coaching platforms.
Since it runs on your own Google Cloud account, it operates at a minimal cost (just the small API usage fees), making it a very affordable alternative.

I hope some of you find it useful or get inspired to build upon it!

Thanks again,

9 Likes

Runs in Google sheets :smiley: That was unexpected. Really neat, thanks for sharing!

Thanks for trying it out, I’ll keep it updated!

Currently, there are usage hurdles, such as the need for a Gemini API key, and issues with API timeouts, so I’m preparing to turn it into a web service.

1 Like

Soon after I posted it was working no problem. Got my workout email this morning! Thanks!

Is there a workflow to get the .ZWO loaded into Intervals.icu?

In the current version, I installed the PC version of Google Drive and synchronized it using a synchronization script (only available for Windows). In the next version, I plan to link it to Zwift by uploading it to intervals.icu.

Thank you for trying it. In the next version, we will make it possible to try sending an email immediately.

1 Like

if (result.success) {
const safeType = type.replace(/[^a-zA-Z0-9]/g, “”);
const fileName = Aixle_${safeType}_${fileDateStr}.zwo;

  const blob = Utilities.newBlob(result.xml, "text/xml", fileName);
  folder.createFile(blob);

  // This uploads the workout to today's date on your calendar
  uploadWorkoutToIntervals(fileName, result.xml, formatDateISO(new Date()));
  //

And put this new function at the bottom of the script:

function uploadWorkoutToIntervals(name, zwoContent, dateStr) {
const athleteId = “0”; // “0” works for the API key owner
const url = https://intervals.icu/api/v1/athlete/${athleteId}/events;

const payload = {
category: “WORKOUT”,
type: “Ride”, // Default to Ride for cycling
name: name,
description: “Generated by Aixle AI Coach”,
start_date_local: dateStr + “T08:00:00”, // Schedules it for 8:00 AM
file_contents: zwoContent,
file_extension: “zwo”
};

const options = {
method: “post”,
headers: {
“Authorization”: ICU_AUTH_HEADER,
“Content-Type”: “application/json”
},
payload: JSON.stringify(payload),
muteHttpExceptions: true
};

try {
const response = UrlFetchApp.fetch(url, options);
if (response.getResponseCode() === 200 || response.getResponseCode() === 201) {
Logger.log( -> Successfully uploaded to Intervals.icu: ${name});
} else {
Logger.log( -> Failed to upload to Intervals.icu: ${response.getContentText()});
}
} catch (e) {
Logger.log( -> Error uploading to Intervals.icu: ${e.toString()});
}
}

1 Like

Love this tool! I’ve added some proposed changes to improve it:

1 Like

I plan to release a web service version in the new year.
No API keys or spreadsheets needed.

new version released!

Aixle

easy to use,no API key,spread sheets,appScript.

3 Likes