Repository navigation
v0.2.1 — what a deep review found
A review release. v0.2.0 put the write path in front of a real watch; v0.2.1 is what a deep review of it turned up, each fix with a test that was red without it. It also has a demo video, and the coach's rules finally reach a chat in Claude Code.
uv tool install git+https://github.com/edxleon/runcoach-ai@v0.2.1Nothing reaches the watch twice
- A 502 after Garmin had created a workout, a timed-out calendar answer, a connection dropped after the request went out, and a process that died mid-upload were all read as "nothing was created". The claim was released and the athlete was told to apply again, which put the session on the watch a second time. Failures are now classified by HTTP status first and then by the exception chain, read from the top. Only a connection that was never made counts as "nothing created".
- A proposal clicked after its day had passed was scheduled on that past day. Past sessions are now skipped.
- "Apply again" is no longer advised for a step that may already have happened, on the card, in
doctoror in chat.
A week that fits the calendar it lands on
propose_weekused to add its sessions to whatever was already on the calendar, so one yes could mean two hard sessions on Tuesday and two long runs on Sunday. Now a day that already has an entry gets nothing. A quality session less than 48 h from another hard day, or on the day before the long run, becomes an easy run. Each change is listed on acalendar:line, and every session in the package is listed with its day.- Undoing a red-day swap now also puts the replaced session back on its day. Applying the swap again after that takes it off again, and the summary reports only what actually happened.
- Calendar titles are read as whole words: "Langsamer Dauerlauf" is no longer taken for a long run.
- A week that was only partly applied can now be taken off the watch from the card as well.
Numbers from runs, not from every sport
- Weekly running volume, the "where you stand" comparison and the week planner's size used to count walks and rides: a 90-minute runner could be planned a 480-minute week. They now count runs only. Zone bounds are taken from the last run, not from a ride.
- A steady session asked for by time keeps a 15-minute block (90 minutes used to become one 77-minute block at threshold).
- "Last hard session" is counted from the same day as the number it shows.
The chat gets the coach
- In Claude Code and Claude Desktop the model used to see only the tool descriptions: no 48-hour rule, no energy boundary. Claude Code keeps only 4,096 characters of a server's instructions, so the server now sends the core rules in about 1,900 characters. A new read-only tool,
get_coaching_reference, returns the full rule set, and in practice the model calls it first. get_training_readinessnow syncs first when the last sync is more than 30 minutes old (RUNCOACH_AUTOSYNC_MIN), so a run from this afternoon is no longer invisible to the next "should I train today?".
Privacy
- The bootstrap token no longer reaches any log line.
- The README now says plainly that while
serveruns, other local accounts can reach it. SetRUNCOACH_TOKENon a shared machine. - The release gate now also checks commit author and committer addresses, plus home paths written as dashed or URL-encoded names.
- The server keeps its single-instance lock fresh when it runs for days.
Evals
- The suite has grown from 18 to 25 cases. The new ones cover the 48-hour rule against an athlete who wants intervals, a moved session that no day can take, an unclear apply, a week fitted to a full calendar, "take it back off", unsynced days not read as detraining, and tempo runs that do not count as VO2max work.
- The judge is now
sonnet. Measured:haikugave the same answer PASS once and FAIL once. - One rule was sharpened. "A short easy jog if it's pain-free" is a session built around a symptom.
Verified
- 719 Python tests and 62 frontend tests, on Linux, Windows and macOS with Python 3.12 and 3.13, plus the install-as-a-user job.
- A live chat against a real Garmin account, in which the auto-sync and the coaching reference were both used.
- Evals: the last two full runs after the final prompt change passed 24 of 25 each, and the case that missed was a different one each time. In one of them the judge's own reason calls the result valid. The badge says 24/25.
Not verified yet
- The fitted week and the swap with its undo have only run against the fake Garmin client, not against a real account.
Not affiliated with Garmin. A training tool, not medical advice.