Fitness model & workout generation

Training load is computed from the rides you actually do. No FTP tests, no zone configuration, no manual entries.

CTL / ATL / TSB

Bannister's impulse-response model with configurable time constants. Each ride contributes a Training Stress Score (derived from normalized power or HR-based fallback), feeding two exponentially-weighted averages: Chronic Training Load (CTL, fitness) and Acute Training Load (ATL, fatigue). Form is CTL − ATL.

Critical Power, automatically

Fitted from the power curve across recent rides. The number reflects current form, not a six-month-old test.

Ingest: Strava sync or direct FIT upload

Two ways in. Most users connect Strava — once-and-done, full-history backfill, webhooks for new rides. For users without Strava (or with Rouvy / Zwift / head-unit FIT files in hand), Routebook also accepts direct FIT uploads through Mapbox-driven map view.

  • Strava: OAuth + webhook subscription, paginated resumable backfill, activity → FIT extraction.
  • Direct FIT upload: resumable TUS uploads to Supabase Storage, parsed in-app, same metrics pipeline.

.zwo workout generation

Per-ride: Claude generates a structured workout (warmup, intervals, ramps, steady-state, cooldown, freeride) constrained by a Zod schema. Eight skill types: target, endurance, threshold, tempo, VO2max, strength, climbing, cadence, recovery. Output rendered as Zwift .zwo.

Read the fitness metrics write-up on Orbital