Use the first time a user connects to Koval, when their FTP / threshold pace / CSS is unset, or when they ask to "set up my profile", "onboard me", "tell Claude about my training", "configure my athlete preferences", "I'm new here". Conducts a structured interview about goals, weekly availability, preferred workout style, recovery rules and communication preferences, then writes athlete-profile.md that every other Koval athlete skill (koval-plan-my-week, koval-find-workout, koval-prep-race, koval-analyze-last-ride, koval-form-check) reads as ground truth so generated plans match the athlete's real life instead of generic Coggan defaults.
getMyProfile returns null FTP / threshold / CSS for the user's primary sportRole gate: Run only if getMyProfile().role == "ATHLETE". If COACH, reply: "Looks like you're a coach — run koval-coach-onboarding instead to capture your coaching philosophy."
Produce (or update) an athlete-profile.md file that captures how this specific athlete actually trains and lives — available days, max session length, goals, preferred workout style, recovery rules, voice — so every other Koval athlete skill can read it and generate plans that fit the athlete's real schedule and preferences instead of falling back to defaults.
The canonical schema for the output file ships with this skill at resources/athlete-profile.template.md. Treat it as the source of truth for section names and ordering.
Gate + context (parallel reads):
getMyProfile → role (must be ATHLETE), name, FTP, weight, threshold pace, CSS, CTL/ATL/TSBlistGoals → pre-fill any goals already setlistZoneSystems → detect whether zones are configuredCheck for an existing profile:
athlete-profile.md already exists, ask: "You already have a profile from <date>. Do you want to review and update it section by section, start over, or just show it?"athlete-profile.draft.md exists, offer to resume from where the previous interview left off.Threshold backstop — for the athlete's primary sport, if FTP (cycling) / threshold pace (running) / CSS (swimming) is null, hand off to koval-zone-setup first, then resume here. Same trigger the existing Angular OnboardingComponent uses for web users.
Interview — ask the questions in grouped batches (not one-by-one). Wait for the athlete's answer before moving on. Always offer "skip / use defaults" per group.
searchRaces and createGoal if yes)getDefaultZoneSystem(sport))Persist anything we can to the backend:
updateFtp(ftp), updateWeight(weightKg), updateThresholdPace(secondsPerKm), updateSwimCss(secondsPer100m).createGoal(title, sport, priority, raceDate, raceId, notes). If a race was found via searchRaces, linkRaceToGoal(raceId, goalId).createZoneSystem(...) with Coggan defaults, or hand to koval-zone-setup.athlete-profile.md — the MCP User model has no free-form preferences field.Compile + save the profile as athlete-profile.md in the same skills folder this skill lives in. Use resources/athlete-profile.template.md as the structural template — copy the headings verbatim, fill in every placeholder, and write _(using defaults)_ in any group the athlete chose to skip.
Show the result as a markdown card and ask: "Want to tweak anything? Tell me a section name (e.g. 'change Group 3') or say 'looks good' to lock it in."
athlete-profile.mdThe output file follows the exact schema in resources/athlete-profile.template.md. Open the template, copy its structure verbatim, then fill in each placeholder.
koval-coach-onboarding._(using defaults)_ in that section so the file is still complete.Last updated.athlete-profile.draft.md so the athlete can resume later with "continue my onboarding".koval-plan-my-weekkoval-form-checkkoval-prep-racekoval-find-workout