laloop

Side project · 2026 · Sports analytics

Training analysis a coach can defend

Training analysis for a triathlon squad and its coach. It reads TrainingPeaks, Garmin and Intervals.icu, computes load, fitness, session types and race predictions, and serves one page per athlete. Every finding comes from a rule with a cited source; the local LLM only narrates.

9
rule-based analysis skills, each traced to its sources
3
data sources reconciled into one session per workout
7
race courses modelled with 10 years of weather
1
container on a mini PC, model included

The problem

A coach's data is scattered: plans in TrainingPeaks, files from watches and bike computers, thresholds in Intervals.icu. The same session shows up two or three times, power meters die mid-ride and thresholds drift.

Generic AI coaching makes this worse: confident advice with no basis. Here the numbers come from published methods and the model is only allowed to explain them.

How it works

Daily pipeline

  1. CollectCoach's exports, device files and Intervals.icu activities and thresholds
  2. ParseFIT files, and the proprietary WKO4 binary, decoded from scratch
  3. ReconcileOne copy per session; every source item gets exactly one fate in a ledger
  4. ComputeZones, TSS, fitness and fatigue, session type, planned versus executed
  5. JudgeNine rule sets fire alerts, watches and context, each with its references
  6. NarrateLocal LLM writes notes and a morning brief from the computed facts only

A skill is a rule set with references

Load monitoring, as the engine applies it. The LLM never sees raw files, only the findings.

skills/load_monitor.md
Sources: Simmons, Total Load; Friel,
  Applying the numbers
Rules
  CTL ramp > 7 points in 7 days     alert
  TSB < -30                         alert
  weekly TSS jump > 10%             watch
  4 weeks without a lighter week    watch
  TSB +15 to +25                    race form
  TSB -10 to -30                    productive
Data
  pmc.daily (ctl, atl, tsb), weekly52

Decisions that mattered

The LLM narrates, never computes

Every number comes from a deterministic step that has tests. The model turns findings into readable notes and nothing else.

Every input is accounted for

A ledger records what happened to each file and entry, and a reconciliation report shows anything unexplained.

Decode instead of giving up

The coach's exports are a proprietary binary. The format was reverse-engineered field by field, including the embedded original device file.

Thresholds change over time

FTP is backed out of the platform's own TSS per quarter and threshold heart rate fitted from steady efforts, so old sessions are scored against the fitness of that day.

Distrust the sensors

A power meter that reads zero most of the ride is ignored, and an implausible TSS is replaced by a heart-rate estimate.

Privacy by role

Athletes only ever receive their own data. Everything runs self-hosted with a local model.

Stack

LayerChoiceWhy
Parsinggarmin-fit-sdk, custom WKO4 decoderPer-second power, heart rate, GPS and laps
PipelinePython scripts over CSV/JSONSimple to inspect, easy to rerun
AppFastAPI, SQLite, argon2Coach and athlete roles, installable web app
LLMOllama on the hostNotes, morning brief, grounded Q&A
MobileCapacitor iOS, APNsPush for new session notes
DeployDocker Compose on a mini PCDaily run at 05:00 plus on-demand sync

Where it stands

In daily use by a small squad. Any public demo uses a synthetic athlete; no real athlete data is shown here.

More work

Have an AI project stuck at the prototype stage?

Tell us the problem, the data and where it needs to run. We'll come back with an architecture and scope proposal.

Email contato@laloop.ai