← Index
Android · In daily use — PRD Oct 18, coaching engine v2 Oct 24

Odu

An AI running coach that coaches like a person: notice, ask, then decide with the athlete.

Overview

I train with a COROS watch, track recovery with a Whoop and a Pixel Watch, and used to have a human coach. Every product I tried owns one slice and stops there. Template plans go quiet; Garmin rewrites the week the moment a run deviates without knowing why a run was cut short. Apps forget injuries and time trials. The watch has the run, Whoop has the sleep, nothing has the food, and none of them talk to each other. Odu sits above the devices as the coaching layer: trust each source only for what it measures well, cross-reference them, and coach through a conversation.

Screens
Chat is the home screen — a real exchange about going heavy the day before a time trial.
Chat is the home screen — a real exchange about going heavy the day before a time trial.
Today: the session as a glass hero card with its reasoning, the week's progress, and body stats.
Today: the session as a glass hero card with its reasoning, the week's progress, and body stats.
The week, colour-coded by session type — green easy, pink intervals, purple long, teal strength.
The week, colour-coded by session type — green easy, pink intervals, purple long, teal strength.
A session opened: the 5K time trial with its purpose and steps, pushable to the watch.
A session opened: the 5K time trial with its purpose and steps, pushable to the watch.
Predicted race times as a range with a confidence label, not a single false number.
Predicted race times as a range with a confidence label, not a single false number.
Easy-run pace against heart rate — the evidence the fitness model actually reads.
Easy-run pace against heart rate — the evidence the fitness model actually reads.
Training load by week against your usual, with the plan holding back when it spikes.
Training load by week against your usual, with the plan holding back when it spikes.
The same chat in dark mode. Light and dark run throughout, including widgets.
The same chat in dark mode. Light and dark run throughout, including widgets.
Today in dark, the session glow tinted to the day's workout type.
Today in dark, the session glow tinted to the day's workout type.
Scroll sideways →
Features
  • A coach you talk to
    Chat is the home screen. The coach explains every decision in your own numbers — paces, distances, dates — never in jargon.
  • It reaches out only when it matters
    After each synced run a rulebook decides: stay quiet, leave a short note, or ask one question with tap-to-answer replies. Tapping "Not needed" makes that kind of check-in rarer; the third time, it stops.
  • It never changes the plan on its own
    Every change is a proposal card showing what you gain and lose. Real reasons — sick, travel — change the plan without argument; preferences get an honest trade-off.
  • Memory with an expiry date
    Injuries, time trials and preferences are stored with a scope: standing, temporary ("until Nov 7"), or one-off. The coach never brings up a cold from three weeks ago.
  • A plan built one week at a time
    Base, build, peak, taper, counted back from race day — never a fixed 16-week block. A workout only progresses to its harder step once you have hit the current one.
  • Fitness read from heart rate, not pace
    10 km at 5:00/km at 160 bpm means a fitter runner than the same run at 180 bpm, and Odu can tell the difference. Predicted race times come as a range with a confidence label.
  • Ramp-back after breaks
    After seven or more days off it rebuilds at 70%, 50% or 35% of the old volume depending on the gap. Breaks are where runners get hurt.
  • One place for everything
    COROS for runs and structured workouts pushed to the watch, Health Connect for sleep and HRV, one-sentence food logging, home-screen widgets tinted to the session's colour.
How it works
  1. 01A run syncs from the COROS watch with its GPS, pace, heart rate and lap splits.
  2. 02The rulebook classifies the outcome: on target, short, easy run too hard, faded late, heart rate high for the pace.
  3. 03That class maps to silence, a note, or one question — and each answer unlocks specific options.
  4. 04Any plan change arrives as a proposal card. You accept it or keep what you had.
  5. 05The next two days of workouts are pushed back to the watch as structured sessions.
Stack
FlutterDartKotlinSupabasePostgresDeno edge functionsClaude APICOROS MCPHealth Connect
Key decisions
Rules decide, the AI explains
A language model is great at conversation and bad at being consistent, so every coaching decision comes from explicit, tested logic. Claude words it, asks the one question that matters, and negotiates only within the options the rule already allows. That split is the whole architecture.
Sit above the devices, not beside them
Each source is trusted only for what it measures well. COROS is the single source of truth for runs; Health Connect supplies sleep, HRV and resting heart rate but is deliberately never used for runs, because it holds duplicate copies of the same run from several apps.
Never change the plan unilaterally
Garmin rewrites the week the moment a run deviates, without knowing why. A cut-short run could be fatigue, an injury or a bathroom stop, and only the athlete knows which. So Odu proposes and the athlete disposes — notice, ask, then decide together.
Recovery-aware, not recovery-driven
If HRV is low and resting heart rate high two days running before a hard session, the coach mentions it and offers an easier option. It never swaps the session on its own. Recovery data informs the conversation rather than overriding it.
Paces move slowly, and only on evidence
A fitness estimate is taken per run from pace against heart-rate reserve, then six weeks are combined with a weighted median so one hot day or a loose strap cannot swing it. Paces update at most one small step a week, only when the evidence holds, and the coach says why.
Context rebuilt on every message
The coach never relies on chat history for facts. Each message rebuilds the athlete's context from the database: the plan and its rationale, active memories, recent runs labelled today or yesterday, past decisions, recovery, food and fitness.
How it was built
PRD first, then build
I wrote the PRD and design spec, then designed and built it with Claude Code as engineering partner. PRD on 18 October, a working app on my phone within the week, coaching engine v2 shipped on the 24th. About 8,700 lines of Dart, 5,300 of TypeScript, 700 of Kotlin and 12 database migrations.
Rescuing a hollow first draft
The first version, generated by another AI tool, looked plausible and was hollow: demo data, an API key built into the app, and a plan that never adapted. I reviewed it against my PRD and rebuilt it end to end — real data model, server-side plan engine, security hardening.
The 18.5 km run that was really 10 km
Health Connect held several copies of the same run, from COROS, the Pixel Watch and Whoop, and summed their distances. The fix was architectural rather than a patch: COROS became the only source of runs, Health Connect was kept for sleep and HRV, and synced runs now replace duplicates.
A backtest that caught a calibration bug
31 scenario tests cover every rule and the fitness model, including the 160-versus-180 bpm case. A backtest script replays real training history day by day — and caught the model scaling to 21:52 when it had been calibrated to 23:00, because the offset was weighted differently from the live estimate. It never reached the app.
Bugs only the real world finds
COROS returned runs that were never stored, because the tool output was JSON-encoded text and the parser saw one line; a sync log found it in minutes. Timestamps in UTC meant 8pm Saturday was already Sunday on the server, so the coach now gets local time and labels every run today, yesterday or tomorrow. A release build crashed on launch when Android's code shrinking stripped part of the background-task library — since then every build is launch-tested on an emulator first.
Next projectParent Learning App →