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 + CLIforge/data/training_thresholds.json— tunable threshold table (edit values, no code change)- Bot tool
training_recommendation_today(no params), wired intoforge_telegram_inbox_brain.py(registered on capture + coordinator personas)
What it does¶
- Pulls live wellness from
/context?about=wellness&window=24h(Garmin readiness, HRV Δ7d, body battery, stress, recovery_time_hours, ACWR, training status, sleep) - Pulls last 14 days of Hevy sessions from
forge_hevy_read._load_workouts()for days-since-lift + per-muscle-group freshness - Picks a band from
data/training_thresholds.json(default: ≥80 push, 60-79 maintain, 40-59 pull_back, <40 rest) - 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)
- Suggests a stale muscle group (default: any group not trained in 4+ days)
- 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 bymin, withlabel+blurbhrv_delta_downgrade_ms/hrv_delta_upgrade_ms— Δ7d HRV thresholds for band shiftstress_high_threshold— Garmin stress avg above which to step downbody_battery_low— body battery threshold for step downrecovery_time_block_hours— Garmin recovery_time hours that downgrades the callmuscle_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]