Skip to main content

easy-or-not

Are your easy runs actually easy?

Most runners who stop improving are not lazy. They run almost everything at the same medium effort, too hard to recover from and too easy to make them faster. This tool reads your own runs and tells you how much of your time went where, how much of your "easy" running drifted into the middle, whether you are getting faster at the same heart rate, your training load from week to week, and how ready you are to train today.

It was built for watches like the Vivoactive 5, which record every heartbeat, overnight HRV and sleep, but leave Training Load and Training Readiness to Garmin's more expensive models.

It works on FIT files you have exported, or straight from your account with a Garmin Personal API key. Everything runs on your machine. Your data and your key never leave it.

30 runs, heart-rate bands from your Garmin running zones
  easy below 154 bpm   middle 154-172 bpm   hard 173+ bpm

Where your running time went
  easy     47%  ██████████████░░░░░░░░░░░░░░░░
  middle   27%  ████████░░░░░░░░░░░░░░░░░░░░░░
  hard     25%  ████████░░░░░░░░░░░░░░░░░░░░░░
  A common target is around 80% easy with the rest mostly hard.

Your easy runs (18 of 30, sessions excluded)
  44% of easy-run time was in the middle band.
    Thu 08 Oct    32 min    68% middle  (treadmill)
    Mon 14 Sep    32 min    65% middle  (outdoor)
    Sun 04 Oct    32 min    56% middle  (outdoor)

Same heart rate, faster? (outdoor easy runs only)
  1.40 -> 1.43 metres per heartbeat (+2.5%).
  Higher means you cover more ground for the same effort.

Training load (heart-rate minutes, weighted 1 to 5 by zone)
  Last 7 days to Thu 22 Oct: 412
  Your average week over the last 4: 380
  Ratio 1.08: in line with your recent weeks.

(Example output from synthetic data.)

Install

Python 3.12 or newer.

uv tool install easy-or-not
# or: pipx install easy-or-not

Use it with your Garmin account

easy-or-not setup    # once: paste your Personal API key
easy-or-not          # your last 8 weeks of runs
easy-or-not garmin --days 90
easy-or-not readiness   # today's readiness and the last 7 nights

setup tells you where to create the key in Garmin Connect (Settings, Personal API Token), reads it without showing it on screen, saves it to ~/.config/garmin/connect-personal-api-key readable only by you, and checks it with Garmin.

Authentication is handled by Garmin's official Python client, which also reads GARMIN_PERSONAL_API_KEY if you prefer an environment variable. Original activity files are cached in ~/.cache/easy-or-not, so later runs only download new activities. Your heart-rate zones are read from your Garmin settings.

Use it with exported files

In Garmin Connect on the web, open an activity, click the gear icon and choose Export Original. Point the tool at the files or the folder:

easy-or-not --max-hr 192 files ~/Downloads/runs/

Without the API there are no Garmin zones to read, so pass your max heart rate.

What it measures

Bands. Easy, middle and hard come from your heart-rate zones. By default easy is zones 1 and 2, middle is zone 3, hard is zones 4 and 5. Garmin's default zones start zone 3 at 70% of max HR, which is stricter than the roughly 80% easy ceiling used in polarised-training research. If you are on Garmin's defaults and everything looks "middle", try --easy-up-to 3. With --max-hr, the bands are below 80%, 80 to 90%, and above 90% of max.

Easy runs. Any run with less than 10% of its time in the hard band. That is a session-free run, whatever you meant it to be.

Efficiency. Metres covered per heartbeat while in the easy band, ignoring the first five minutes while heart rate catches up. The tool compares the median of your first third of outdoor easy runs with your last third. It needs at least six.

What gets left out. Activities with under 10 minutes of heart-rate data (a GPS test, a watch started by accident), and walks logged as runs (median cadence under 140 steps per minute). A walk home or a watch left recording after the run is trimmed off the end, so it does not count as easy running. The report says how many were left out and why.

Zones that look too low. If you held a median heart rate in zone 5 for half an hour or more, the report says your zones are probably set too low rather than telling you that you ran half an hour flat out.

Training load. Each run's load is its Edwards TRIMP: minutes in each heart-rate zone multiplied by the zone number, so a minute in zone 5 counts five times a minute in zone 1. The report compares the last 7 days with your average week over the last 4 (it needs 4 weeks of runs). Below 0.8 is lighter than usual, 0.8 to 1.3 is in line, 1.3 to 1.5 is a step up, above 1.5 is a big jump. Runs under 10 minutes still count towards load; walks do not. From your Garmin account, load is measured up to today, so a week off shows as a week off. It is a heart-rate estimate, not Garmin's Training Load, and it is only as right as your zones.

Readiness. With your Garmin account, the report ends with a readiness check for today, and easy-or-not readiness shows it with the last 7 nights. It rates four signals against your own normal:

Signal Off Well off
Overnight HRV above Garmin's balanced range for you below it
Resting HR 3 to 4 bpm above your 4-week median 5 or more above
Sleep Garmin sleep score under 60, or under 6 hours with no score
Training load ratio 1.3 to 1.5 above 1.5

Nothing off means good to train, a little off means go easy, more than that means rest or keep it very easy. A night with no data (watch off or charging) is shown as missing, not counted against you. This is a transparent estimate built from the same kinds of data, not Garmin's Training Readiness score, whose weightings are not public.

Pauses. Gaps of more than 10 seconds between samples (traffic lights, a stopped watch) are not counted.

Limits

  • Treadmill pace is an estimate. Indoors, the watch works out speed from your wrist, so treadmill runs count towards time in zone but are left out of the efficiency trend.
  • Heart rate is only as good as the sensor. Wrist HR can lock on to cadence, especially in the first few minutes or in the cold. A chest strap gives cleaner numbers.
  • Your zones decide the answer. If the max heart rate in your Garmin settings is a guess, the bands are too. If you know your real max (from a race finish or a hard hill effort), pass --max-hr.
  • It describes, it does not coach. "44% of your easy running was in the middle" is a fact about your data. What to do about it is up to you.

Development

uv venv && uv pip install -e '.[dev]'
uv run pytest -q
uv run ruff check .

The tests build real FIT files in memory, so nothing personal is committed. *.fit, *.zip and key files are git-ignored.

Licence

MIT. Not affiliated with Garmin.

Metadata

Release files for easy-or-not 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for easy-or-not 0.2.0
File Size Uploaded Provenance
easy_or_not-0.2.0.tar.gz 28.5 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for easy-or-not 0.2.0
File Interpreter ABI Platform
easy_or_not-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 54.7 kB

Release files / easy_or_not-0.2.0.tar.gz

Download URL easy_or_not-0.2.0.tar.gz
Size 28.5 kB
Tags Source
SHA-256 checksum
How to use checksums
ec2e3216a0e2af72c687b835b712efeff240f8cae858775bc636ed75861808be
BLAKE2b-256 checksum
How to use checksums
410defdac986396d29b7b8901fa98fd772c2749c8725c297b47d96c07dfe9fef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / easy_or_not-0.2.0-py3-none-any.whl

Download URL easy_or_not-0.2.0-py3-none-any.whl
Size 26.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
add2e2510515b439fe9f952ecd042e7752170ef95813beeb1b8808af3d4ef91a
BLAKE2b-256 checksum
How to use checksums
79914e792637cc078f391223bdb04a03a3034ec0a6c47ef5930cdd1e111e60d2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Security for easy-or-not 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for easy_or_not-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page