Skip to content

Developers

Install, license, integrations, embedding. The Python library + CLI side. Methodology lives in /methodology; usage docs in /help.

Is it on PyPI? How do I install the library?

Not yet. Pre-1.0 the API still moves enough that a PyPI wheel would mislead about stability. Install from source:

git clone https://github.com/sam-dumont/bike-power-model-lib
cd bike-power-model-lib
uv sync --extra api --extra analysis
uv run bpm --help

uv is the supported path. Bare pip install -e . works but isn't covered by CI. PyPI publish lands with the 1.0 SemVer commit.

What's the license? Can I ship it in a paid product?

MIT. Fork it, modify it, ship it in a closed-source product, sublicense it. Attribution required (standard MIT notice in your dist), no copyleft, no royalty.

Per-sector surface Crr database, OTS-stamped predictions, validation cohort: same repo, same license. A heads-up at info@bikepowermodel.fit is appreciated if you ship commercially, but not required.

Does it integrate with TrainingPeaks / Wahoo / intervals.icu?

Partial.

  • intervals.icu: wired, OAuth. Hit "Connect intervals.icu" in Settings: it imports your FTP, weight, W′ and real power curve (read-only scopes). Plans use your curve as of the race's date: a race next Sunday gets your last 90 days, a past race gets the 90 days before that day (the day itself excluded), plus the FTP and weight you had back then. Analyzing a ride does the same at the ride's date. A toggle in Settings switches all of it off if your curve is unrepresentative. The token lives in your browser, never on our server. As a library, auth stays in ~/.config/bike-power-model/.env.
  • TrainingPeaks / Wahoo: not yet. Today's workflow is GPX in → Garmin Power Guide FIT out. The FIT you download from the planner sideloads onto an Edge via Garmin Express; nothing pushes to a coach platform.
  • CSV export: the planner has a CSV download for the per-split plan if you want to pull it into your own pipeline.

What's the SemVer / breaking-change policy?

Pre-1.0, so technically anything-goes. In practice:

  • The public surface (plan_race, plan_ride, RiderProfile, Course, the for_time_trial constructor) is treated as stable. Breaking changes here get a CHANGELOG entry quantifying the impact.
  • Internal helpers (modifiers, splitters, calibration tables) move freely without notice.
  • Recalibrations can shift predicted times by 2-5 % even with identical inputs. That's a customer-visible drift with no input change. Treated as a minor bump, not a patch.

1.0 commits to strict SemVer with a deprecation cycle. Until then, embedders should pin to a specific commit, not a moving tag.

Can I run bulk predictions for a squad?

The web UI is one-rider, one-route at a time. The Python library handles bulk:

from bike_power_model import RiderProfile, plan_race

for athlete in roster:
    rider = RiderProfile(
        ftp=athlete.ftp,
        rider_mass_kg=athlete.weight_kg,
        bike_mass_kg=8,
        cda=athlete.cda or 0.30,
        height_m=athlete.height_m,
        sex=athlete.sex,
    )
    rider.effort = 1.0
    plan = plan_race(course_path, rider,
                     race_date="2026-08-15",
                     race_start_hour_local=9)
    print(athlete.name, plan.result.total_time_s)

A coach with Python familiarity can wire athlete CSVs to per-rider FIT files in an afternoon. CLI wrappers + a coach-surface UI are planned but not shipped.

What dependencies does the library pull in?

Lean. Core: numpy, requests, pmtiles + mapbox-vector-tile (OSM surface tiles), scipy (cKDTree for spatial sector lookup), click (CLI), and the Garmin fit-tool + garmin-fit-sdk for FIT read and write.

No PyTorch, no scikit-learn at runtime (a Lasso baseline is a one-off benchmark, not a runtime dep). The API extras pull in fastapi, uvicorn, boto3, altcha, email-validator: only needed if you're running the SaaS, not the library.

Versions exact-pinned (supply-chain policy); full set in pyproject.toml + uv.lock.

What's on the CLI?

bpm plan generates a Power Guide FIT from a GPX + a rider profile. bpm calibrate back- solves CdA from a flat ride of yours. bpm power-guide reads the messages 352/353 out of an existing Garmin Power Guide FIT. bpm --help for the full list.

All commands take a --ftp, --weight, --cda, --effort, --intent flag set; the preset chips on the SPA are just shorthand for these.