This is my hobby project. I am not a coder, so all the code is written by Claude. Yes, I am one of those disliked vibe coders :-). That said, this app serves my needs and has been developed according to the hardware that I have available. If you would like to use this app you are of course free to do so. If you have any issues with the app, or if your hardware isn't supported or if you have any feature request, you are free to let me know.
Cycle is a native GNOME application for indoor cycling training, built in Rust with GTK4 and libadwaita. It connects to smart trainers and sensors over Bluetooth LE and ANT+, executes structured workouts with automatic resistance control (ERG), records sessions, and integrates with Intervals.icu and the Anthropic Claude API for training analysis and AI-assisted coaching.
The application targets GNOME desktop environments and is distributed as a Flatpak.
Cycle is not on Flathub. It is published from its own Flatpak repository instead, which works exactly the same way — you just have to tell your computer about it once.
What is a Flatpak? It is a way of installing Linux apps that keeps each app and everything it needs in its own box. Nothing it installs can break the rest of your system, and removing it leaves nothing behind. Most Linux systems already have Flatpak; if yours does not, install the flatpak package from your distribution.
A "repository" is just an address your computer checks for the app and its updates. Open a terminal and paste:
flatpak remote-add --if-not-exists cycle https://rorynuijens.github.io/Cycle/cycle.flatpakrepoNothing is installed yet — this only saves the address.
flatpak install cycle io.github.rorynuijens.CycleThe first install also downloads the GNOME runtime (the shared set of libraries every GNOME Flatpak uses), so it may take a few minutes and a few hundred megabytes. Later updates are much smaller. Cycle then appears in your applications menu like any other app.
flatpak updateRun this whenever you like. It updates Cycle along with everything else you installed through Flatpak. There is nothing else to configure.
Every release also has a .flatpak file attached. Download it and run:
flatpak install ./cycle-0.1.0.flatpakThis is handy for a machine that cannot reach the repository, but it is a one-off: flatpak update will not find new versions, so you have to repeat the download for each release. The repository in step 1 is the better option if it works for you.
flatpak uninstall io.github.rorynuijens.Cycle
flatpak remote-delete cycleYour training data lives outside the app and is not deleted by this. To remove that too, delete ~/.var/app/io.github.rorynuijens.Cycle.
- "No remote refs found" — the repository address could not be reached. Check that
https://rorynuijens.github.io/Cycle/opens in a browser. - "GPG signatures found, but none are in trusted keyring" — the remote was added incorrectly. Remove it with
flatpak remote-delete cycleand redo step 1 using the full.flatpakrepoURL above, which carries the signing key with it. - The app starts but finds no trainer — that is a Bluetooth or ANT+ matter, not an installation one; see Requirements below.
Cycle communicates with BLE devices using standard GATT profiles:
- Smart trainers — Fitness Machine Service (FTMS). ERG mode for structured workouts (the app sends a target power and the trainer adjusts resistance automatically) and SIM mode for route rides (the app sends the road gradient and the trainer sets resistance to match).
- Power meters — Cycling Power Service (CPS). Read-only; power data is recorded but the meter cannot be commanded.
- Heart rate monitors — Heart Rate Service (HRS). Supports both 8-bit and 16-bit HR measurement formats.
- Cadence sensors — Cycling Speed and Cadence Service (CSC), crank revolution data.
Trainers that expose no usable BLE interface are supported over ANT+: with a USB ANT+ stick, Cycle drives FE-C trainers with full ERG and SIM control plus power and speed readings.
Devices paired in a previous session are remembered and reconnected automatically on the next launch.
Structured workouts are executed segment by segment. Each segment specifies a target power as a percentage of the athlete's FTP. Ramp segments interpolate linearly between two power values. During execution the player displays elapsed and remaining time, target power in watts, live power, cadence, and heart rate from connected devices, and a colour-coded workout graph with a position cursor.
Workouts can be paused and resumed. Ending a workout early saves the recorded portion as a complete session. At the end of a session the athlete is prompted to record a Rate of Perceived Exertion (RPE) on a 1–10 scale.
GPX routes can be ridden in simulation mode: the trainer's resistance follows the route's gradient, and the rider's measured power is converted to a virtual speed through a road-cycling physics model — ease off on a climb and the climb takes longer. The route player shows live gradient, virtual speed, position on the elevation profile, and distance remaining. Without a controllable trainer, route rides fall back to ERG emulation: power targets computed from the gradient at a fixed assumed speed.
The library holds structured workouts across eight training categories: Recovery, Endurance, Tempo, Sweet Spot, Threshold, VO₂ Max, Anaerobic, and Custom. A built-in workout creator edits workouts segment by segment — steady blocks and ramps with FTP-percentage targets, reorderable by drag and drop — and existing workouts can be opened in the same editor. Workouts can also be imported from .zwo files (Zwift XML format) or .erg files, scheduled to a calendar date, or deleted. GPX files can be loaded to preview a route's elevation profile and ride it in the route player.
A monthly calendar view shows scheduled workouts, completed sessions, and marked time-off periods. FIT files recorded on external devices can be imported directly from the calendar. Time off can be marked for individual dates or date ranges.
All sessions are stored locally in SQLite. The history view shows duration, average power, normalised power, average cadence, average heart rate, power zone distribution, kilojoules, and Training Stress Score. A route map rendered from OpenStreetMap tiles is shown when GPS data is present in the source FIT file. Sessions can be deleted individually or uploaded to Intervals.icu as FIT files.
The fitness page computes and displays:
- CTL (Chronic Training Load) — 42-day exponentially weighted average of daily TSS
- ATL (Acute Training Load) — 7-day exponentially weighted average of daily TSS
- TSB (Training Stress Balance) — CTL minus ATL
- Weekly TSS totals and power zone distribution across recent sessions
These metrics are derived from both locally recorded sessions and activities synced from Intervals.icu.
Connecting an Intervals.icu account enables syncing activity history (training load, power, HR, cadence, distance), syncing wellness data (HRV, resting HR, sleep, steps, calories), uploading locally recorded sessions as FIT files, and importing structured workouts from the Intervals.icu workout library. Credentials are stored in the GNOME Secret Service keyring.
Cycle integrates with the Anthropic Claude API to provide:
- Morning briefing — a daily readiness assessment based on current CTL, ATL, TSB, wellness data, scheduled workouts, and upcoming time off. The briefing concludes with a recommendation to proceed, modify the planned workout, or rest.
- Workout recommendation — suggests a workout from the local library given the athlete's current training load and defined goals.
- Retrospective analysis — a written review of the past week or month of training, incorporating session data and wellness trends.
- Training program generation — produces a multi-week training plan toward a stated goal, expressed as workout recommendations.
The Anthropic API key is stored in the GNOME Secret Service keyring.
Cycle is intended for cyclists who train indoors on a smart trainer and want a self-contained GNOME application for session execution and training load management. It is most useful to athletes who already use Intervals.icu to track training history and wellness, prefer a native Linux desktop application over a browser-based or proprietary platform, and want AI-assisted training guidance without sending personal data to a third-party coaching service.
The application assumes familiarity with power-based training concepts: FTP, TSS, CTL, ATL, and power zones.
- Linux with a GNOME desktop environment
- Bluetooth adapter supporting Bluetooth LE (4.0 or later)
- Optional: a USB ANT+ stick for ANT+ FE-C trainers
- BlueZ accessible via D-Bus (standard on Fedora, Ubuntu, Arch, and most common distributions)
- GNOME Secret Service daemon (gnome-keyring or equivalent) for credential storage
- Network access for Intervals.icu sync, AI features, and map tile rendering
- ANT+ covers FE-C trainers only. ANT+ heart rate straps and cadence sensors are not supported; use their BLE mode instead. Running the ANT+ stick outside Flatpak may require a udev rule granting USB access.
- The SIM physics model is simplified: fixed air density, rolling resistance, and drag area, with no wind, drafting, or surface changes. Rider weight comes from the athlete profile.
- The Anthropic Claude API is the only supported AI provider. The API endpoint is hardcoded to
api.anthropic.com. Despite a reference to OpenAI and compatible APIs in the setup wizard, only the Anthropic API is implemented. - AI features require a paid Anthropic API account. There is no offline fallback.
- The AI has no write access to the workout schedule; recommendations are displayed as text and must be acted on manually.
- Intervals.icu is the only supported external training platform. There is no Strava, TrainingPeaks, Garmin Connect, or Wahoo integration.
- FIT files from Garmin or other devices must be transferred manually and imported via the calendar or history view.
- Linux only. There are no macOS or Windows builds.
- Distributed as a Flatpak targeting the GNOME Platform runtime. Running outside a Flatpak environment requires manual dependency resolution.
- The application has not been tested on non-GNOME desktop environments (KDE, Sway, etc.).
- Session data is stored in a local SQLite database (
~/.var/app/io.github.rorynuijens.Cycle/data/cycle/cycle.dbin the Flatpak sandbox). There is no automatic backup or cloud sync of the local database. - FIT export is available per session. There is no bulk export of the full session history.









