Wellness Project - Fitness AI - MCP

Connect Apple Health, Fitbit, Oura, and Google Health Connect to Claude, ChatGPT, Grok, and Mistral.

Community: Submitted by a user or imported; check the owner before granting accessOnlineNo sign-inGlobalFreeCan modify data

What it can do

  • Log Meal: Log a meal to the user's food diary. Use when the user mentions eating, describes a meal, or asks to log food. INFER — do not ask: - date: today, or from context ("yesterday", "last night")
  • List Meals: List all meals logged for a date or date range, including each meal's ID, date, type, food description, and macros. Use this before update_meal or delete_meal to find the correct meal ID.
  • Update Meal: Update one or more fields on an existing meal entry. Use when the user wants to correct or change something already logged. REQUIRED WORKFLOW: always call list_meals first to get the meal

What data it sees

Do you need an account

No: the server works without sign-in

Connect Apple Health, Fitbit, Oura, and Google Health Connect to Claude, ChatGPT, Grok, and Mistral. Wellness Project is a hosted MCP server: your devices sync into one account, and your AI reads your workouts, sleep, nutrition, and recovery in plain English. No exports, no CSV wrangling, no copy-paste, and nothing to self-host.

Most health services ship no MCP server of their own. There is no official Fitbit MCP server, no Oura MCP server, no Hevy or TrainingPeaks MCP server, so an AI assistant cannot read that data on its own. The community repos that fill the gap are yours to run, refresh tokens for, and keep alive. Wellness Project is the hosted alternative. You connect your devices once over OAuth and the endpoint stays connected across every conversation.

What you can ask once it is connected:

  • "How did my training look this week?"
  • "Show my sleep for the last month."
  • "How is my bench progressing?"
  • "Log today's lunch: chicken burrito bowl, about 700 calories."
  • "What was my resting heart rate trend against my HRV this quarter?"
  • "Which muscle groups have I been neglecting?"

60 tools across three kinds:

  • Read tools pull your logged and synced history: workouts and individual sets, meals and macros, sleep stages, runs, steps, body metrics, resting heart rate and HRV, lab results, injuries, supplements, cycle tracking, wellbeing check-ins, and rest days.
  • Write tools log new entries by voice or text, so you can record a workout or a meal without opening the app.
  • 11 chart widgets render an interactive inline graph instead of a wall of numbers, each with a 7d/30d/90d/1y toggle and hover tooltips.

Technical details:

  • Endpoint: https://wellnessproject.ai/api/mcp
  • Transport: streamable HTTP
  • Auth: OAuth 2.0 with dynamic client registration and PKCE. No API key to paste, no token to rotate by hand.
  • Scoped to the signed-in user's own data. Every tool call is bound to the account that authorized the connection.
  • Works with any MCP client. Tested against Claude, ChatGPT, Grok, and Mistral Le Chat.

Wellness Project is a free AI health app, and the connector is free during early access. Create an account at https://wellnessproject.ai, connect a device under Settings, then add https://wellnessproject.ai/api/mcp as a custom connector in your AI client.

Tool catalog, schemas, and setup guides: https://github.com/turnnoblindeye/wellness-project-mcp

Server tool list (59)

Raw names from tools/list. Only developers need these.

log_mealLog a meal to the user's food diary. Use when the user mentions eating, describes a meal, or asks to log food. INFER — do not ask: - date: today, or from context ("yesterday", "last night") - meal_type: from time of day (midnight-5am=Snack, 5am-10am=Breakfast, 10am-2pm=Lunch, 2pm-5pm=Snack, 5pm-10pm=Dinner, 10pm-midnight=Snack) or context ("post-workout shake"=Post-Workout); see mealTypeForHour in src/lib/mealTypes.ts for the canonical mapping - calories, protein_g, fat_g, carbs_g: ALWAYS estimate these from the food description before calling — a meal must never be logged without macros, and never ask the user for them BRAND NAMES: for a branded, restaurant, or specific product (e.g. "Chipotle chicken bowl", "Clif Bar Chocolate Chip"), look up published macros for that product before falling back to a generic estimate; match the size/variant mentioned, or assume a standard serving. ASK the user only if food_items are entirely absent. Never call this tool without calories and macros populated. FASTING: if the user ate nothing / fasted all day, log a single entry with food_items "Fast day" and calories/protein_g/fat_g/carbs_g all 0 (meal_type "Snack"). Records a real 0-calorie day for calorie/TDEE math, distinct from a day with no log at all. DUPLICATES: if this tool returns a duplicate error, tell the user what's already logged and ask whether this is a separate serving (call again with force=true) or should update the existing entry instead (call update_meal with the adjusted values).
list_mealsList all meals logged for a date or date range, including each meal's ID, date, type, food description, and macros. Use this before update_meal or delete_meal to find the correct meal ID. Also useful to answer "what did I eat today/this week/yesterday?" or to review what has been logged. Maximum range: 31 days per call. For longer periods, make multiple calls with sequential date ranges. INFER — do not ask: - date: default to today - end_date: if the user asks about a week or range, set end_date to cover the full period (e.g. "this week" → date=Monday, end_date=today; "last 7 days" → date=7 days ago, end_date=today). For a single day, omit end_date.
update_mealUpdate one or more fields on an existing meal entry. Use when the user wants to correct or change something already logged. REQUIRED WORKFLOW: always call list_meals first to get the meal ID — never guess or invent an ID. Only send the fields that need to change; omit all others. ASK the user if their intent is ambiguous about which meal to update (e.g. multiple meals of the same type on one day).
delete_mealPermanently delete a meal entry. Use when the user explicitly asks to remove or delete a logged meal. REQUIRED WORKFLOW: always call list_meals first to confirm the meal ID. This action is irreversible — if the user's intent is ambiguous (e.g. "remove that meal" without specifying which), confirm which meal before deleting.
list_exercisesReturns all canonical exercise names from the exercise library, grouped by muscle group. Call this before log_workout or update_workout to match user-described exercise names to canonical ones. Canonical names ensure proper exercise tracking and NSI score calculation.
log_workoutLog a complete workout session: exercises, sets, reps, weights, and session metadata. Use when the user describes finishing a workout, lists exercises performed, or asks to log training. EXERCISE NAMES: - Call list_exercises first; match each exercise to the closest canonical name. No reasonable match → use the name as stated. Don't ask before logging, match silently and log. - "Chest press" (machine) and "bench press" (barbell) are DISTINCT — pass the user's term through so the resolver's aliases pin the right one. - name is ONLY the exercise name, never reps/weights/sets — those go in the sets array. - LITERAL NAME: literal_name: true keeps the user's exact wording instead of the closest library match, skips the resolver, and gets no NSI score (no benchmark to compare an unmatched name against). Use for "call it exactly X", "not the standard one", "literally X", or a rejected match. - The result says when a name was matched to something other than what the user said. Relay it in your own words rather than repeating the line verbatim. If a name matches nothing closely enough, the result names near-miss library exercises; ask the user which they meant rather than accept the unscored custom log silently. - EQUIPMENT (load basis): dumbbell_pair is one dumbbell in EACH hand, weight_lb PER HAND (2x for NSI); dumbbell_single is one implement total. Laterality (single-leg/arm) does NOT decide this alone. Set it when the user describes the load (each hand, machine, band); a wrong or missing tag silently halves or doubles NSI. Values: barbell, dumbbell_pair, dumbbell_single, machine, kettlebell, bodyweight, band, cable, trx, other. SETS: - "3 sets of 15 reps" → 3 set objects with reps: 15. "15/12/10" → 3 sets with reps 15, 12, 10. - Pure isometric holds (planks, dead hangs, wall sits) have no reps: "30 second plank" = { hold_length_sec: 30 }. - Tempo/pause work combines reps + weight_lb + hold_length_sec (seconds per rep) on the same set, never in notes. - Loaded carries (farmers carry, sled push, weighted plank) are one set per trip: hold_length_sec + weight_lb, omit reps unless a trip count is given. weight_lb is PER HAND for a two-implement carry, TOTAL for one implement. Distance has no column and is never a duration — put it in notes. INFER — do not ask: - date: today, or from context - focus_type: from the exercises (bench/shoulders/triceps=Push, rows/pulldowns/curls=Pull, squats/deadlifts/lunges=Legs, mixed upper=Upper, everything=Full Body) - is_bodyweight: true for pull-ups, push-ups, dips, bodyweight squats - superset_group: same integer for exercises done back-to-back or as a superset - slot_type: 'warmup' for prep at the start, 'finisher' for burnout/cardio at the end, 'working' (default) otherwise RPE (Rate of Perceived Exertion) — 1-10 scale: - Session-level RPE: overall session difficulty. Infer from user comments like "brutal session" (8-9) or "easy day" (3-4). Optional. - Per-set RPE: how hard each individual set felt. Include only if the user explicitly mentions per-set effort or failure. Optional. - Scale: 1=minimal effort, 5=moderate, 7=hard, 8=few reps left, 9=one rep left, 10=maximal/failure. ASK (single batched question) only if missing and not inferable: location, focus_type (list ambiguous), heart_points (tracker provides them but not mentioned). RETURNS the new session's ID (as "[ID NN]"). Pass it to update_workout / delete_workout / get_workout / add_exercises for follow-ups in this conversation.
list_workoutsList workout sessions in a date range: ID, date, focus type, location, and session-level NSI with rating. Use before get_workout to find a session ID, or to answer "how many times did I train this week?", "when was my last leg day?", "did I work out yesterday?", "how is my NSI trending?". Each row's NSI is the mean of per-exercise NSIs (after dropping anything below 50% of the user's median for that exercise), with a rating band (Below Average, Novice, Average, Intermediate, Advanced, Elite). 100 = the population intermediate standard for the user's bodyweight, age, and sex. Use the rolling average across rows for trend questions. Maximum range: 90 days per call. For longer periods (PR lookups, "have I ever done X", "when was the last time I did Y"), make multiple sequential calls walking backwards (days 0-90, then 90-180, then 180-270...) until you find what you need. Don't give up after one call. INFER — default start_date to 7 days ago, end_date to today. Widen up to 90 days for trend questions. Chain calls for anything older.
get_workoutRetrieve full detail of a workout session: exercises, sets, reps, weights, superset groupings, heart points, notes, and NSI scoring at every grain. Use for detailed questions about a past workout, reviewing training before recommendations, confirming what was logged, or comparing a session to population strength standards. NSI: session NSI/rating in the header; per-exercise NSI (max set NSI), rating, est. 1RM, and the population_1rm_lb/population_reps benchmark it was measured against; per-set NSI and est. 1RM to see which set drove the exercise score. EQUIPMENT: shown per exercise when every set shares a tag, else per set; missing means untagged. A wrong or missing tag on a dumbbell exercise silently halves or doubles its NSI score — fix it via update_workout's set_updates or add_exercises equipment field. REQUIRED WORKFLOW: call list_workouts first to find the session ID — never guess it.
get_exercise_historyLook up everything the user has done for ONE exercise: all-time PR plus recent performance, across many sessions. USE FOR: - PR lookups — "what's my bench PR?", "have I ever squatted 315?". Returns the est. 1RM PR and the exact set it came from (date, weight, reps, RPE, banded vs unbanded, superset siblings, notes), plus rep-range bests (1RM/3RM/5RM/10RM). Banded and unbanded PRs are shown side-by-side when both exist. - Recent-activity questions — "how has my squat been lately?", "when did I last deadlift?". Returns the most recent N sessions containing the exercise, formatted like get_workout. - Trend questions — "am I getting stronger on incline DB press?". Includes a one-line delta of current best vs ~30-90 days ago. NOT for a full session (every exercise in one workout — use get_workout) or a date-window list regardless of exercise (use list_workouts). INFER — do not ask: exercise_name (take the user's words; resolves to canonical, or says so if never logged), recent_limit (default 10 sessions), since_date (optional — narrows only the Recent block; the PR is always all-time).
delete_workoutPermanently delete a workout session and all its exercises and sets. Use when the user wants to remove a logged workout entirely. REQUIRED WORKFLOW: call list_workouts first to confirm the session ID — never guess it. This action is irreversible and removes the session, all supersets, and all sets. If the user's intent is ambiguous, confirm which session before deleting.
update_workoutUpdate a workout session: correct metadata, fix set values, rename/add/remove exercises or individual sets, or move exercises between supersets. Use for any post-log correction. REQUIRED WORKFLOW: 1) list_workouts for the session ID. 2) get_workout for full detail (set_id values, exercise names, slot names SS1/SS2/WarmUp/Finisher). 3) If adding or renaming, list_exercises first for the canonical name. 4) Call with only the fields that change — operations can combine in one call. OPERATIONS: - Metadata: date, focus_type, location, notes, rpe, heart_points_moderate/peak. - set_updates: patch reps/weight/notes/equipment on sets by set_id. - remove_sets: delete sets by set_id; remaining sets renumber; an emptied exercise/slot is removed automatically. - rename_exercises: renames every set of an exercise in place (preserves set IDs, RPE, notes; rebuilds NSI), never remove + add. - remove_exercises: deletes all sets for named exercises; empty slots removed automatically. - add_exercises: new exercises with sets; to_superset_slot joins an existing slot, omit for standalone. - move_exercises: reassigns an exercise to a different slot; "new" makes it standalone. SUPERSET SLOTS: rename_exercises/remove_exercises match by exercise name alone unless scoped. If a name is in more than one slot and the user means only one, pass superset_slot (or { name, superset_slot } for remove_exercises) naming that slot from get_workout. Omitting it hits every occurrence, a real corruption risk. LITERAL NAME: literal_name: true keeps the user's exact wording instead of the closest library match, skips the resolver, and gets no NSI score (no benchmark to compare an unmatched name against). Use for "call it exactly X", "not the standard one", "literally X", or a rejected match. Applies below. EQUIPMENT (load basis): dumbbell_pair is one dumbbell in EACH hand, weight_lb PER HAND (2x for NSI); dumbbell_single is one implement total. Laterality (single-leg/arm) does NOT decide this alone. Set it when the user describes the load (each hand, machine, band); a wrong or missing tag silently halves or doubles NSI. Values: barbell, dumbbell_pair, dumbbell_single, machine, kettlebell, bodyweight, band, cable, trx, other. The result discloses a mismatched name from rename_exercises/add_exercises; relay it in your own words. If a name matches nothing closely enough, the result names near-miss library exercises; ask the user which they meant rather than accept the unscored custom log silently. INFER — do not ask: session, set_id, slot names (get_workout/list_workouts), canonical names (list_exercises).
log_wearableLog daily wearable metrics (RHR, HRV, Zone Minutes / AZM, VO2max, calories eaten / dietary energy, stress, and supplemental steps). STEPS — read before using step_count: manual step_count is ADDITIVE — it adds on top of whatever a connected wearable (Fitbit, Oura, Apple Health, Health Connect) already recorded that day; it never replaces or overrides device data. Only use it when the user explicitly says they walked steps their device did NOT capture (phone left home, battery died, device not worn). If the user says sync is wrong, steps look doubled, or they want to fix/override/replace device data: do NOT pass step_count — explain that manual steps add on top, and sync issues need investigating at the device level. ALL OTHER FIELDS (RHR, HRV, AZM, VO2max, stress) replace the existing manual value for that day and are safe to use for corrections. INFER — do not ask: date defaults to today unless the user says otherwise. IDEMPOTENT: if the values you'd log already exist for that date (any source), the tool returns a no-op success — report this as "already had data", not "failed".
list_wearable_dataList daily wearable data (steps, RHR, HRV, Zone Minutes / AZM including the vigorous-intensity breakdown, VO2max, calories eaten / dietary energy, stress) within a date range. Use when the user asks about their step count, heart rate, HRV trends, vigorous minutes, calories eaten / dietary energy, cardio fitness, or any wearable metrics over time. Zone Minutes (a.k.a. Active Zone Minutes) are shown as a daily total plus, when the per-zone breakdown is available, a moderate (1 pt/min, 50–69% max HR) vs vigorous (2 pts/min, 70%+ max HR — Cardio + Peak zones) split. INFER — do not ask: - start_date: default to 14 days ago - end_date: default to today
log_body_metricsLog or update body composition metrics for a given date. Use when the user shares weight, body fat percentage, or any other body composition reading — whether typed manually, copy-pasted from a smart scale app, or described from a photo of a scale display. PROACTIVE DATA COLLECTION: If the user hasn't shared their data yet, ask them to copy-paste the output from their scale app or upload a photo of the display — this lets you parse all fields at once instead of asking one by one. INFER — do not ask: - date: default to today; infer from context ("this morning", "yesterday") - derived fields (lean_mass_lb, fat_mass_lb): calculate from weight and body fat % if possible — lean = weight × (1 - bf%/100), fat = weight × bf%/100 You may log any subset of fields. One row per day. Calling this tool twice on the same date updates the existing entry (upsert).
list_body_metricsList body composition entries within a date range. Use when the user asks about their weight history, body fat trend, or any body metrics over time. INFER — do not ask: - start_date: default to 30 days ago - end_date: default to today
log_sleepLog a sleep entry. Use when the user shares sleep data — total duration, score, or stage breakdown — from Fitbit, Oura, Whoop, Apple Health, or manual recall. PROACTIVE DATA COLLECTION: If the user says they want to log sleep but hasn't shared numbers, ask: "How many hours did you sleep, and do you have a sleep score or stage breakdown from your tracker?" They can paste or describe the summary screen. INFER — do not ask: - date: the night's date (use the date they woke up, or the night they went to bed — either is fine); default to today You may log any subset of fields. One row per day. Calling this tool twice on the same date updates the existing entry (upsert). Entries made through this tool are always tagged as manual — the wearable-provider sources (Fitbit/Oura/Apple Health) are reserved for the actual auto-sync pipelines.
list_sleepList sleep log entries within a date range. Use when the user asks about their sleep history, trends, or quality over time. INFER — do not ask: - start_date: default to 14 days ago - end_date: default to today
list_lab_markersReturns all LOINC-coded markers in the reference library: canonical name, LOINC code, panel, typical unit, and common aliases. Call this BEFORE log_lab_results to match user-provided marker names to canonical entries — same pattern as list_exercises for workouts. Prevents name drift and ensures trending works across lab visits.
log_lab_resultsLog one or more blood test or biomarker results. Use when the user shares lab values — copy-pasted from a Quest/LabCorp PDF, typed from a paper report, or described from a photo of their results. REQUIRED WORKFLOW: 1) call list_lab_markers for canonical names and LOINC codes. 2) for each marker the user provides, find the best match and use its canonical marker_name and loinc_code. 3) if no match exists, use the name as stated and omit loinc_code. If the user says they have lab results but hasn't shared them, prompt: "You can paste the text from your lab report PDF, or upload a photo of the results page — I'll parse all the values at once." INFER — do not ask: date (look for a collection/drawn date in the pasted text, default today), panel_name (from list_lab_markers for matched markers, infer for unmatched), flag (extract from the report if present: "H", "L", "HH", "LL", "A"), ref_range_low/high (parse from the report if shown), lab_name (from the report header, same for all markers in a visit). Submit all markers from a single lab visit in one call.
list_lab_resultsList lab/biomarker results within a date range. Use when the user asks about their lab history, blood work trends, or specific marker values over time. Optionally filter by panel or marker name. INFER — do not ask: - start_date: default to 365 days ago (labs are infrequent) - end_date: default to today
log_injuryLog a new injury or aggravation. Use when the user mentions getting hurt, feeling pain, straining something, or describes an injury. Injuries are date ranges — they start on a date and are ongoing until an end_date is set. INFER — do not ask: - start_date: default to today - severity: estimate from description (minor twinge=2-3, moderate pain=5-6, severe/acute=8-9) - status: default to 'Active' for new injuries - affected_movements: infer from body part and injury type (e.g. shoulder strain → pressing, overhead) - side: infer from description if mentioned (e.g. "right shoulder" → Right) ASK only if body_part is entirely unclear.
list_injuriesList injuries from the injury log. Use when the user asks about their injury history, current injuries, or rehab progress. Returns entry IDs needed for update_injury and delete_injury. Defaults to active and monitoring injuries. INFER — do not ask: - status: default to showing Active and Monitoring; use 'all' to include Resolved; use 'Resolved' for history only.
update_injuryUpdate an existing injury entry. Use when the user reports an injury is improving, worsening, resolved, or wants to change details. When severity changes, the new value is automatically tracked in the severity history for trend analysis. REQUIRED WORKFLOW: call list_injuries first to get the injury ID. Only send fields that need to change. Setting end_date automatically marks the injury as Resolved. Use severity_date to backfill historical severity changes (e.g., "it was a 7 in January, dropped to 4 by March").
delete_injuryPermanently delete an injury entry by ID. Use list_injuries first to confirm the injury ID before deleting. Also removes all severity history for that injury. INFER — do not ask: - id: must be provided or looked up via list_injuries first
log_wellbeingLog subjective wellbeing ratings for a day, week, month, or custom date range. Use when the user describes how they feel — energy level, mood, stress, or muscle soreness. Supports single-day entries ("how I feel today") and period entries ("this week was stressful", "March was great"). If an overlapping entry already exists for the requested period, returns a warning with the conflicting entry IDs — the user must update or delete existing entries first. INFER — do not ask: - period_start: default to today - period_end: default to same as period_start (single day). For "this week" use Monday–Sunday, for "this month" use first–last day. - ratings: estimate from description ("exhausted"=2, "great energy"=8, "stressed out"=8 stress, "feeling good"=7 mood) You may log any subset of rating fields.
list_wellbeingList wellbeing log entries within a date range. Use when the user asks about their mood, energy, stress, or soreness trends over time. Returns entry IDs needed for update_wellbeing and delete_wellbeing. INFER — do not ask: - start_date: default to 14 days ago - end_date: default to today
update_wellbeingUpdate an existing wellbeing entry by ID. Use list_wellbeing first to find the entry ID. Only updates fields that are provided — omitted fields remain unchanged. INFER — do not ask: - id: must be provided or looked up via list_wellbeing first
delete_wellbeingPermanently delete a wellbeing entry by ID. Use list_wellbeing first to confirm the entry ID before deleting. INFER — do not ask: - id: must be provided or looked up via list_wellbeing first
list_supplementsList the user's medications and supplements. Use when the user asks what medications or supplements they're taking, asks to review their stack, or you need IDs before calling manage_supplement. INFER — do not ask: - filter: default to 'active' (current items); use 'all' if the user asks about history or a specific past period; use 'historical' for ended items only. - category: omit to return both medications and supplements; set to 'medication' or 'supplement' to filter by type. Returns each item's id, category, name, brand, dose, schedule, start_date, and end_date.
manage_supplementAdd, update, end, or delete a medication or supplement. Use when the user describes their stack, adds a new item, changes a dose or schedule, says they stopped taking something, or wants to remove an entry. INFER — do not ask: - action: 'add' for a new item, 'update' for changing a field, 'end' when they stopped/finished a course, 'delete' only to remove the record entirely - category: 'medication' for prescription/OTC drugs and pharmaceuticals, 'supplement' for vitamins/minerals/herbs/other dietary supplements — default 'supplement' if unclear - start_date: today for new entries - end_date (for 'end'): today unless the user specifies otherwise ASK the user only if name is missing for a new entry, or 'end' (set end_date) vs 'delete' (remove record) intent is ambiguous. REQUIRED for 'update', 'end', 'delete': call list_supplements first to get the id.
log_supplement_takenMark a medication or supplement as taken or not taken for a specific date. Only relevant when the user has daily tracking mode enabled. Use when the user says they took (or missed) a medication or supplement on a particular day. INFER — do not ask: - date: default to today - taken: default to true (marking as taken) REQUIRED WORKFLOW: call list_supplements first to get the id if the user refers to it by name.
list_recovery_strategiesList the user's recovery and mindfulness strategies. Use when the user asks about their recovery practices, mindfulness routines, or you need strategy IDs before logging a session. INFER — do not ask: - filter: default to 'active'; use 'all' for history; use 'historical' for ended strategies only. Returns each strategy's id, name, category, schedule, start_date, and end_date.
manage_recovery_strategyAdd, update, end, or delete a recovery/mindfulness strategy. Use when the user describes a new practice, changes a schedule, stops a practice, or removes one. Infer category from name, start_date defaults to today, infer schedule from context. ASK only if name is missing. For update/end/delete call list_recovery_strategies first. AFTER a successful 'add': do NOT just confirm and stop. Reply by (1) restating the assumed schedule (sessions per period, duration, time of day, start date) in plain language, and (2) asking the user to confirm or correct it — especially any optional fields you did NOT set (duration_minutes, time_of_day). Example: "Logged sauna starting today, assuming once per week. Sound right? About how long do you usually go for, and what time of day — morning, evening?" If the user corrects anything, call this tool again with action='update'. The goal is accurate adherence data, not a silent confirmation.
log_recovery_sessionLog a completed or skipped recovery/mindfulness session. Use when the user says they did (or skipped) a breathing exercise, meditation, cold plunge, sauna, stretching, or any recovery practice. Also use for one-off standalone sessions not linked to a recurring strategy. INFER — do not ask: - date: default to today - category: infer from the practice name - strategy_name: use the strategy name if linked, or the user's description - duration_minutes: infer if mentioned (omit for skipped sessions) - quality: only include if the user rates it (1-5 scale) - skipped: true when the user says they skipped, missed, or didn't do a session; false (default) for completed sessions PREFERRED WORKFLOW: call list_recovery_strategies first to link the session to an active strategy for adherence tracking. If no matching strategy exists, log as standalone.
update_recovery_sessionUpdate one or more fields on an existing recovery session log entry. Use when the user wants to correct or change something already logged (e.g. wrong duration, quality rating, or notes). REQUIRED WORKFLOW: call list_recovery_strategies or review recent recovery logs first to find the correct session ID. Only send the fields that need to change; omit all others.
delete_recovery_sessionPermanently delete a recovery session log entry. This action is irreversible. REQUIRED WORKFLOW: confirm the session ID before deleting. If the user's intent is ambiguous, ask which session to remove.
log_runLog a run to the user's running tracker. Use when the user mentions going for a run, jogging, or any running activity. REQUIRED: date, distance, and duration. Everything else is optional. INFER — do not ask: - date: default to today; infer from context ("yesterday", "this morning") - run_type: infer from context if obvious ("easy run"=easy, "long run"=long, "tempo"=tempo, "intervals"=interval, "recovery jog"=recovery, "race"=race). Omit if not clear. - surface: infer only if stated ("treadmill run"=treadmill, "trail run"=trail). Omit if not clear. DURATION — accept flexible input and convert to seconds: - "28 minutes" → 1680 - "1:15:30" or "1h 15m 30s" → 4530 - "45 min" → 2700 - "1 hour" → 3600 ASK only if distance or duration are completely missing and cannot be inferred.
list_runsList runs logged within a date range, returning each run's ID, date, distance, duration, pace, and type. Use to answer questions like "how far did I run this week?", "what was my last run?", or before delete_run to find a run ID. Maximum range: 31 days per call. For longer periods, make multiple calls with sequential date ranges. INFER — default start_date to 7 days ago and end_date to today.
delete_runDelete a run by ID. Use when the user wants to remove a run entry. Call list_runs first to find the correct ID. ASK for confirmation if the user's intent is ambiguous.
log_rest_dayMark a date as an intentional rest day. Use when the user says they took a rest day, are taking one today, or wants to mark a past day as rest after the fact (e.g. "this past Monday was a rest day", "today is a rest day", "I rested yesterday"). Suppresses the workout-prompt nudges for that date and lets the engine treat the day as planned, not skipped. INFER — do not ask: - date: parse the user's reference. "today" = today, "yesterday" = today minus 1, "last Monday" = the most recent Monday before today, etc. Default to today when nothing is specified. Idempotent — calling twice on the same date is a no-op (the second call returns the same confirmation). To remove a rest day, use cancel_rest_day.
cancel_rest_dayRemove a previously declared rest day. Use when the user changes their mind ("scratch that, I'm going to lift today after all") or wants to undo a mistaken declaration. INFER — do not ask: - date: parse the user's reference; default to today.
list_rest_daysList the dates a user has marked as rest days within a range. Use when the user asks about their rest pattern ("how many rest days have I taken this month?", "did I rest last week?"). INFER — do not ask: - start_date: default to 30 days ago - end_date: default to today
list_blog_postsSearch the public Crew Blog at /blog for advisor-authored daily posts. Only call when the user explicitly asks about the blog or what an advisor has written; don't volunteer posts in normal conversation. Returns each matching post's slug, title, summary, advisor name, and date. Link a post inline as /blog/<slug>.
get_app_guide_sectionLook up how this app works (features, settings, navigation, troubleshooting). Call when the user asks where something lives, how a feature works, what a metric is computed from, or how to do something inside the product. Do NOT call for advice about the user's body or data — those route to specialists. Examples: "where do I see my PRs?"→pages_training/troubleshooting; "what does Fit Score include?"→pages_dashboard; "what happens in the On Deck workout builder?"→pages_training; "where do I track macros/sleep/cycle?"→pages_nutrition; "how do I connect Oura?"→wearables; "how do I set a calorie goal?"→goals; "can I export my data?"→privacy; "what does Lauryn handle?"→personas; "how does photo meal scan work?"→photos; "how do I log a meal in chat?"→logging; "how do friend challenges work?"→challenges. Returns a Markdown section plus a short guardrail preamble that constrains how to answer. Pick exactly one topic per call; if the question spans two, call twice.
log_cycleLog a period to the user's cycle log. Handles all cases: - Starting a period today: "my period started today" - Backfilling a past period: "my period started May 3rd and ended May 8th" - Resuming a period ended today: "actually I'm still on my period" — detects that today's period was marked ended and reopens it - Logging just a start with no end yet: "I just got my period" Before logging, check that cycle tracking is enabled (consented_at in cycle_prefs). If not, tell the user to turn it on from the dashboard first. INFER — do not ask: - started_on: default to today for current-period statements - ended_on: omit unless the user says it ended; infer from context ("5-day period starting May 3" → ended_on May 7) Do NOT use this tool to log future dates.
list_cycleList the user's logged period records within a date range. Use to look up period history before updating or deleting a record, or when the user asks about their cycle history. INFER — do not ask: - start_date: default to 6 months ago - end_date: default to today
update_cycleUpdate an existing period record by ID. Use to correct dates, add a missing end date, or clear an end date (resume). Use list_cycle first to find the record ID. Common uses: - "my period ended on the 9th not the 8th" → update ended_on - "actually my period started the 2nd not the 3rd" → update started_on - "I'm still on my period" → clear ended_on (pass null) to reopen it INFER — do not ask: - id: look up via list_cycle first if not provided
delete_cycleDelete a period record by ID. Use list_cycle first to confirm the record before deleting. Only delete if the user explicitly asks to remove a specific record. Do not delete to "fix" a record — use update_cycle instead.
show_week_workoutsShow the user their past 7 days of workouts (heart points per day, days trained) as an inline chart. When the user asks about this, prefer calling this tool and rendering the chart over describing the numbers in text. Interactive: 7d/30d/90d/1y range toggle and hover tooltips; returns a short text summary alongside the chart.
show_week_fit_scoreShow the user their past 7 days of daily Fit Score (the app's 0-100 composite) as an inline chart. When the user asks about this, prefer calling this tool and rendering the chart over describing the numbers in text. Interactive: 7d/30d/90d/1y range toggle and hover tooltips; returns a short text summary alongside the chart.
show_week_macrosShow the user their past 7 days of calories and macros (protein, carbs, fat) vs targets as an inline chart. When the user asks about this, prefer calling this tool and rendering the chart over describing the numbers in text. Interactive: 7d/30d/90d/1y range toggle and hover tooltips; returns a short text summary alongside the chart.
show_week_sleepShow the user their past 7 days of sleep (hours per night and sleep score) as an inline chart. When the user asks about this, prefer calling this tool and rendering the chart over describing the numbers in text. Interactive: 7d/30d/90d/1y range toggle and hover tooltips; returns a short text summary alongside the chart.
show_week_stepsShow the user their past 7 days of step counts vs their daily goal as an inline chart. When the user asks about this, prefer calling this tool and rendering the chart over describing the numbers in text. Interactive: 7d/30d/90d/1y range toggle and hover tooltips; returns a short text summary alongside the chart.
show_body_weightShow the user their body weight (and body-fat %) trend over time as an interactive line chart with a 30/90-day/1-year range toggle. When the user asks about this, prefer calling this tool and rendering the chart over describing the numbers in text. Interactive: 7d/30d/90d/1y range toggle and hover tooltips; returns a short text summary alongside the chart.
show_recoveryShow the user their resting heart rate and HRV recovery trend over time as an interactive dual-line chart with a 30/90-day/1-year range toggle. When the user asks about this, prefer calling this tool and rendering the chart over describing the numbers in text. Interactive: 7d/30d/90d/1y range toggle and hover tooltips; returns a short text summary alongside the chart.
show_runsShow the user their running mileage over the last 14 days as an inline bar chart. When the user asks about this, prefer calling this tool and rendering the chart over describing the numbers in text. Interactive: 7d/30d/90d/1y range toggle and hover tooltips; returns a short text summary alongside the chart.
show_fit_score_breakdownShow how today's Fit Score breaks down across its six components (Train, Sleep, Fuel, Recovery, Steps, Wellbeing) as an inline donut/radial chart. When the user asks about this, prefer calling this tool and rendering the chart over describing the numbers in text. Interactive: 7d/30d/90d/1y range toggle and hover tooltips; returns a short text summary alongside the chart.
show_exercise_progressionShow the user's estimated 1-rep-max progression for a lift over time as an interactive line chart, with filters for date range (30/90-day/1-year) and muscle group, and an exercise picker. Use when the user asks about progress on a specific lift (e.g. "how's my bench progressing"). When the user asks about this, prefer calling this tool and rendering the chart over describing the numbers in text. Interactive: 7d/30d/90d/1y range toggle and hover tooltips; returns a short text summary alongside the chart.
show_workoutShow a single logged workout session's exercises and sets as an inline card. Defaults to the most recent workout; can target a specific date. When the user asks about this, prefer calling this tool and rendering the chart over describing the numbers in text. Interactive: 7d/30d/90d/1y range toggle and hover tooltips; returns a short text summary alongside the chart.