Per-meal optimization for balanced meals. Use when user wants to control calories per meal, avoid huge snacks, balance breakfast/lunch/dinner, or needs per-meal protein targets...
This skill creates meal plans with per-meal constraints, ensuring balanced distribution of calories and nutrients across breakfast, lunch, dinner, and snacks. This prevents issues like 995-calorie "snacks" that occur with post-hoc meal allocation.
Consider template-based first (--template --pattern X):
uv run llmn optimize --pattern pescatarian --template --jsonUse multi-period when:
Use multi-period optimization when:
For basic multi-period optimization with auto-derived meal targets:
uv run llmn optimize --multiperiod --json
This uses default splits: Breakfast 25%, Lunch 35%, Dinner 35%, Snack 5%.
First, get the user's overall daily targets:
Ask the user about meal distribution. Offer these presets:
Balanced (default):
Front-loaded (big breakfast):
Back-loaded (big dinner):
For a 2000 kcal diet with "Balanced" split:
Ask if user wants per-meal protein targets:
Create a YAML profile at /tmp/multiperiod_profile.yaml:
name: multiperiod_custom
description: "Multi-period optimization with per-meal constraints"
# Daily totals (linking constraints)
calories:
min: <daily_cal_min>
max: <daily_cal_max>
nutrients:
protein:
min: <daily_protein_min>
fiber:
min: 30
# Per-meal structure (triggers multi-period mode)
meals:
breakfast:
calories:
min: <breakfast_cal_min>
max: <breakfast_cal_max>
nutrients:
protein:
min: <breakfast_protein_min>
lunch:
calories:
min: <lunch_cal_min>
max: <lunch_cal_max>
nutrients:
protein:
min: <lunch_protein_min>
dinner:
calories:
min: <dinner_cal_min>
max: <dinner_cal_max>
nutrients:
protein:
min: <dinner_protein_min>
snack:
calories:
min: 50
max: 200 # Keep snacks small!
include_tags:
- staple
options:
max_grams_per_food: 400
Equi-calorie constraint (lunch β dinner):
equicalorie:
- meals: [lunch, dinner]
tolerance: 100 # Within 100 kcal of each other
Food-meal affinity (restrict foods to specific meals):
food_meal_rules:
171287: [breakfast] # Eggs only at breakfast
170567: [snack] # Almonds only as snack
175167: [lunch, dinner] # Salmon for lunch/dinner only
uv run llmn optimize --file /tmp/multiperiod_profile.yaml --json
The JSON output has a meals structure:
{
"data": {
"meals": [
{
"meal_type": "breakfast",
"foods": [...],
"total_calories": 480,
"total_protein": 32
},
{
"meal_type": "snack",
"foods": [...],
"total_calories": 145, // Now properly constrained!
"total_protein": 5
}
],
"daily_totals": {...}
}
}
Present each meal separately with its foods and totals.
Multi-period has more constraints, so infeasibility is more common. Check for:
Per-meal minimums exceed daily maximum: "Your per-meal calorie minimums sum to 2500 kcal but daily max is 2000 kcal" β Reduce per-meal minimums
Per-meal maximums below daily minimum: "Your per-meal calorie maximums sum to 1500 kcal but daily min is 1800 kcal" β Increase per-meal maximums
Protein constraints too tight: "Can't get 50g protein at breakfast with available foods" β Reduce breakfast protein or add high-protein breakfast foods
The optimizer's infeasibility_diagnosis field explains the conflict.
calories:
min: 1700
max: 1900
nutrients:
protein:
min: 150
meals:
breakfast:
calories: {min: 400, max: 500}
nutrients: {protein: {min: 30}}
lunch:
calories: {min: 550, max: 650}
nutrients: {protein: {min: 45}}
dinner:
calories: {min: 550, max: 650}
nutrients: {protein: {min: 45}}
snack:
calories: {min: 50, max: 150}
equicalorie:
- meals: [lunch, dinner]
tolerance: 75
calories:
min: 2700
max: 2900
nutrients:
protein:
min: 200
meals:
breakfast:
calories: {min: 600, max: 750}
nutrients: {protein: {min: 50}}
lunch:
calories: {min: 800, max: 950}
nutrients: {protein: {min: 60}}
dinner:
calories: {min: 800, max: 950}
nutrients: {protein: {min: 60}}
snack:
calories: {min: 200, max: 350}
nutrients: {protein: {min: 20}}
# Quick multi-period with auto-derived targets
uv run llmn optimize --multiperiod --json
# Multi-period with custom profile
uv run llmn optimize --file /tmp/multiperiod_profile.yaml --json
# With verbose output (shows constraint matrices)
uv run llmn optimize --file /tmp/multiperiod_profile.yaml --verbose
# With explicit food IDs (bypass tag filtering)
uv run llmn optimize --multiperiod --foods 175167,171287,172421 --json
--multiperiod flag first, then customize with a profile