No description
Find a file
mog a747de4e27 Document the Nantes marathon plan and the fuelling targets
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>
2026-10-25 22:31:45 +01:00
config Read the configuration and workouts from XDG locations 2026-10-25 11:21:03 +01:00
docs Document the Nantes marathon plan and the fuelling targets 2026-10-25 22:31:45 +01:00
src/marathonz Add a course command for even-effort paces from a GPX track 2026-10-25 22:26:27 +01:00
tests Add a course command for even-effort paces from a GPX track 2026-10-25 22:26:27 +01:00
workouts Add fuelling targets to the NSM marathon long runs and races 2026-10-25 22:26:27 +01:00
.copier-answers.yml Update template to 0.1.6 2026-10-15 21:41:58 +02:00
.gitignore Read the configuration and workouts from XDG locations 2026-10-25 11:21:03 +01:00
.python-version Update template to 0.1.6 2026-10-15 21:41:58 +02:00
CLAUDE.md Document the Nantes marathon plan and the fuelling targets 2026-10-25 22:31:45 +01:00
LICENSE Create a skeleton from template via Copier 2026-10-15 08:37:23 +02:00
pyproject.toml Merge the CLI tools into marathonz subcommands 2026-10-25 11:11:14 +01:00
README.md Add a course command for even-effort paces from a GPX track 2026-10-25 22:26:27 +01:00
uv.lock Merge the CLI tools into marathonz subcommands 2026-10-25 11:11:14 +01:00

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.