runcoach
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| RUNCOACH_TZ | No | IANA zone for 'which day was this run' | system zone |
| RUNCOACH_LOG | No | Log level — set INFO or DEBUG to watch a sync. INFO and DEBUG also log every HTTP request of the web app | WARNING |
| RUNCOACH_HOME | No | Data directory | ~/.runcoach |
| RUNCOACH_MODEL | No | Model for coach cards | CLI default |
| RUNCOACH_TOKEN | No | Required for --host 0.0.0.0 (phone in your home network) | |
| RUNCOACH_QUOTA_WAIT_S | No | How long a job waits for subscription quota | 3600 |
| RUNCOACH_GARMIN_TOKENS | No | Reuse an existing python-garminconnect token dir | ~/.runcoach/garmin |
| RUNCOACH_JOB_TIMEOUT_S | No | Hard timeout for a single coach job | 600 |
| RUNCOACH_LT_HISTORY_DAYS | No | How far back the lactate-threshold history is fetched | 180 |
| RUNCOACH_ACTIVITY_BACKFILL_DAYS | No | Minimum window of workouts a sync fetches (the ACWR fallback needs ~28 days) | 35 |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| get_training_readinessA | Today's readiness verdict GO / EASY / REST with the signals behind it (HRV status, sleep score, Body Battery, resting HR vs 27-day baseline, ACWR, days since the last hard workout). Rule-based and conservative. START HERE for "should I train today?". Flags stale data explicitly. |
| get_recovery_summaryA | Averages of sleep, HRV, resting HR, stress, Body Battery and steps over the last N days plus a snapshot of the latest day. Use for "how has my recovery been?". Aggregates only — never a day-by-day list. |
| get_daily_metricsA | Every recorded recovery value for ONE day (default: latest day with data). Use when a single night/day is in question, not for trends. |
| get_trendA | Weekly averages of ONE recovery metric over the last N days — for "is my HRV / resting HR / sleep trending up or down?". |
| get_training_loadA | Training-load picture: ACWR with its SOURCE (Garmin's EWMA ratio, or a self-computed fallback that is less reliable), Garmin training status, VO2max with change, and weekly load buckets. VO2max change is only reported when the value actually varied (Garmin carries the last value forward). |
| get_recent_activitiesA | Workout digest: totals per sport plus the latest workouts, each run classified Quality / Long Run / Easy (from training effect and duration). Use to see what was actually trained before recommending the next session. |
| get_intensity_distributionA | Time in heart-rate zones across all runs (easy Z1-2 / moderate Z3 / hard Z4-5 / Z5) with percentages — the basis for the 80/20 polarisation question. States how many runs have zone detail, so an incomplete picture is visible. |
| analyze_workoutA | Deep dive into ONE run: time in each HR zone, interval structure (rep count, rep length, work vs recovery HR), weather, performance condition, plus rule-based notes. Default: the latest run with detail. The interval structure is Garmin's auto-detection — if the athlete states a different structure, the athlete is right. |
| get_vo2max_historyA | VO2max over the last 8 weeks as STEPS (only the days the value really changed — Garmin carries it forward in between) plus a descriptive comparison of the last 28 days with the 28 before (distance, Z5 minutes, easy share, temperature). Use for "why is my VO2max moving?". Descriptive, not causal. |
| sync_garminA | Pull the latest days and workouts from Garmin Connect NOW. Call this first when today's run or last night's sleep is missing. Takes 10-40 s. Read-only towards Garmin; writes only to the local database. |
| propose_workoutA | Build a structured session for the athlete's route or time budget and file
it as a PROPOSAL - warm-up, work reps with targets, recovery jogs, cool-down -
sized so the whole thing adds up to the route. Targets come from the
athlete's own Garmin zones; anything not measured is listed as an assumption.
Use when the athlete asks for a workout ("plan me intervals for my 10 km",
"an easy 45 minutes", "a threshold session") or when the readiness verdict
calls for a different session than the one on the calendar.
Kinds: easy/long (one capped step), threshold (Z4 reps), vo2max (Z5 reps),
steady (>= 12 min even effort at threshold - the only shape Garmin measures
VO2max from). |
| propose_weekA | Build a polarised training week and file it as ONE proposal: a VO2max session and a threshold session 48 h apart, the long run on its weekday, easy runs between, nothing hard the day before or after the long run, at least one rest day. Sizes come from defaults (50/55/45/90 min), targets from the athlete's own zones. Use when the athlete asks for their week ("plan my week", "what should next week look like"). What the calendar already holds in that week is listed - the package ADDS to it. Returns the preview of every session and one proposal id; apply_workout with that id puts the whole week on Garmin after the athlete's yes. Nothing is written here. |
| apply_workoutA | WRITE a proposed session to the athlete's Garmin account: upload the workout, schedule it on the proposal's day, push it to the watch, then read it back and verify structure and targets. Call ONLY after the athlete has seen the preview and explicitly agreed - a request ("plan me 10 km") is not agreement, "yes, put it on the watch" is. Not available to the app's own card runs; there the athlete clicks. Returns what is now on Garmin, with any warning (not pushed because the watch is offline; a mismatch found on read-back). A proposal can be applied once; an unknown or used id says so and lists the open ones. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 13 tools
Each tool serves a distinct purpose: specific metric retrievals (vo2max, trend, load, activities, intensity, daily, readiness, recovery), a workout deep-dive, two proposal generators, one apply action, and a sync function. There is no meaningful overlap; even similar 'get' tools focus on different data slices (e.g., single metric trend vs. multi-metric summary).
All tool names follow a consistent snake_case pattern with a clear verb prefix (get_, sync_, analyze_, propose_, apply_) and a descriptive noun. The verbs map cleanly to actions (get for reads, propose for plans, apply for writes), making the API predictable and self-documenting.
With 13 tools, the server covers the full coaching lifecycle without bloat. Each tool addresses a distinct piece of the workflow—data ingestion, metrics retrieval, analysis, planning, and execution—so the count feels appropriate for the stated domain.
The tool surface covers the entire coaching loop: syncing data, reading all key metrics and trends, analyzing individual workouts, generating single-session and weekly proposals, and applying them to Garmin. No obvious gaps exist for a personal coaching use case, including readiness and recovery checks that guide recommendations.