Pierre Nutrition and USDA Integration Methodology
What This Document Covers
This comprehensive guide explains the scientific methods, algorithms, and data integration behind pierre’s nutrition system. It provides transparency into:
- mathematical foundations: BMR formulas, TDEE calculations, macronutrient distribution algorithms
- usda fooddata central integration: real food database access with 350,000+ foods
- calculation methodologies: step-by-step algorithms for daily nutrition needs
- scientific references: peer-reviewed research backing each recommendation
- implementation details: rust code architecture and api integration patterns
- validation: bounds checking, input validation, and safety mechanisms
- testing: comprehensive test coverage without external api dependencies
target audience: developers, nutritionists, coaches, and users seeking deep understanding of pierre’s nutrition intelligence.
Table of Contents
- Tool-to-Algorithm Mapping
- Architecture Overview
- 1. Basal Metabolic Rate (BMR) Calculation
- 2. Total Daily Energy Expenditure (TDEE)
- 3. Macronutrient Recommendations
- 4. Nutrient Timing
- 5. USDA FoodData Central Integration
- 6. MCP Tool Integration
- 7. Testing and Verification
- 8. Configuration and Customization
- 9. Scientific References
- 10. Implementation Roadmap
- 11. Limitations and Considerations
- 12. Usage Examples
Architecture Overview
Pierre’s nutrition system uses a foundation modules approach integrated with usda fooddata central:
┌─────────────────────────────────────────────┐
│ mcp/a2a protocol layer │
│ (src/protocols/universal/) │
└──────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ nutrition tools (5 tools) │
│ (src/protocols/universal/handlers/) │
└──────────────────┬──────────────────────────┘
│
┌──────────────┼──────────────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌──────────────┐ ┌──────────────┐
│ Nutrition │ │ USDA Food │ │ Meal │
│ Calculator │ │ Database │ │ Analyzer │
│ │ │ │ │ │
│ BMR/TDEE │ │ 350k+ Foods │ │ Multi-Food │
│ Macros │ │ Nutrients │ │ Summation │
│ Timing │ │ API Client │ │ Analysis │
└─────────────┘ └──────────────┘ └──────────────┘
NUTRITION FOUNDATION MODULE
Nutrition Calculator Module
src/intelligence/nutrition_calculator.rs - core nutrition algorithms
- mifflin-st jeor bmr calculation with gender-specific constants
- tdee calculation with 5 activity level multipliers (1.2-1.9)
- protein recommendations based on activity level and training goal (0.8-2.2 g/kg)
- carbohydrate targeting optimized for endurance, strength, or weight loss (3-12 g/kg)
- fat calculations ensuring dri compliance (20-35% of tdee)
- nutrient timing for pre/post-workout optimization
- protein distribution across meals for muscle protein synthesis
- input validation with physiological bounds checking
USDA Integration Module
src/external/usda_client.rs - fooddata central api client
- async http client with configurable timeout and rate limiting
- food search by name with pagination support
- food details retrieval with complete nutrient breakdown
- mock client for testing without api calls
- error handling with retry logic and graceful degradation
- caching with ttl for api response optimization
src/external/usda_client.rs - usda data structures (models re-exported via src/external/mod.rs)
- food representation with fdc_id and description
- nutrient structure with name, amount, unit
- search results with pagination metadata
- type-safe deserialization from usda json responses
Tool-to-Algorithm Mapping
This section provides a comprehensive mapping between MCP tools and their underlying algorithms, implementation files, and test coverage.
Nutrition Tools (5 tools)
| Tool Name | Algorithm/Intelligence | Implementation | Test File |
|---|---|---|---|
calculate_daily_nutrition | Mifflin-St Jeor BMR + TDEE activity factors + macro calculations | src/tools/implementations/nutrition.rs:107-274 | tests/nutrition_comprehensive_test.rs |
get_nutrient_timing | Kerksick et al. pre/post-workout timing + protein distribution | src/tools/implementations/nutrition.rs:280-385 | tests/nutrition_comprehensive_test.rs |
search_food | USDA FoodData Central API search | src/tools/implementations/nutrition.rs:391-472 | tests/nutrition_tools_integration_test.rs |
get_food_details | USDA FoodData Central nutrient retrieval | src/tools/implementations/nutrition.rs:478-549 | tests/nutrition_tools_integration_test.rs |
analyze_meal_nutrition | USDA nutrient summation + macro percentage calculation | src/tools/implementations/nutrition.rs:555-676 | tests/nutrition_tools_integration_test.rs |
Recipe Tools (7 tools)
| Tool Name | Algorithm/Intelligence | Implementation | Test File |
|---|---|---|---|
get_recipe_constraints | TDEE-based calorie proportions + meal timing macro distribution | src/tools/implementations/recipes.rs:132-292 | tests/recipe_tools_integration_test.rs |
validate_recipe | USDA FoodData Central validation + unit conversion | src/tools/implementations/recipes.rs:298-520 | tests/recipe_tools_integration_test.rs |
save_recipe | Recipe persistence + ingredient parsing | src/tools/implementations/recipes.rs:526-661 | tests/recipes_test.rs |
list_recipes | Database query with meal timing filter | src/tools/implementations/recipes.rs:667-768 | tests/recipes_test.rs |
get_recipe | Recipe retrieval with nutrition data | src/tools/implementations/recipes.rs:774-855 | tests/recipes_test.rs |
delete_recipe | Recipe deletion with tenant isolation | src/tools/implementations/recipes.rs:861-916 | tests/recipes_test.rs |
search_recipes | Full-text search on name/tags/description | src/tools/implementations/recipes.rs:922-1023 | tests/recipes_test.rs |
Intelligence Module Dependencies
| Module | Algorithm | Source File |
|---|---|---|
NutritionCalculator | Mifflin-St Jeor BMR, TDEE, macro calculations | src/intelligence/nutrition_calculator.rs |
RecipeConstraints | Meal timing macro distribution (ISSN research) | src/intelligence/recipes/models.rs |
MealTdeeProportions | TDEE-based calorie allocation by meal timing | src/config/intelligence/nutrition.rs |
UsdaClient | FoodData Central API integration | src/external/usda_client.rs |
RecipeManager | Recipe CRUD operations | src/database/recipes.rs |
Algorithm Reference Summary
| Algorithm | Scientific Basis | Key Parameters |
|---|---|---|
| Mifflin-St Jeor BMR | Mifflin et al. (1990) | Weight×10 + Height×6.25 - Age×5 ± gender constant |
| TDEE Activity Factors | McArdle Exercise Physiology (2010) | 1.2 (sedentary) to 1.9 (extra active) |
| Protein Needs | Phillips & Van Loon (2011) | 0.8-2.2 g/kg based on activity/goal |
| Carbohydrate Needs | Burke et al. (2011) | 3-10 g/kg based on activity/goal |
| Fat Calculation | DRI Guidelines | 20-35% of TDEE |
| Pre-workout Timing | Kerksick et al. (2017) | 0.5-1.0 g/kg carbs 1-3 hours before |
| Post-workout Timing | Jäger et al. (2017) | 20-40g protein + 0.8-1.2 g/kg carbs within 2 hours |
| Meal Macro Distribution | ISSN Position Stand | Pre: 20/55/25, Post: 30/45/25, Rest: 30/35/35 |
1. Basal Metabolic Rate (BMR) Calculation
Mifflin-St Jeor Formula (1990)
most accurate formula for resting energy expenditure (±10% error vs indirect calorimetry), superior to harris-benedict.
Formula
for males:
bmr = (10 × weight_kg) + (6.25 × height_cm) - (5 × age) + 5
for females:
bmr = (10 × weight_kg) + (6.25 × height_cm) - (5 × age) - 161
Implementation
src/intelligence/nutrition_calculator.rs:169-207
#![allow(unused)]
fn main() {
pub fn calculate_mifflin_st_jeor(
weight_kg: f64,
height_cm: f64,
age: u32,
gender: Gender,
config: &BmrConfig,
) -> Result<f64, AppError> {
// Validation
if weight_kg <= 0.0 || weight_kg > 300.0 {
return Err(AppError::invalid_input("Weight must be between 0 and 300 kg"));
}
if height_cm <= 0.0 || height_cm > 300.0 {
return Err(AppError::invalid_input("Height must be between 0 and 300 cm"));
}
if !(10..=120).contains(&age) {
return Err(AppError::invalid_input(
"Age must be between 10 and 120 years (Mifflin-St Jeor formula validated for ages 10+)",
));
}
// Mifflin-St Jeor formula
let weight_component = config.msj_weight_coef * weight_kg; // 10.0
let height_component = config.msj_height_coef * height_cm; // 6.25
let age_component = config.msj_age_coef * f64::from(age); // -5.0
let gender_constant = match gender {
Gender::Male => config.msj_male_constant, // +5
Gender::Female => config.msj_female_constant, // -161
};
let bmr = weight_component + height_component + age_component + gender_constant;
// Minimum 1000 kcal/day safety check
Ok(bmr.max(1000.0))
}
}
Example Calculations
example 1: 30-year-old male, 75kg, 180cm
bmr = (10 × 75) + (6.25 × 180) - (5 × 30) + 5
bmr = 750 + 1125 - 150 + 5
bmr = 1730 kcal/day
example 2: 25-year-old female, 60kg, 165cm
bmr = (10 × 60) + (6.25 × 165) - (5 × 25) - 161
bmr = 600 + 1031.25 - 125 - 161
bmr = 1345 kcal/day
Configuration
src/config/intelligence/nutrition.rs:47-62
#![allow(unused)]
fn main() {
pub struct BmrConfig {
pub use_mifflin_st_jeor: bool, // true (recommended)
pub use_harris_benedict: bool, // false (legacy)
pub msj_weight_coef: f64, // 10.0
pub msj_height_coef: f64, // 6.25
pub msj_age_coef: f64, // -5.0
pub msj_male_constant: f64, // 5.0
pub msj_female_constant: f64, // -161.0
}
}
Scientific Reference
mifflin, m.d., et al. (1990) “a new predictive equation for resting energy expenditure in healthy individuals” American journal of clinical nutrition, 51(2), 241-247 Doi: 10.1093/ajcn/51.2.241
key findings:
- validated on 498 healthy subjects (247 males, 251 females)
- accuracy: ±10% error vs indirect calorimetry
- superior to harris-benedict formula (1919) by 5%
- accounts for modern body composition changes
2. Total Daily Energy Expenditure (TDEE)
Activity Factor Multipliers
tdee = bmr × activity factor
Activity Levels
Based on mcardle, katch & katch exercise physiology (2010):
| activity level | description | multiplier | example activities |
|---|---|---|---|
| sedentary | little/no exercise | 1.2 | desk job, no workouts |
| lightly active | 1-3 days/week | 1.375 | walking, light yoga |
| moderately active | 3-5 days/week | 1.55 | running 3×/week, cycling |
| very active | 6-7 days/week | 1.725 | daily training, athlete |
| extra active | 2×/day hard training | 1.9 | professional athlete |
Implementation
src/intelligence/nutrition_calculator.rs:209-245
#![allow(unused)]
fn main() {
pub fn calculate_tdee(
bmr: f64,
activity_level: ActivityLevel,
config: &ActivityFactorsConfig,
) -> Result<f64, AppError> {
if bmr < 1000.0 || bmr > 5000.0 {
return Err(AppError::invalid_input("BMR must be between 1000 and 5000"));
}
let activity_factor = match activity_level {
ActivityLevel::Sedentary => config.sedentary, // 1.2
ActivityLevel::LightlyActive => config.lightly_active, // 1.375
ActivityLevel::ModeratelyActive => config.moderately_active, // 1.55
ActivityLevel::VeryActive => config.very_active, // 1.725
ActivityLevel::ExtraActive => config.extra_active, // 1.9
};
Ok(bmr * activity_factor)
}
}
Example Calculations
sedentary: bmr 1500 × 1.2 = 1800 kcal/day very active: bmr 1500 × 1.725 = 2587 kcal/day
Configuration
src/config/intelligence/nutrition.rs:68-79
#![allow(unused)]
fn main() {
pub struct ActivityFactorsConfig {
pub sedentary: f64, // 1.2
pub lightly_active: f64, // 1.375
pub moderately_active: f64, // 1.55
pub very_active: f64, // 1.725
pub extra_active: f64, // 1.9
}
}
3. Macronutrient Recommendations
Protein Needs
Recommendations by Activity and Goal
Based on phillips & van loon (2011) doi: 10.1080/02640414.2011.619204:
| activity level | training goal | protein (g/kg) | rationale |
|---|---|---|---|
| sedentary | any | 0.8 | dri minimum |
| lightly/moderately active | maintenance | 1.3 | active lifestyle support |
| very/extra active | endurance | 2.0 | glycogen sparing, recovery |
| very/extra active | strength/muscle gain | 2.2 | muscle protein synthesis |
| any | weight loss | 1.8 | muscle preservation |
Implementation
src/intelligence/nutrition_calculator.rs:274-313
#![allow(unused)]
fn main() {
pub fn calculate_protein_needs(
weight_kg: f64,
activity_level: ActivityLevel,
training_goal: TrainingGoal,
config: &MacronutrientConfig,
) -> Result<f64, AppError> {
let protein_g_per_kg = match (activity_level, training_goal) {
// Sedentary baseline (DRI minimum)
(ActivityLevel::Sedentary, _) => config.protein_min_g_per_kg, // 0.8
// Moderate activity
(ActivityLevel::LightlyActive | ActivityLevel::ModeratelyActive, _) => {
config.protein_moderate_g_per_kg // 1.3
}
// Athletic - goal-specific
(ActivityLevel::VeryActive | ActivityLevel::ExtraActive, TrainingGoal::EndurancePerformance) => {
config.protein_endurance_max_g_per_kg // 2.0
}
(ActivityLevel::VeryActive | ActivityLevel::ExtraActive,
TrainingGoal::StrengthPerformance | TrainingGoal::MuscleGain) => {
config.protein_strength_max_g_per_kg // 2.2
}
// Weight loss: higher protein for muscle preservation
(_, TrainingGoal::WeightLoss) => config.protein_athlete_g_per_kg, // 1.8
// Default for very/extra active
(ActivityLevel::VeryActive | ActivityLevel::ExtraActive, _) => {
config.protein_athlete_g_per_kg // 1.8
}
};
Ok(weight_kg * protein_g_per_kg)
}
}
Carbohydrate Needs
Recommendations by Activity and Goal
Based on burke et al. (2011) doi: 10.1080/02640414.2011.585473:
| activity level | training goal | carbs (g/kg) | rationale |
|---|---|---|---|
| sedentary/light | any | 3.0 | brain function minimum |
| moderate | maintenance | 6.0 | glycogen replenishment |
| very/extra active | muscle gain | 7.2 (6.0 × 1.2) | anabolic support |
| any | endurance | 10.0 | high glycogen demand |
Implementation
src/intelligence/nutrition_calculator.rs:336-365
#![allow(unused)]
fn main() {
pub fn calculate_carb_needs(
weight_kg: f64,
activity_level: ActivityLevel,
training_goal: TrainingGoal,
config: &MacronutrientConfig,
) -> Result<f64, AppError> {
let carbs_g_per_kg = match (activity_level, training_goal) {
// Low activity
(ActivityLevel::Sedentary | ActivityLevel::LightlyActive, _) => {
config.carbs_low_activity_g_per_kg // 3.0
}
// Endurance athletes need high carbs
(_, TrainingGoal::EndurancePerformance) => {
config.carbs_high_endurance_g_per_kg // 10.0
}
// Moderate activity
(ActivityLevel::ModeratelyActive, _) => {
config.carbs_moderate_activity_g_per_kg // 6.0
}
// Very/extra active (non-endurance) - slightly higher
(ActivityLevel::VeryActive | ActivityLevel::ExtraActive, _) => {
config.carbs_moderate_activity_g_per_kg * 1.2 // 7.2
}
};
Ok(weight_kg * carbs_g_per_kg)
}
}
Fat Needs
DRI Guidelines
Dietary reference intakes (institute of medicine):
- minimum: 20% of tdee (hormone production, vitamin absorption)
- optimal: 25-30% of tdee (satiety, performance)
- maximum: 35% of tdee (avoid excess)
Implementation
src/intelligence/nutrition_calculator.rs:392-435
#![allow(unused)]
fn main() {
pub fn calculate_fat_needs(
tdee: f64,
protein_g: f64,
carbs_g: f64,
training_goal: TrainingGoal,
config: &MacronutrientConfig,
) -> Result<f64, AppError> {
// Calculate calories from protein and carbs
let protein_kcal = protein_g * 4.0;
let carbs_kcal = carbs_g * 4.0;
let fat_kcal_available = tdee - protein_kcal - carbs_kcal;
// Goal-specific fat targeting
let target_fat_percent = match training_goal {
TrainingGoal::WeightLoss => config.fat_min_percent_tdee, // 20%
TrainingGoal::MuscleGain | TrainingGoal::StrengthPerformance => {
config.fat_optimal_percent_tdee - 2.5 // 25%
}
TrainingGoal::EndurancePerformance | TrainingGoal::Maintenance => {
config.fat_optimal_percent_tdee // 27.5%
}
};
// Take maximum of remainder or target percentage
let fat_from_remainder = fat_kcal_available / 9.0;
let fat_from_target = (tdee * target_fat_percent / 100.0) / 9.0;
let fat_g = fat_from_remainder.max(fat_from_target);
// Enforce DRI bounds (20-35% of TDEE)
let min_fat = (tdee * config.fat_min_percent_tdee / 100.0) / 9.0;
let max_fat = (tdee * config.fat_max_percent_tdee / 100.0) / 9.0;
Ok(fat_g.clamp(min_fat, max_fat))
}
}
Configuration
src/config/intelligence/nutrition.rs:88-111
#![allow(unused)]
fn main() {
pub struct MacronutrientConfig {
// Protein ranges (g/kg)
pub protein_min_g_per_kg: f64, // 0.8
pub protein_moderate_g_per_kg: f64, // 1.3
pub protein_athlete_g_per_kg: f64, // 1.8
pub protein_endurance_max_g_per_kg: f64, // 2.0
pub protein_strength_max_g_per_kg: f64, // 2.2
// Carbohydrate ranges (g/kg)
pub carbs_low_activity_g_per_kg: f64, // 3.0
pub carbs_moderate_activity_g_per_kg: f64, // 6.0
pub carbs_high_endurance_g_per_kg: f64, // 10.0
// Fat percentages (% of TDEE)
pub fat_min_percent_tdee: f64, // 20%
pub fat_max_percent_tdee: f64, // 35%
pub fat_optimal_percent_tdee: f64, // 27.5%
}
}
4. Nutrient Timing
Pre-workout Nutrition
Based on kerksick et al. (2017) doi: 10.1186/s12970-017-0189-4:
timing: 1-3 hours before workout carbohydrates: 0.5-1.0 g/kg (intensity-dependent)
- low intensity: 0.375 g/kg (0.5 × 0.75)
- moderate intensity: 0.75 g/kg
- high intensity: 0.975 g/kg (1.3 × 0.75)
Post-workout Nutrition
timing: within 2 hours (flexible - total daily intake matters most) protein: 20-40g (muscle protein synthesis threshold) carbohydrates: 0.8-1.2 g/kg (glycogen restoration)
Protein Distribution
optimal: 4 meals/day with even protein distribution minimum: 3 meals/day rationale: muscle protein synthesis maximized with 0.4-0.5 g/kg per meal
Implementation
src/intelligence/nutrition_calculator.rs:539-606
#![allow(unused)]
fn main() {
pub fn calculate_nutrient_timing(
weight_kg: f64,
daily_protein_g: f64,
workout_intensity: WorkoutIntensity,
config: &NutrientTimingConfig,
) -> Result<NutrientTimingPlan, AppError> {
// Pre-workout carbs based on intensity
let pre_workout_carbs = match workout_intensity {
WorkoutIntensity::Low => weight_kg * config.pre_workout_carbs_g_per_kg * 0.5,
WorkoutIntensity::Moderate => weight_kg * config.pre_workout_carbs_g_per_kg,
WorkoutIntensity::High => weight_kg * config.pre_workout_carbs_g_per_kg * 1.3,
};
// Post-workout protein (20-40g optimal range)
let post_workout_protein = config.post_workout_protein_g_min
.max((daily_protein_g / 5.0).min(config.post_workout_protein_g_max));
// Post-workout carbs
let post_workout_carbs = weight_kg * config.post_workout_carbs_g_per_kg;
// Protein distribution across day
let meals_per_day = config.protein_meals_per_day_optimal;
let protein_per_meal = daily_protein_g / f64::from(meals_per_day);
Ok(NutrientTimingPlan {
pre_workout: PreWorkoutNutrition {
carbs_g: pre_workout_carbs,
timing_hours_before: config.pre_workout_window_hours,
recommendations: vec![
format!("Consume {pre_workout_carbs:.0}g carbs 1-3 hours before workout"),
"Focus on easily digestible carbs (banana, oatmeal, toast)".to_string(),
],
},
post_workout: PostWorkoutNutrition {
protein_g: post_workout_protein,
carbs_g: post_workout_carbs,
timing_hours_after: config.post_workout_window_hours,
recommendations: vec![
format!("Consume {post_workout_protein:.0}g protein + {post_workout_carbs:.0}g carbs within 2 hours"),
"Window is flexible - total daily intake matters most".to_string(),
],
},
daily_protein_distribution: ProteinDistribution {
meals_per_day,
protein_per_meal_g: protein_per_meal,
strategy: format!(
"Distribute {daily_protein_g:.0}g protein across {meals_per_day} meals (~{protein_per_meal:.0}g each)"
),
},
})
}
}
Configuration
src/config/intelligence/nutrition.rs:119-136
#![allow(unused)]
fn main() {
pub struct NutrientTimingConfig {
pub pre_workout_window_hours: f64, // 2.0
pub post_workout_window_hours: f64, // 2.0
pub pre_workout_carbs_g_per_kg: f64, // 0.75
pub post_workout_protein_g_min: f64, // 20.0
pub post_workout_protein_g_max: f64, // 40.0
pub post_workout_carbs_g_per_kg: f64, // 1.0
pub protein_meals_per_day_min: u8, // 3
pub protein_meals_per_day_optimal: u8, // 4
}
}
Recipe Meal Timing Macro Distributions
The recipe system (src/intelligence/recipes/) uses percentage-based macronutrient distributions that adjust based on training context. These distributions are applied when generating recipe constraints for LLM clients or validating recipes.
Macro Distribution by Meal Timing
| Meal Timing | Protein | Carbs | Fat | Rationale |
|---|---|---|---|---|
| Pre-training | 20% | 55% | 25% | Maximize glycogen, minimize GI distress |
| Post-training | 30% | 45% | 25% | Optimize MPS + glycogen replenishment |
| Rest day | 30% | 35% | 35% | Lower glycogen needs, carb periodization |
| General | 25% | 45% | 30% | Balanced for non-specific meals |
Scientific Justification
Pre-training (20% protein, 55% carbs, 25% fat)
High carbohydrate availability maximizes muscle glycogen stores for energy. The ISSN recommends 1-4 g/kg of high-glycemic carbohydrates 1-4 hours before exercise for glycogen optimization. Lower fat (25%) aids gastric emptying, reducing gastrointestinal distress during exercise.
Reference: Kerksick CM, Arent S, Schoenfeld BJ, et al. (2017) “International Society of Sports Nutrition Position Stand: Nutrient Timing” Journal of the International Society of Sports Nutrition 14:33. DOI: 10.1186/s12970-017-0189-4
Post-training (30% protein, 45% carbs, 25% fat)
Elevated protein intake (0.25-0.4 g/kg or approximately 20-40g) within 2 hours post-exercise maximizes muscle protein synthesis (MPS). Moderate carbohydrates (0.8-1.2 g/kg) accelerate glycogen resynthesis, especially when combined with protein. The 30% protein proportion ensures adequate leucine threshold (~2.5-3g) for MPS activation.
Reference: Jäger R, Kerksick CM, Campbell BI, et al. (2017) “International Society of Sports Nutrition Position Stand: Protein and Exercise” Journal of the International Society of Sports Nutrition 14:20. DOI: 10.1186/s12970-017-0177-8
Rest day (30% protein, 35% carbs, 35% fat)
Carbohydrate periodization principles advocate for reduced carbohydrate intake on non-training days when glycogen demands are lower. Training with reduced glycogen availability (the “train-low” approach) stimulates mitochondrial biogenesis and improves oxidative capacity. Higher fat (35%) compensates for reduced carbohydrate calories while maintaining satiety through slower gastric emptying.
Reference: Impey SG, Hearris MA, Hammond KM, et al. (2018) “Fuel for the Work Required: A Theoretical Framework for Carbohydrate Periodization and the Glycogen Threshold Hypothesis” Sports Medicine 48(5):1031-1048. DOI: 10.1007/s40279-018-0867-7
Implementation
src/intelligence/recipes/models.rs:33-49
#![allow(unused)]
fn main() {
impl MealTiming {
/// Get recommended macro distribution percentages for this timing
///
/// Returns (`protein_pct`, `carbs_pct`, `fat_pct`) tuple that sums to 100
pub const fn macro_distribution(&self) -> (u8, u8, u8) {
match self {
// Pre-training: prioritize carbs for energy
Self::PreTraining => (20, 55, 25),
// Post-training: prioritize protein for recovery
Self::PostTraining => (30, 45, 25),
// Rest day: balanced with lower carbs
Self::RestDay => (30, 35, 35),
// General: balanced distribution
Self::General => (25, 45, 30),
}
}
}
}
TDEE-Based Recipe Calorie Calculation
When generating recipe constraints via get_recipe_constraints, the system calculates target calories using a priority-based approach:
- Explicit calories - If provided in the request, uses the exact value
- TDEE-based - When user’s TDEE is provided, calculates calories as a proportion of daily energy
- Fallback defaults - Uses research-based defaults when no TDEE is available
TDEE Proportions by Meal Timing
| Meal Timing | TDEE Proportion | Example (2500 kcal TDEE) | Rationale |
|---|---|---|---|
| Pre-training | 17.5% | 438 kcal | Moderate meal to fuel workout without GI stress |
| Post-training | 27.5% | 688 kcal | Largest meal for recovery and glycogen restoration |
| Rest day | 25.0% | 625 kcal | Standard meal proportion for recovery days |
| General | 25.0% | 625 kcal | Balanced default for non-training meals |
Fallback Calorie Values
When TDEE is not provided, the system uses these scientifically-informed defaults:
| Meal Timing | Fallback Calories | Rationale |
|---|---|---|
| Pre-training | 400 kcal | Light meal suitable for pre-workout fueling |
| Post-training | 600 kcal | Larger meal for optimal recovery nutrition |
| Rest day | 500 kcal | Moderate meal for non-training days |
| General | 500 kcal | Balanced default for general meal planning |
Scientific Justification
Post-training as largest meal (27.5% of TDEE)
The post-workout period represents the optimal window for nutrient partitioning. Elevated muscle glycogen synthase activity and enhanced insulin sensitivity make this the ideal time for higher calorie intake. The 27.5% proportion ensures adequate calories for both glycogen restoration (requiring 0.8-1.2 g/kg carbohydrates) and muscle protein synthesis (requiring 20-40g protein).
Reference: Ivy JL, Katz AL, Cutler CL, et al. (1988) “Muscle glycogen synthesis after exercise: effect of time of carbohydrate ingestion” Journal of Applied Physiology 64(4):1480-1485. DOI: 10.1152/jappl.1988.64.4.1480
Pre-training as smaller meal (17.5% of TDEE)
Lower calorie intake pre-workout minimizes gastrointestinal distress while still providing adequate fuel. The ISSN recommends consuming carbohydrates 1-4 hours before exercise, with smaller meals closer to workout time. The 17.5% proportion provides sufficient energy without compromising exercise performance or comfort.
Configuration
src/config/intelligence/nutrition.rs:298-315
#![allow(unused)]
fn main() {
/// Meal TDEE proportion configuration based on ISSN research
pub struct MealTdeeProportionsConfig {
pub pre_training: f64, // 0.175 (17.5% of TDEE)
pub post_training: f64, // 0.275 (27.5% of TDEE)
pub rest_day: f64, // 0.25 (25% of TDEE)
pub general: f64, // 0.25 (25% of TDEE)
pub fallback_calories: MealFallbackCaloriesConfig,
}
/// Fallback calorie values when TDEE is not available
pub struct MealFallbackCaloriesConfig {
pub pre_training: f64, // 400.0 kcal
pub post_training: f64, // 600.0 kcal
pub rest_day: f64, // 500.0 kcal
pub general: f64, // 500.0 kcal
}
}
API Response Fields
When TDEE is provided, get_recipe_constraints includes additional fields:
{
"calories": 688,
"tdee_based": true,
"tdee": 2500,
"tdee_proportion": 0.275
}
When TDEE is not provided, tdee_based is false and fallback calories are used.
5. USDA FoodData Central Integration
API Overview
usda fooddata central provides access to:
- 350,000+ foods in the database
- comprehensive nutrients (protein, carbs, fat, vitamins, minerals)
- branded foods with manufacturer data
- foundation foods with detailed nutrient profiles
- sr legacy foods from usda nutrient database
Client Implementation
src/external/usda_client.rs:1-233
Real Client (Production)
#![allow(unused)]
fn main() {
pub struct UsdaClient {
client: reqwest::Client,
config: UsdaClientConfig,
}
impl UsdaClient {
pub async fn search_foods(&self, query: &str, page_size: usize) -> Result<SearchResult> {
let url = format!("{}/foods/search", self.config.base_url);
let response = self.client
.get(&url)
.query(&[
("query", query),
("pageSize", &page_size.to_string()),
("api_key", &self.config.api_key),
])
.timeout(Duration::from_secs(self.config.timeout_secs))
.send()
.await?;
response.json().await
}
pub async fn get_food_details(&self, fdc_id: u64) -> Result<FoodDetails> {
let url = format!("{}/food/{}", self.config.base_url, fdc_id);
let response = self.client
.get(&url)
.query(&[("api_key", &self.config.api_key)])
.timeout(Duration::from_secs(self.config.timeout_secs))
.send()
.await?;
response.json().await
}
}
}
Mock Client (Testing)
#![allow(unused)]
fn main() {
pub struct MockUsdaClient;
impl MockUsdaClient {
pub fn new() -> Self {
Self
}
pub fn search_foods(&self, query: &str, _page_size: usize) -> Result<SearchResult> {
// Return realistic mock data based on query
let foods = match query.to_lowercase().as_str() {
q if q.contains("chicken") => vec![
Food {
fdc_id: 171477,
description: "Chicken breast, skinless, boneless, raw".to_string(),
},
],
q if q.contains("banana") => vec![
Food {
fdc_id: 173944,
description: "Banana, raw".to_string(),
},
],
// ... more mock foods
};
Ok(SearchResult {
foods,
total_hits: foods.len(),
current_page: 1,
total_pages: 1,
})
}
pub fn get_food_details(&self, fdc_id: u64) -> Result<FoodDetails> {
// Return complete nutrient breakdown
match fdc_id {
171477 => Ok(FoodDetails { // Chicken breast
fdc_id: 171477,
description: "Chicken breast, skinless, boneless, raw".to_string(),
food_nutrients: vec![
Nutrient {
nutrient_name: "Protein".to_string(),
amount: 23.09,
unit: "g".to_string(),
},
Nutrient {
nutrient_name: "Energy".to_string(),
amount: 120.0,
unit: "kcal".to_string(),
},
// ... more nutrients
],
}),
// ... more mock foods
}
}
}
}
Configuration
src/config/intelligence/nutrition.rs:140-151
#![allow(unused)]
fn main() {
pub struct UsdaApiConfig {
pub base_url: String, // "https://api.nal.usda.gov/fdc/v1"
pub timeout_secs: u64, // 10
pub cache_ttl_hours: u64, // 24
pub max_cache_items: usize, // 1000
pub rate_limit_per_minute: u32, // 30
}
}
6. MCP Tool Integration
Pierre exposes 5 nutrition tools via mcp protocol:
calculate_daily_nutrition
calculates complete daily nutrition requirements
{
"name": "calculate_daily_nutrition",
"description": "Calculate complete daily nutrition requirements (BMR, TDEE, macros)",
"inputSchema": {
"type": "object",
"properties": {
"weight_kg": { "type": "number", "description": "Body weight in kg" },
"height_cm": { "type": "number", "description": "Height in cm" },
"age": { "type": "integer", "description": "Age in years" },
"gender": { "type": "string", "enum": ["male", "female"] },
"activity_level": { "type": "string", "enum": ["sedentary", "lightly_active", "moderately_active", "very_active", "extra_active"] },
"training_goal": { "type": "string", "enum": ["maintenance", "weight_loss", "muscle_gain", "endurance_performance"] }
},
"required": ["weight_kg", "height_cm", "age", "gender", "activity_level", "training_goal"]
}
}
example response:
{
"bmr": 1730,
"tdee": 2682,
"protein_g": 135,
"carbs_g": 402,
"fat_g": 82,
"macro_percentages": {
"protein_percent": 20.1,
"carbs_percent": 60.0,
"fat_percent": 27.5
},
"method": "Mifflin-St Jeor + Activity Factor"
}
calculate_nutrient_timing
calculates pre/post-workout nutrition and daily protein distribution
{
"name": "calculate_nutrient_timing",
"inputSchema": {
"properties": {
"weight_kg": { "type": "number" },
"daily_protein_g": { "type": "number" },
"workout_intensity": { "type": "string", "enum": ["low", "moderate", "high"] }
}
}
}
search_foods (USDA)
searches usda fooddata central database
{
"name": "search_foods",
"inputSchema": {
"properties": {
"query": { "type": "string", "description": "Food name to search" },
"page_size": { "type": "integer", "default": 10 },
"use_mock": { "type": "boolean", "default": false }
}
}
}
get_food_details (USDA)
retrieves complete nutrient breakdown for a food
{
"name": "get_food_details",
"inputSchema": {
"properties": {
"fdc_id": { "type": "integer", "description": "USDA FDC ID" },
"use_mock": { "type": "boolean", "default": false }
}
}
}
analyze_meal_nutrition
analyzes complete meal with multiple foods
{
"name": "analyze_meal_nutrition",
"inputSchema": {
"properties": {
"meal_foods": {
"type": "array",
"items": {
"type": "object",
"properties": {
"fdc_id": { "type": "integer" },
"grams": { "type": "number" }
}
}
},
"use_mock": { "type": "boolean", "default": false }
}
}
}
example request:
{
"meal_foods": [
{ "fdc_id": 171477, "grams": 150 }, // chicken breast
{ "fdc_id": 170379, "grams": 200 }, // brown rice
{ "fdc_id": 170417, "grams": 100 } // broccoli
]
}
example response:
{
"total_calories": 456,
"total_protein_g": 42.5,
"total_carbs_g": 62.3,
"total_fat_g": 5.1,
"food_details": [
{ "fdc_id": 171477, "description": "Chicken breast", "grams": 150 },
{ "fdc_id": 170379, "description": "Brown rice", "grams": 200 },
{ "fdc_id": 170417, "description": "Broccoli", "grams": 100 }
]
}
7. Testing and Verification
Comprehensive Test Suite
39 algorithm tests covering all nutrition calculations:
Test Categories
bmr calculations (4 tests)
- male/female typical cases
- minimum bmr enforcement (1000 kcal floor)
- large athlete scenarios
tdee calculations (5 tests)
- all 5 activity levels (1.2-1.9 multipliers)
- sedentary through extra active
protein needs (5 tests)
- all 4 training goals
- activity level scaling
- weight proportionality
carbohydrate needs (4 tests)
- endurance high-carb requirements
- weight loss lower-carb approach
- muscle gain optimization
- activity level scaling
fat calculations (3 tests)
- balanced macro scenarios
- minimum fat enforcement (20% tdee)
- high tdee edge cases
complete daily nutrition (3 tests)
- male maintenance profile
- female weight loss profile
- athlete endurance profile
nutrient timing (3 tests)
- high/moderate/low workout intensities
- pre/post-workout calculations
- protein distribution strategies
edge cases & validation (13 tests)
- negative/zero weight rejection
- invalid height rejection
- age bounds (10-120 years)
- extreme tdee scenarios
- macro percentage summing (always 100%)
- all intensity levels
- invalid inputs handling
Test Execution
tests/nutrition_comprehensive_test.rs:1-902
# run nutrition tests
cargo test --test nutrition_comprehensive_test
# output
test result: ok. 39 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Formula Verification
mifflin-st jeor accuracy:
- 30yo male, 75kg, 180cm: calculated 1730 kcal (matches hand calculation)
- 25yo female, 60kg, 165cm: calculated 1345 kcal (matches hand calculation)
macro percentages:
- all scenarios tested sum to 100.0% ±0.1%
usda integration:
- mock client tested with banana (173944), chicken (171477), oatmeal (173904), salmon (175168)
- nutrient calculations verified against usda data
8. Configuration and Customization
All nutrition parameters are configurable via src/config/intelligence/nutrition.rs:
#![allow(unused)]
fn main() {
pub struct NutritionConfig {
pub bmr: BmrConfig,
pub activity_factors: ActivityFactorsConfig,
pub macronutrients: MacronutrientConfig,
pub nutrient_timing: NutrientTimingConfig,
pub usda_api: UsdaApiConfig,
}
}
Environment Variables
# USDA API (optional - mock client available for testing)
export USDA_API_KEY=your_api_key_here
# Server configuration
export HTTP_PORT=8081
export DATABASE_URL=sqlite:./data/users.db
Dependency Injection
All calculation functions accept configuration structs:
- testable: inject mock configs for testing
- flexible: change thresholds without code changes
- documented: configuration structs have inline documentation
9. Scientific References
BMR and Energy Expenditure
-
mifflin, m.d., et al. (1990)
- “a new predictive equation for resting energy expenditure”
- american journal of clinical nutrition, 51(2), 241-247
- doi: 10.1093/ajcn/51.2.241
-
mcardle, w.d., katch, f.i., & katch, v.l. (2010)
- exercise physiology: nutrition, energy, and human performance
- lippincott williams & wilkins
Protein Recommendations
-
phillips, s.m., & van loon, l.j. (2011)
- “dietary protein for athletes: from requirements to optimum adaptation”
- journal of sports sciences, 29(sup1), s29-s38
- doi: 10.1080/02640414.2011.619204
-
morton, r.w., et al. (2018)
- “a systematic review, meta-analysis and meta-regression of protein intake”
- british journal of sports medicine, 52(6), 376-384
- doi: 10.1136/bjsports-2017-097608
Carbohydrate Recommendations
- burke, l.m., et al. (2011)
- “carbohydrates for training and competition”
- journal of sports sciences, 29(sup1), s17-s27
- doi: 10.1080/02640414.2011.585473
Nutrient Timing
-
kerksick, c.m., et al. (2017)
- “international society of sports nutrition position stand: nutrient timing”
- journal of the international society of sports nutrition, 14(1), 33
- doi: 10.1186/s12970-017-0189-4
-
aragon, a.a., & schoenfeld, b.j. (2013)
- “nutrient timing revisited: is there a post-exercise anabolic window?”
- journal of the international society of sports nutrition, 10(1), 5
- doi: 10.1186/1550-2783-10-5
Fat Recommendations
- institute of medicine (2005)
- dietary reference intakes for energy, carbohydrate, fiber, fat, fatty acids, cholesterol, protein, and amino acids
- national academies press
10. Implementation Roadmap
Phase 1: Foundation (Complete ✅)
- bmr calculation (mifflin-st jeor)
- tdee calculation with activity factors
- protein recommendations by activity/goal
- carbohydrate targeting
- fat calculations with dri compliance
- nutrient timing algorithms
- input validation and bounds checking
- 39 comprehensive algorithm tests
Phase 2: USDA Integration (Complete ✅)
- usda client with async api calls
- food search functionality
- food details retrieval
- mock client for testing
- meal analysis with multi-food support
- nutrient summation calculations
Phase 3: MCP Tools (Complete ✅)
- calculate_daily_nutrition tool
- calculate_nutrient_timing tool
- search_foods tool
- get_food_details tool
- analyze_meal_nutrition tool
Phase 4: Future Enhancements
- meal planning tool (weekly meal generation)
- recipe nutrition analysis
- micronutrient tracking (vitamins, minerals)
- dietary restriction support (vegan, gluten-free, etc.)
- food substitution recommendations
- grocery list generation
11. Limitations and Considerations
Age Range
- validated: 10-120 years
- optimal accuracy: adults 18-65 years
- pediatric: mifflin-st jeor not validated for children under 10
Activity Level Estimation
- subjective: users may overestimate activity
- recommendation: start conservative (lower activity level)
- adjustment: monitor results and adjust over 2-4 weeks
Individual Variation
- bmr variance: ±10% between individuals
- metabolic adaptation: tdee may decrease with prolonged deficit
- recommendation: use calculations as starting point, adjust based on results
Athletic Populations
- elite athletes: may need higher protein (2.2-2.4 g/kg)
- ultra-endurance: may need higher carbs (12+ g/kg)
- strength athletes: may benefit from higher fat (30-35%)
Medical Conditions
- contraindications: diabetes, kidney disease, metabolic disorders
- recommendation: consult healthcare provider before dietary changes
- monitoring: regular health checkups recommended
12. Usage Examples
Example 1: Calculate Daily Nutrition
input:
#![allow(unused)]
fn main() {
let params = DailyNutritionParams {
weight_kg: 75.0,
height_cm: 180.0,
age: 30,
gender: Gender::Male,
activity_level: ActivityLevel::ModeratelyActive,
training_goal: TrainingGoal::Maintenance,
};
let result = calculate_daily_nutrition_needs(
¶ms,
&config.bmr,
&config.activity_factors,
&config.macronutrients,
)?;
}
output:
#![allow(unused)]
fn main() {
DailyNutritionNeeds {
bmr: 1730.0,
tdee: 2682.0,
protein_g: 97.5,
carbs_g: 450.0,
fat_g: 82.0,
macro_percentages: MacroPercentages {
protein_percent: 14.5,
carbs_percent: 67.1,
fat_percent: 27.5,
},
method: "Mifflin-St Jeor + Activity Factor",
}
}
Example 2: Nutrient Timing
input:
#![allow(unused)]
fn main() {
let timing = calculate_nutrient_timing(
75.0, // weight_kg
150.0, // daily_protein_g
WorkoutIntensity::High,
&config.nutrient_timing,
)?;
}
output:
#![allow(unused)]
fn main() {
NutrientTimingPlan {
pre_workout: PreWorkoutNutrition {
carbs_g: 73.1, // 75kg × 0.75 × 1.3
timing_hours_before: 2.0,
},
post_workout: PostWorkoutNutrition {
protein_g: 30.0, // min(max(150/5, 20), 40)
carbs_g: 75.0, // 75kg × 1.0
timing_hours_after: 2.0,
},
daily_protein_distribution: ProteinDistribution {
meals_per_day: 4,
protein_per_meal_g: 37.5, // 150 / 4
strategy: "Distribute 150g protein across 4 meals (~38g each)",
},
}
}
Example 3: Meal Analysis
input:
{
"meal_foods": [
{ "fdc_id": 171477, "grams": 150 },
{ "fdc_id": 170379, "grams": 200 }
],
"use_mock": true
}
output:
{
"total_calories": 420,
"total_protein_g": 40.0,
"total_carbs_g": 46.0,
"total_fat_g": 4.5,
"food_details": [
{ "fdc_id": 171477, "description": "Chicken breast", "grams": 150 },
{ "fdc_id": 170379, "description": "Brown rice", "grams": 200 }
]
}
Appendix: Formula Derivations
Mifflin-St Jeor Regression Coefficients
derived from 498-subject study:
weight coefficient (10.0)
- represents metabolic cost of maintaining lean mass
- approximately 22 kcal/kg/day for lean tissue
height coefficient (6.25)
- correlates with body surface area
- taller individuals have higher metabolic rate
age coefficient (-5.0)
- accounts for age-related metabolic decline
- approximately 2% decrease per decade
gender constant
- male (+5): accounts for higher lean mass percentage
- female (-161): accounts for higher fat mass percentage
Activity Factor Derivation
based on doubly labeled water studies:
sedentary (1.2): 20% above bmr
- typical desk job with no structured exercise
lightly active (1.375): 37.5% above bmr
- 1-3 days/week light exercise (walking, yoga)
moderately active (1.55): 55% above bmr
- 3-5 days/week moderate exercise (running, cycling)
very active (1.725): 72.5% above bmr
- 6-7 days/week intense training
extra active (1.9): 90% above bmr
- professional athletes with 2×/day training
document version: 1.0.0 last updated: 2025-10-31 implementation status: production-ready test coverage: 39 algorithm tests, 1,188 total tests passing