Weight Loss Nutritionist

Weight Loss Nutritionist · GPT-Aktionen

Weight Loss Coach Actions

Backend Actions for the Weight Loss Nutritionist GPT. All numeric computations happen here so the model does not drift on arithmetic. Every response contains a `narrative` string the GPT should echo verbatim.

  • POST /bmrCompute basal metabolic rate (BMR)

    Returns Mifflin-St Jeor BMR. CALL THIS instead of doing the math yourself. Pass user_id to persist the profile for future conversations. Echo the returned narrative verbatim.

  • POST /tdeeCompute total daily energy expenditure (TDEE)

    Returns TDEE = BMR × activity multiplier. Call this before recommending a calorie goal. Pass user_id to persist the full profile. Echo the returned narrative verbatim.

  • POST /calorie-goalRecommend a daily calorie goal with safety floors enforced

    Core safety-gated endpoint. Enforces calorie floors (1200F/1500M/1600 teen), BMI <19 screen, 1kg/week rate cap, and pregnancy refusal. The `narrative` field is what the GPT should say — do not propose your own numbers on top of this.

  • POST /macrosCompute protein/fat/carb grams for a daily calorie goal

    Returns macros based on weight and preference. Protein is pinned to 1.2–1.6 g/kg (balanced), 1.8 g/kg (high_protein), or 1.6 g/kg (keto). Echo the narrative verbatim.

  • GET /foodLook up calories + macros for a food, scaled to a portion

    Wraps USDA FoodData Central. Returns top matches scaled to the given grams. Applies under-estimation margins for nuts, oils, cheese, fried items, liquid calories, alcohol.

  • POST /mealEstimate total kcal + macros for a meal from natural-language items

    Call this to tally any meal the user describes. Looks up each item in USDA FDC, applies under-estimation margins, returns per-item + totals with a confidence band. Echo the narrative verbatim.

  • POST /weight-trendDe-noise a weight history and return the real fat trend

    Applies a 7-day EMA to filter out water-weight noise, then regresses the last 14 smoothed points for a kg/week slope. Use this before answering "am I plateauing?" or "is this fat or water?". Echo the narrative verbatim.

  • POST /plateauDiagnose a weight-loss plateau using the playbook checklist

    Runs the plateau diagnostic from coaching-playbook.md. Returns ranked likely causes and ONE specific adjustment. Call this when the user reports 2+ weeks of no change. Echo the narrative verbatim.

  • GET /profileRetrieve a saved user profile

    Returns the biometrics previously saved via calculateBMR or calculateTDEE. Call this at the start of a new conversation to restore the user's context without re-asking all the biometrics.

  • GET /meal-logGet the user's meal log for a given date

    Returns all meals logged today (or a specified date) with running totals. Call this when the user asks 'how much have I eaten today' or at end-of-day for a summary. Echo the narrative verbatim.

Ursprüngliches API-Schema
{
  "openapi": "3.1.0",
  "info": {
    "title": "Weight Loss Coach Actions",
    "version": "0.1.0",
    "description": "Backend Actions for the Weight Loss Nutritionist GPT. All numeric computations happen here so the model does not drift on arithmetic. Every response contains a `narrative` string the GPT should echo verbatim."
  },
  "servers": [
    {
      "url": "https://gpt.nanorhino.ai"
    }
  ],
  "components": {
    "schemas": {
      "BMRResult": {
        "type": "object",
        "properties": {
          "bmr_kcal": {
            "type": "number"
          },
          "method": {
            "type": "string",
            "enum": [
              "mifflin_st_jeor"
            ]
          },
          "katch_mcardle_kcal": {
            "type": "number"
          },
          "steps": {
            "type": "string"
          },
          "narrative": {
            "type": "string"
          },
          "profile_saved": {
            "type": "boolean"
          }
        },
        "required": [
          "bmr_kcal",
          "method",
          "steps",
          "narrative",
          "profile_saved"
        ]
      },
      "BMRInput": {
        "type": "object",
        "properties": {
          "sex": {
            "type": "string",
            "enum": [
              "male",
              "female"
            ]
          },
          "age_years": {
            "type": "integer",
            "minimum": 10,
            "maximum": 100
          },
          "height_cm": {
            "type": "number",
            "minimum": 120,
            "maximum": 230
          },
          "weight_kg": {
            "type": "number",
            "minimum": 30,
            "maximum": 300
          },
          "body_fat_pct": {
            "type": "number",
            "minimum": 3,
            "maximum": 60,
            "description": "Optional. If provided, Katch-McArdle is returned alongside Mifflin-St Jeor."
          },
          "user_id": {
            "type": "string",
            "maxLength": 100,
            "description": "Optional user identifier. If provided, biometrics are saved for future reference."
          }
        },
        "required": [
          "sex",
          "age_years",
          "height_cm",
          "weight_kg"
        ]
      },
      "TDEEResult": {
        "type": "object",
        "properties": {
          "bmr_kcal": {
            "type": "number"
          },
          "tdee_kcal": {
            "type": "number"
          },
          "activity": {
            "type": "string",
            "enum": [
              "sedentary",
              "light",
              "moderate",
              "active",
              "very_active"
            ],
            "description": "sedentary (desk job, <10km walking/day), light (1-3x/wk), moderate (3-5x/wk), active (6-7x/wk), very_active (hard daily + physical job)"
          },
          "multiplier": {
            "type": "number"
          },
          "steps": {
            "type": "string"
          },
          "narrative": {
            "type": "string"
          },
          "profile_saved": {
            "type": "boolean"
          }
        },
        "required": [
          "bmr_kcal",
          "tdee_kcal",
          "activity",
          "multiplier",
          "steps",
          "narrative",
          "profile_saved"
        ]
      },
      "TDEEInput": {
        "type": "object",
        "properties": {
          "sex": {
            "type": "string",
            "enum": [
              "male",
              "female"
            ]
          },
          "age_years": {
            "type": "integer",
            "minimum": 10,
            "maximum": 100
          },
          "height_cm": {
            "type": "number",
            "minimum": 120,
            "maximum": 230
          },
          "weight_kg": {
            "type": "number",
            "minimum": 30,
            "maximum": 300
          },
          "activity": {
            "type": "string",
            "enum": [
              "sedentary",
              "light",
              "moderate",
              "active",
              "very_active"
            ],
            "description": "sedentary (desk job, <10km walking/day), light (1-3x/wk), moderate (3-5x/wk), active (6-7x/wk), very_active (hard daily + physical job)"
          },
          "user_id": {
            "type": "string",
            "maxLength": 100,
            "description": "Optional user identifier. If provided, the full profile (including activity + TDEE) is saved for future reference."
          }
        },
        "required": [
          "sex",
          "age_years",
          "height_cm",
          "weight_kg",
          "activity"
        ]
      },
      "SafetyIssue": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "below_floor",
              "underweight_current",
              "underweight_goal",
              "unsafe_rate",
              "teen",
              "pregnant_or_nursing"
            ]
          },
          "floor": {
            "type": "number"
          },
          "requested": {
            "type": "number"
          },
          "bmi": {
            "type": "number"
          },
          "goal_bmi": {
            "type": "number"
          },
          "requested_kg_per_week": {
            "type": "number"
          },
          "capped_to": {
            "type": "number"
          }
        },
        "required": [
          "type"
        ]
      },
      "CalorieGoalResult": {
        "type": "object",
        "properties": {
          "tdee_kcal": {
            "type": "number"
          },
          "daily_kcal_goal": {
            "type": "number"
          },
          "deficit_kcal": {
            "type": "number"
          },
          "effective_rate_kg_per_week": {
            "type": "number"
          },
          "weeks_to_goal": {
            "type": [
              "number",
              "null"
            ]
          },
          "calorie_floor": {
            "type": "number"
          },
          "safety_issues": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SafetyIssue"
            }
          },
          "steps": {
            "type": "string"
          },
          "narrative": {
            "type": "string"
          },
          "refusal": {
            "type": "boolean",
            "description": "True when safety screening refused a deficit. GPT must follow the narrative, not propose its own number."
          }
        },
        "required": [
          "tdee_kcal",
          "daily_kcal_goal",
          "deficit_kcal",
          "effective_rate_kg_per_week",
          "weeks_to_goal",
          "calorie_floor",
          "safety_issues",
          "steps",
          "narrative",
          "refusal"
        ]
      },
      "CalorieGoalInput": {
        "type": "object",
        "properties": {
          "sex": {
            "type": "string",
            "enum": [
              "male",
              "female"
            ]
          },
          "age_years": {
            "type": "integer",
            "minimum": 10,
            "maximum": 100
          },
          "height_cm": {
            "type": "number",
            "minimum": 120,
            "maximum": 230
          },
          "weight_kg": {
            "type": "number",
            "minimum": 30,
            "maximum": 300
          },
          "activity": {
            "type": "string",
            "enum": [
              "sedentary",
              "light",
              "moderate",
              "active",
              "very_active"
            ],
            "description": "sedentary (desk job, <10km walking/day), light (1-3x/wk), moderate (3-5x/wk), active (6-7x/wk), very_active (hard daily + physical job)"
          },
          "goal_weight_kg": {
            "type": "number",
            "minimum": 30,
            "maximum": 300
          },
          "target_rate_kg_per_week": {
            "type": "number",
            "minimum": 0.1,
            "maximum": 2,
            "default": 0.5,
            "description": "Desired loss rate. Will be capped at 1.0 kg/week."
          },
          "pregnant_or_nursing": {
            "type": "boolean"
          }
        },
        "required": [
          "sex",
          "age_years",
          "height_cm",
          "weight_kg",
          "activity",
          "goal_weight_kg"
        ]
      },
      "MacrosResult": {
        "type": "object",
        "properties": {
          "protein_g": {
            "type": "number"
          },
          "fat_g": {
            "type": "number"
          },
          "carb_g": {
            "type": "number"
          },
          "protein_kcal": {
            "type": "number"
          },
          "fat_kcal": {
            "type": "number"
          },
          "carb_kcal": {
            "type": "number"
          },
          "protein_g_per_kg": {
            "type": "number"
          },
          "steps": {
            "type": "string"
          },
          "narrative": {
            "type": "string"
          }
        },
        "required": [
          "protein_g",
          "fat_g",
          "carb_g",
          "protein_kcal",
          "fat_kcal",
          "carb_kcal",
          "protein_g_per_kg",
          "steps",
          "narrative"
        ]
      },
      "MacroPreference": {
        "type": "string",
        "enum": [
          "balanced",
          "high_protein",
          "keto"
        ],
        "default": "balanced"
      },
      "MacrosInput": {
        "type": "object",
        "properties": {
          "daily_kcal": {
            "type": "number",
            "minimum": 800,
            "maximum": 5000
          },
          "weight_kg": {
            "type": "number",
            "minimum": 30,
            "maximum": 300
          },
          "preference": {
            "$ref": "#/components/schemas/MacroPreference"
          }
        },
        "required": [
          "daily_kcal",
          "weight_kg"
        ]
      },
      "FoodMatch": {
        "type": "object",
        "properties": {
          "fdc_id": {
            "type": "number"
          },
          "description": {
            "type": "string"
          },
          "brand": {
            "type": "string"
          },
          "grams": {
            "type": "number"
          },
          "kcal": {
            "type": "number"
          },
          "protein_g": {
            "type": "number"
          },
          "fat_g": {
            "type": "number"
          },
          "carb_g": {
            "type": "number"
          },
          "fiber_g": {
            "type": "number"
          },
          "margin_applied": {
            "type": "number"
          },
          "margin_reasons": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "fdc_id",
          "description",
          "grams",
          "kcal",
          "protein_g",
          "fat_g",
          "carb_g",
          "fiber_g"
        ]
      },
      "FoodLookupResult": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string"
          },
          "grams": {
            "type": "number"
          },
          "matches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FoodMatch"
            }
          },
          "confidence": {
            "type": "string",
            "enum": [
              "high",
              "medium",
              "low"
            ]
          },
          "narrative": {
            "type": "string"
          }
        },
        "required": [
          "query",
          "grams",
          "matches",
          "confidence",
          "narrative"
        ]
      },
      "MealItemResult": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string"
          },
          "grams": {
            "type": "number"
          },
          "kcal": {
            "type": "number"
          },
          "protein_g": {
            "type": "number"
          },
          "fat_g": {
            "type": "number"
          },
          "carb_g": {
            "type": "number"
          },
          "confidence": {
            "type": "string",
            "enum": [
              "high",
              "medium",
              "low"
            ]
          },
          "not_found": {
            "type": "boolean",
            "description": "True when not in DB — GPT should estimate this item itself."
          },
          "margin_applied": {
            "type": "number"
          },
          "margin_reasons": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "matched_as": {
            "type": "string"
          },
          "note": {
            "type": "string"
          }
        },
        "required": [
          "description",
          "grams",
          "kcal",
          "protein_g",
          "fat_g",
          "carb_g",
          "confidence",
          "not_found"
        ]
      },
      "MealResult": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MealItemResult"
            }
          },
          "total_kcal": {
            "type": "number"
          },
          "total_protein_g": {
            "type": "number"
          },
          "total_fat_g": {
            "type": "number"
          },
          "total_carb_g": {
            "type": "number"
          },
          "confidence_band_kcal": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 2,
            "maxItems": 2,
            "description": "[low, high] kcal range"
          },
          "overall_confidence": {
            "type": "string",
            "enum": [
              "high",
              "medium",
              "low"
            ]
          },
          "narrative": {
            "type": "string"
          }
        },
        "required": [
          "items",
          "total_kcal",
          "total_protein_g",
          "total_fat_g",
          "total_carb_g",
          "confidence_band_kcal",
          "overall_confidence",
          "narrative"
        ]
      },
      "MealItem": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string",
            "minLength": 1,
            "example": "grilled chicken breast"
          },
          "grams": {
            "type": "number",
            "minimum": 1,
            "maximum": 3000,
            "description": "If omitted, a sensible portion is assumed (150g default)."
          }
        },
        "required": [
          "description"
        ]
      },
      "MealInput": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MealItem"
            },
            "minItems": 1,
            "maxItems": 15
          },
          "meal_label": {
            "type": "string",
            "example": "lunch"
          }
        },
        "required": [
          "items"
        ]
      },
      "WeightTrendResult": {
        "type": "object",
        "properties": {
          "smoothed": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string"
                },
                "kg": {
                  "type": "number"
                }
              },
              "required": [
                "date",
                "kg"
              ]
            }
          },
          "latest_smoothed_kg": {
            "type": "number"
          },
          "slope_kg_per_week": {
            "type": "number"
          },
          "label": {
            "type": "string",
            "enum": [
              "true_trend_down",
              "true_trend_up",
              "flat_noise",
              "insufficient_data"
            ]
          },
          "raw_range_kg": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 2,
            "maxItems": 2,
            "description": "[min, max] of raw readings"
          },
          "narrative": {
            "type": "string"
          }
        },
        "required": [
          "smoothed",
          "latest_smoothed_kg",
          "slope_kg_per_week",
          "label",
          "raw_range_kg",
          "narrative"
        ]
      },
      "WeightReading": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "description": "ISO date",
            "example": "2026-04-10"
          },
          "kg": {
            "type": "number",
            "minimum": 30,
            "maximum": 300
          }
        },
        "required": [
          "date",
          "kg"
        ]
      },
      "WeightTrendInput": {
        "type": "object",
        "properties": {
          "readings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WeightReading"
            },
            "minItems": 3,
            "maxItems": 180
          }
        },
        "required": [
          "readings"
        ]
      },
      "PlateauCause": {
        "type": "object",
        "properties": {
          "cause": {
            "type": "string",
            "enum": [
              "outdated_tdee",
              "tracking_drift",
              "new_exercise_water",
              "high_sodium",
              "luteal_phase",
              "actual_plateau"
            ]
          },
          "likelihood": {
            "type": "string",
            "enum": [
              "high",
              "medium",
              "low"
            ]
          },
          "adjustment": {
            "type": "string"
          }
        },
        "required": [
          "cause",
          "likelihood",
          "adjustment"
        ]
      },
      "PlateauResult": {
        "type": "object",
        "properties": {
          "weeks_stalled": {
            "type": "number"
          },
          "ranked_causes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlateauCause"
            }
          },
          "recommended_adjustment": {
            "type": "string"
          },
          "narrative": {
            "type": "string"
          }
        },
        "required": [
          "weeks_stalled",
          "ranked_causes",
          "recommended_adjustment",
          "narrative"
        ]
      },
      "PlateauInput": {
        "type": "object",
        "properties": {
          "weeks_stalled": {
            "type": "number",
            "minimum": 1,
            "maximum": 52
          },
          "kg_lost_since_tdee_recalc": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "default": 0
          },
          "started_new_exercise_last_4_weeks": {
            "type": "boolean",
            "default": false
          },
          "high_sodium_recently": {
            "type": "boolean",
            "default": false
          },
          "in_luteal_phase": {
            "type": "boolean"
          },
          "tracking_confidence": {
            "type": "string",
            "enum": [
              "high",
              "medium",
              "low"
            ],
            "default": "medium"
          },
          "avg_daily_kcal_logged": {
            "type": "number"
          },
          "current_tdee_estimate_kcal": {
            "type": "number"
          }
        },
        "required": [
          "weeks_stalled"
        ]
      },
      "ProfileResult": {
        "type": "object",
        "properties": {
          "found": {
            "type": "boolean"
          },
          "profile": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "user_id": {
                "type": "string"
              },
              "sex": {
                "type": "string",
                "enum": [
                  "male",
                  "female"
                ]
              },
              "age_years": {
                "type": "number"
              },
              "height_cm": {
                "type": "number"
              },
              "weight_kg": {
                "type": "number"
              },
              "activity": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "body_fat_pct": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "bmr_kcal": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "tdee_kcal": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "updated_at": {
                "type": "string"
              }
            },
            "required": [
              "user_id",
              "sex",
              "age_years",
              "height_cm",
              "weight_kg",
              "activity",
              "body_fat_pct",
              "bmr_kcal",
              "tdee_kcal",
              "updated_at"
            ]
          },
          "narrative": {
            "type": "string"
          }
        },
        "required": [
          "found",
          "profile",
          "narrative"
        ]
      },
      "MealLogEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "number"
          },
          "meal_label": {
            "type": [
              "string",
              "null"
            ]
          },
          "total_kcal": {
            "type": "number"
          },
          "total_protein_g": {
            "type": "number"
          },
          "total_fat_g": {
            "type": "number"
          },
          "total_carb_g": {
            "type": "number"
          },
          "confidence": {
            "type": "string"
          },
          "logged_at": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "meal_label",
          "total_kcal",
          "total_protein_g",
          "total_fat_g",
          "total_carb_g",
          "confidence",
          "logged_at"
        ]
      },
      "MealLogResult": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string"
          },
          "meals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MealLogEntry"
            }
          },
          "day_total_kcal": {
            "type": "number"
          },
          "day_total_protein_g": {
            "type": "number"
          },
          "day_total_fat_g": {
            "type": "number"
          },
          "day_total_carb_g": {
            "type": "number"
          },
          "meal_count": {
            "type": "number"
          },
          "narrative": {
            "type": "string"
          }
        },
        "required": [
          "date",
          "meals",
          "day_total_kcal",
          "day_total_protein_g",
          "day_total_fat_g",
          "day_total_carb_g",
          "meal_count",
          "narrative"
        ]
      }
    },
    "parameters": {}
  },
  "paths": {
    "/bmr": {
      "post": {
        "operationId": "calculateBMR",
        "summary": "Compute basal metabolic rate (BMR)",
        "description": "Returns Mifflin-St Jeor BMR. CALL THIS instead of doing the math yourself. Pass user_id to persist the profile for future conversations. Echo the returned narrative verbatim.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BMRInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "BMR with arithmetic shown",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BMRResult"
                }
              }
            }
          }
        }
      }
    },
    "/tdee": {
      "post": {
        "operationId": "calculateTDEE",
        "summary": "Compute total daily energy expenditure (TDEE)",
        "description": "Returns TDEE = BMR × activity multiplier. Call this before recommending a calorie goal. Pass user_id to persist the full profile. Echo the returned narrative verbatim.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TDEEInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "TDEE with steps",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TDEEResult"
                }
              }
            }
          }
        }
      }
    },
    "/calorie-goal": {
      "post": {
        "operationId": "recommendCalorieGoal",
        "summary": "Recommend a daily calorie goal with safety floors enforced",
        "description": "Core safety-gated endpoint. Enforces calorie floors (1200F/1500M/1600 teen), BMI <19 screen, 1kg/week rate cap, and pregnancy refusal. The `narrative` field is what the GPT should say — do not propose your own numbers on top of this.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CalorieGoalInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calorie goal, or a refusal narrative if safety issues were triggered",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CalorieGoalResult"
                }
              }
            }
          }
        }
      }
    },
    "/macros": {
      "post": {
        "operationId": "calculateMacros",
        "summary": "Compute protein/fat/carb grams for a daily calorie goal",
        "description": "Returns macros based on weight and preference. Protein is pinned to 1.2–1.6 g/kg (balanced), 1.8 g/kg (high_protein), or 1.6 g/kg (keto). Echo the narrative verbatim.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MacrosInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Macro grams with steps",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MacrosResult"
                }
              }
            }
          }
        }
      }
    },
    "/food": {
      "get": {
        "operationId": "lookupFood",
        "summary": "Look up calories + macros for a food, scaled to a portion",
        "description": "Wraps USDA FoodData Central. Returns top matches scaled to the given grams. Applies under-estimation margins for nuts, oils, cheese, fried items, liquid calories, alcohol.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "example": "grilled chicken breast"
            },
            "required": true,
            "name": "query",
            "in": "query"
          },
          {
            "schema": {
              "type": "number",
              "minimum": 1,
              "maximum": 5000,
              "default": 100
            },
            "required": false,
            "name": "grams",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Top matches",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FoodLookupResult"
                }
              }
            }
          },
          "502": {
            "description": "Upstream FDC error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "narrative": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error",
                    "narrative"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/meal": {
      "post": {
        "operationId": "estimateMealCalories",
        "summary": "Estimate total kcal + macros for a meal from natural-language items",
        "description": "Call this to tally any meal the user describes. Looks up each item in USDA FDC, applies under-estimation margins, returns per-item + totals with a confidence band. Echo the narrative verbatim.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MealInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Meal totals",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MealResult"
                }
              }
            }
          }
        }
      }
    },
    "/weight-trend": {
      "post": {
        "operationId": "smoothWeightTrend",
        "summary": "De-noise a weight history and return the real fat trend",
        "description": "Applies a 7-day EMA to filter out water-weight noise, then regresses the last 14 smoothed points for a kg/week slope. Use this before answering \"am I plateauing?\" or \"is this fat or water?\". Echo the narrative verbatim.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WeightTrendInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Smoothed trend",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WeightTrendResult"
                }
              }
            }
          }
        }
      }
    },
    "/plateau": {
      "post": {
        "operationId": "diagnosePlateau",
        "summary": "Diagnose a weight-loss plateau using the playbook checklist",
        "description": "Runs the plateau diagnostic from coaching-playbook.md. Returns ranked likely causes and ONE specific adjustment. Call this when the user reports 2+ weeks of no change. Echo the narrative verbatim.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlateauInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ranked causes + one adjustment",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlateauResult"
                }
              }
            }
          }
        }
      }
    },
    "/profile": {
      "get": {
        "operationId": "getProfile",
        "summary": "Retrieve a saved user profile",
        "description": "Returns the biometrics previously saved via calculateBMR or calculateTDEE. Call this at the start of a new conversation to restore the user's context without re-asking all the biometrics.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "maxLength": 100,
              "default": "default",
              "description": "User identifier. Defaults to \"default\" for single-user mode."
            },
            "required": false,
            "name": "user_id",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Profile if found, or found=false",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfileResult"
                }
              }
            }
          }
        }
      }
    },
    "/meal-log": {
      "get": {
        "operationId": "getMealLog",
        "summary": "Get the user's meal log for a given date",
        "description": "Returns all meals logged today (or a specified date) with running totals. Call this when the user asks 'how much have I eaten today' or at end-of-day for a summary. Echo the narrative verbatim.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "description": "ISO date (YYYY-MM-DD). Defaults to today (UTC).",
              "example": "2026-04-14"
            },
            "required": false,
            "name": "date",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Day's meals with running totals",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MealLogResult"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {}
}