An AI fitness coach for people who cannot afford a human one. It starts everyone on the same proven plan, changes it as you train, and does more the more you give it.
In one line: a personal AI trainer built to make good decisions on data it cannot fully trust.
Walk three personas through setup, the daily card and the weekly decision. The internal dashboard is the second tab.
Week 12 of a HYROX block. The athlete has completed every session. Adherence says push harder. His heart rate variability and resting heart rate both say he is under-recovered. He says he feels strong.
The model's own confidence in this decision collapses to 0.05, far below the 0.65 it needs to change a training week.
It cuts his load anyway.
The decision that defines the product. Every number here is computed live in the simulator, not drawn.
A coach that is honest about what it does not know is more useful than one that is confidently wrong. Uncertainty should change how big an action is, not whether the coach acts at all.
Personal coaching works. It is priced out of reach for almost everyone.
The bet is that a coach reading real signals, adapting weekly, and explaining itself delivers most of a human coach's value at a fraction of the price. Not all of it. Enough to change behaviour for a very large group.
I scoped it as three tiers of one engine: someone who wants to start and not quit, someone holding a routine, and someone training for a race. Different data, different horizons, different levels of autonomy handed to the coach. If a tier needed its own logic branch rather than its own configuration, the architecture would be wrong.
The obvious version is a chatbot that generates a plan. It demos well and it fails quietly, because generating a plan is the easy half. Anyone can produce a reasonable twelve-week programme. Almost nobody adapts it well when the user misses two weeks, sleeps badly, or turns up with a sore knee and twenty minutes.
So the first real decision was where the intelligence belongs.
| Stays deterministic | Needs an agent |
|---|---|
| Training load maths, overload ratios | Interpreting "my knee felt weird and I was up late with my kid" |
| Zone boundaries, periodisation, taper timing | Resolving signals that contradict each other |
| Calorie and macro arithmetic | Negotiating the version of today's session the user will actually do |
| Safety ceilings and deload triggers | Deciding when not to change anything |
Physiology has known formulas. A language model computing them produces confident wrong numbers, which is the worst possible failure in a product people trust with their bodies. So: a deterministic physiology core, with the agent at the edges. The agent perceives, interprets, decides what to change and how to say it. The engine computes what the change actually is.
The coach has to make decisions from data of wildly uneven quality, and it gets worse over time.
A race athlete has a chest strap, a power meter and a recent lab test. A mass-market user has a phone step count and whatever they typed into a form three weeks ago. And everyone drifts: nobody cancels, they just stop wearing the watch.
Most fitness apps handle this by ignoring it. A weight typed in a month ago is treated exactly like a measurement taken this morning, and the output sounds equally confident either way. That is how these products lose trust. Not by being wrong occasionally, but by being equally confident when they are wrong.
So I built a model for it.
Every input gets a score: source quality, decayed by how old it is, gated on whether it is physiologically plausible. A lab measurement from last year is not a lab-grade input today.
Those roll up into one number per decision, and that number decides not whether the coach acts but how much authority it has.
Four bands. A second, independent gate controls how big the change can be: 0.50 for a small step, 0.65 to change the week's structure, 0.80 for a deload or a block change.
Self-report is not weak data. It is weak for measuring the body and it is the only valid source for everything else. No device measures whether someone has twenty minutes on Thursday, how sore their shoulder is, or what they are actually training for. Downgrading self-report across the board would have made the coach worse while looking more rigorous.
Missing data should cost you something without stopping the product. An input below the floor is dropped and its weight redistributes, then a coverage penalty applies. In practice a user with no wearable progresses in five percent steps instead of ten, and cannot add a session until they connect something. That is a better answer than either blocking them or pretending the gap does not exist.
Any change that reduces load, adds rest, or routes to a professional has no confidence floor at all.
The coach never needs to be certain to make training easier. It only needs to be certain to make it harder.
Uncertainty should always resolve toward the safer action. The cost of an unnecessary rest day is a slightly slower week. The cost of a missed overtraining signal is an injury and a churned user. Those are not symmetric, so the gates should not be either.
This is what fires in the opening example. The maths says hold. The action reduces load, so the floor does not apply, and the coach acts and names the disagreement out loud rather than hiding it. That last part matters as much as the decision: a human coach says exactly this, and it is what makes the product feel like a coach rather than an algorithm.
The spec was internally coherent and completely unshippable. That only became visible after running it thirty-six times.
I built a working simulator rather than a clickable prototype, because the thing I needed to prove happens across weeks, not screens. Three personas, twelve weeks each, every decision computed by the real model.
The coach never progressed anyone. All three personas sat permanently in Hold. Three separate causes:
coherence = |Σ w·direction|
Divides by total weight, so a metric with no opinion counts against agreement. Adherence saying "push" while recovery sits neutral scored 0.40 when nothing disagreed with it.
coherence = |net| / opinionated weight
A neutral signal is not a dissenting one. Most metrics have no opinion most of the time, and the coach should not be punished for that.
Correction one. The other two: I had written graceful fallback for missing inputs into the model and never implemented it, which structurally locked the entire mass-market segment out of ever progressing. And fatigue was measured against a fixed constant, so a six-session athlete read as permanently overtrained and sat in an endless deload.
I also changed how the coach chooses an action. It now proposes the largest step its confidence supports, rather than picking something ambitious and then failing its own gate. Same evidence, more confidence, bigger step.
A specification you have not simulated is a hypothesis. Three of the errors were invisible on the page and obvious the moment the model had to produce twelve consecutive weeks of behaviour for a person who was not cooperating.
The app on the left, the engine's reasoning on the right. The inspector exists so a reviewer can disagree with the coach and point at the number that was wrong.
Reviewing the build, the reaction was that the coach felt dead. It was right. My loop ran weekly, which is the correct cadence for changing someone's training and the wrong cadence for keeping them in the product. Six days out of seven the app had nothing to say.
The obvious fix is to say something every day. That is worse. A single day of steps tells you almost nothing, HRV has a three-day half-life, and manufacturing a confident daily insight from thin data is exactly what the whole confidence model exists to prevent.
The resolution was to separate what the two loops are allowed to do.
| Daily card | Weekly decision | |
|---|---|---|
| Runs | Every day | Day 7 |
| Does | Observes yesterday, suggests one small action for today | Changes the plan |
| Changes load | Never | Yes |
| Confidence gate | None required | Full gate |
| Purpose | A reason to open the app | A plan that fits the person |
The daily card can run on weak data because it never alters the plan. Six rules fire in priority order by what the data supports, and the most important of them is the one that fires when nothing is readable: the card says "I am working blind on recovery" and still gives the user one thing to do. It does not invent an observation to fill the space.
Every card carries one specific, today-sized action with a reason. After a miss: do the first ten minutes, you can stop after. On a session day: put a start time in your calendar. Never "get fitter", never a target weeks away.
With one exception. An athlete with a race date is motivated by the horizon, not despite it, so Tier 3 gets a visible countdown above the daily card. Tier 1 does not, because a visible distant goal is precisely what discourages someone who has already failed at one. Same engine, different configuration.
The dashboard is the other half of the build: what the company sees, against what the model assumed.
Adaptation acceptance rate rising over time for the same user, with completion rate holding or rising. If the coach's suggestions get more accepted the longer someone uses it, the learning loop is real. If it stays flat, the personalisation is cosmetic.
Simulated cohort, 1,240 users, 12 weeks. I wrote the numbers to tell an honest story rather than a flattering one.
Three findings I built in because they are the ones this product would genuinely surface:
All three were caught by building the thing rather than by reading the document again.