Skip to content

v0.2.1 — what a deep review found

Choose a tag to compare

@edxleon edxleon released this 28 Oct 18:59
· 116 commits to main since this release

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.1

Nothing 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 doctor or in chat.

A week that fits the calendar it lands on

  • propose_week used 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 a calendar: 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_readiness now 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 serve runs, other local accounts can reach it. Set RUNCOACH_TOKEN on 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: haiku gave 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.