Agent instructions (training decisions, workout naming, calendar sync gotchas) go in CLAUDE.md, the plan's state and the fuelling targets and recipes in docs/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|---|---|---|
| config | ||
| docs | ||
| src/marathonz | ||
| tests | ||
| workouts | ||
| .copier-answers.yml | ||
| .gitignore | ||
| .python-version | ||
| CLAUDE.md | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
marathonz
Running pace and race-time tools, built on Jack Daniels' VDOT, with workout templates synced to intervals.icu.
marathonz vdot 5km 19:10 # VDOT of a race and equivalent race times
marathonz paces # usual reference paces at the current VDOT
marathonz paces marathon "10km+3%" # any pace of the templates syntax
marathonz --vdot 48.3 paces "4:39*95%"
marathonz week # intervals / easy / rests of the current week
marathonz week -1 --type Ride # previous week, for another activity type
marathonz course race.gpx -D marathon marathon 3:05:00 # even-effort splits
Installation
uv tool install --editable .
marathonz link # from the repository, see below
Files follow the XDG base directory specification:
~/.config/marathonz/ # $XDG_CONFIG_HOME/marathonz
├── config.toml # athlete_id = "i…" and vdot = 52.3, or a [test] table
└── .env # INTERVALS_API_KEY=…
~/.local/share/marathonz/ # $XDG_DATA_HOME/marathonz, or -d DIRECTORY
├── 🏃 NSM/ # one subdirectory per intervals.icu library folder
│ └── intervalles-courts.toml
└── 🏃 NSM plan.toml # one file per intervals.icu plan
They are versioned in this repository as config/ (where .env is ignored by
git) and workouts/: marathonz link links the two locations to them, so that
marathonz works from any directory. --vdot overrides the configured VDOT.
Course paces
marathonz course reads a GPX track and prints the paces of an even effort over
the course: per kilometer (with the cumulative time and the waypoints, such as
feed stations), then over each climb and descent. Goals are flat paces in the
paces syntax (marathon by default, 4:20, semi+2%), or finish times
(3:05:00). -D scales the track to the official distance, since GPS tracks
are rarely exact.
The track is resampled every 20 m and its elevation smoothed over 200 m, as raw
GPS elevations count much more climbing than there is. Each segment's pace is
the flat pace times 1 + 0.033·g uphill, 1 + 0.018·max(g, -4) downhill, for a
grade of g%. A waypoint near a road that the course takes twice gets both
passes.
Workout templates
marathonz keeps intervals.icu workouts as local files whose paces are derived
from a VDOT, and pushes them to intervals.icu on demand (e.g. after a test).
# config.toml
athlete_id = "i364734"
[test]
distance = "5km"
time = "19:10"
# 🏃 NSM/intervalles-courts.toml
name = "Intervalles courts"
type = "Run"
description = '''
11x
- 3' {60'+1%}-{60'} Pace intensity=interval
- 1' intensity=rest
'''
Descriptions use the intervals.icu workout builder syntax. Placeholders between
braces are replaced by the maximal pace over a duration ({1h}, {90'}) or a
distance ({10km}, {semi}, {marathon}), by the pace at VO2max ({mas}), or
by a literal pace ({4:39}). Adjustments apply from left to right: *65% for
65% of the speed, +1% for a pace 1% slower, +2' for a pace 2 min/km slower
(e.g. {mas*65%+2'}). Each placeholder is a single pace: ranges join two
placeholders (e.g. {60'+1%}-{60'}).
marathonz week classifies the planned steps by intensity: interval steps are
intervals, rest steps are rests, and everything else is easy running.
The API key is read from the INTERVALS_API_KEY environment variable, or from a
.env file in the current directory, one of its parents, or the configuration
directory.
marathonz pull "🏃 NSM" # bootstrap from an existing folder
marathonz render # preview the computed paces
marathonz sync --dry-run # show the diff with intervals.icu
marathonz sync --calendar # update the library and planned workouts
Plans
A TOML file at the root of the workouts directory is an intervals.icu plan, named
after the file. It lists workouts week by week, from Monday to Sunday, with ""
for rest days. Workouts can come from any folder, as long as their names are
unique:
# 🏃 NSM plan.toml
weeks = [
["Jog", "Intervalles courts", "", "Intervalles moyens", "", "Jog", "Sortie longue"],
]
marathonz sync creates the plan and keeps its workouts identical to the
templates, matched by day: plan workouts on rest days are deleted. Plans are
applied to the calendar from intervals.icu, after which sync --calendar keeps
the planned workouts up to date.