feat: athlete context read tools (profile, sport-settings, summary) #2
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Part of the 0.3.0 coaching-context milestone. Give the AI coach the athlete's
actual configuration and thresholds — currently a blind spot.
Tools
get_athlete_profile—GET /athlete/{id}(+/athlete/{id}/profile) — weight, sex, timezone, prefsget_sport_settings—GET /athlete/{id}/sport-settings— FTP, W', LTHR, HR zones, pace zones, thresholds per sportget_athlete_summary—GET /athlete/{id}/athlete-summary— fitness/fatigue/load overview over a rangeNotes
resolve_caller_credentials(), format viautils/formatting.py.get_sport_settingsoutput enables readiness/intensity reasoning (issue #1).server.py+tools/__init__.py; tests (success + error).Implementation plan (0.3.0) — intended delivery model: Claude Opus 4.8
Branch:
feat/coaching-context(shared across the 0.3.0 issues; one conventionalfeat:commit per issue socz bumpderives 0.3.0).Endpoints (verified against the official OpenAPI spec at
intervals.icu/api/v1/docs)GET /athlete/{id}->WithSportSettings(athlete object with embedded sport settings)GET /athlete/{athleteId}/sport-settings->SportSettings[]GET /athlete/{id}/athlete-summary{ext}->SummaryWithCats[]; query:start,end(dates),tags(array). Empty{ext}returns JSON (same pattern as the existing power-curves tool, which omits ext).New module:
tools/athlete.pyget_athlete_profile()—GET /athlete/{id}. Format: name, sex, weight, timezone, ICU IDs, units prefs. Do NOT dump the embeddedsportSettingsblob (that'sget_sport_settings' job) — summarize as "N sports configured".get_sport_settings(sport: str | None = None)—GET /athlete/{athleteId}/sport-settings, optional client-side filter by sport (each record'stypeslist). Per record, format the coaching-relevant subset of the 61 props:types,ftp,indoor_ftp,w_prime,p_max,power_zones(+names),lthr,max_hr,hr_zones(+names),threshold_pace,pace_units,pace_zones,warmup_time/cooldown_time. Include each record'sid— required input forupdate_sport_settings(#5).get_athlete_summary(start_date, end_date, tags=None)— date-validated viaresolve_date_params; render totals/load per category.Conventions (per CLAUDE.md)
await credentials.resolve_caller_credentials(); all HTTP throughmake_intervals_request; check the{"error": True}shape; return formattedstr.utils/formatting.py(format_athlete_profile,format_sport_settings,format_athlete_summary), conditional-line style likeformat_wellness_entry(null hides the line).server.pyE402 block +__all__andtools/__init__.py(import-side-effect registration).Tests (
tests/test_athlete.py)make_intervals_requestat module level (pattern fromtest_wellness.py); autouse conftest creds fixture gives("i1","testkey").Order & estimate
First issue to land on the branch (its output feeds #1 readiness and #5 writes). ~350 LOC incl. tests.