Skip to content

Training Recommendation Engine

Built 2026-04-30 as Build 2 of the Garmin + Hevy integration plan (reference_garmin_workout_integration.md).

Files

  • forge/scripts/forge_training_recommendation.py — engine + CLI
  • forge/data/training_thresholds.json — tunable threshold table (edit values, no code change)
  • Bot tool training_recommendation_today (no params), wired into forge_telegram_inbox_brain.py (registered on capture + coordinator personas)

What it does

  1. Pulls live wellness from /context?about=wellness&window=24h (Garmin readiness, HRV Δ7d, body battery, stress, recovery_time_hours, ACWR, training status, sleep)
  2. Pulls last 14 days of Hevy sessions from forge_hevy_read._load_workouts() for days-since-lift + per-muscle-group freshness
  3. Picks a band from data/training_thresholds.json (default: ≥80 push, 60-79 maintain, 40-59 pull_back, <40 rest)
  4. Adjusts the band based on signal corrections (HRV down ≥10 → step down; stress ≥50 → step down; body battery ≤30 → step down; recovery_time ≥12h → step down; HRV up ≥8 → step up)
  5. Suggests a stale muscle group (default: any group not trained in 4+ days)
  6. Calls Sonnet for a 1-2 sentence personalized rationale (em-dashes stripped via forge_text_sanitize.strip_em_dashes); falls back to band's default blurb if Sonnet unavailable

Usage

# CLI human-readable
~/forge/scripts/integrations/.venv/bin/python ~/forge/scripts/forge_training_recommendation.py

# CLI JSON (full structured output)
~/forge/scripts/integrations/.venv/bin/python ~/forge/scripts/forge_training_recommendation.py --json

# Skip Sonnet (rule-based blurb only, no quota burn)
~/forge/scripts/integrations/.venv/bin/python ~/forge/scripts/forge_training_recommendation.py --no-sonnet

Bot trigger phrases: "should I lift today", "how should I train", "am I recovered", "what should today's workout look like".

Tuning

Edit data/training_thresholds.json directly. Schema:

  • readiness_bands[] — ordered descending by min, with label + blurb
  • hrv_delta_downgrade_ms / hrv_delta_upgrade_ms — Δ7d HRV thresholds for band shift
  • stress_high_threshold — Garmin stress avg above which to step down
  • body_battery_low — body battery threshold for step down
  • recovery_time_block_hours — Garmin recovery_time hours that downgrades the call
  • muscle_group_freshness_days — days a muscle group must be unworked to be flagged "stale"

Dependencies

Requires Build 1 fields (Garmin gap-fill ingestion). Without recovery_time_hours / acwr_ratio etc the engine still works but loses the load-management adjustments. Garmin poller must have run at least once today; ha_poller must have run within 15 min for fresh /context reads.

[Claude Code, Build 2 of Garmin + Hevy plan]