Skill: javi23ruiz/nutrition-pro (version 1.3.0)

--- name: nutrition-pro description: > The AI nutrition coach that actually gets to know you. Just say what you ate — nutrition-pro figures out the portion, looks it up, and logs it. No grams required. It builds a living memory of your eating patterns, trusted meals, food preferences, and personal goals — and rewrites that picture of you every week as it learns more. Proactive cron check-ins (morning summary, evening log, weekly digest) keep you consistent without nagging. Trusted meals are remembered forever so you never answer the same portion question twice. Zero installation required — no CLI, no pip, no binary. Works entirely through agent knowledge and memory. Triggers on: food names, meal logging ("I just had X", "log my lunch"), nutrition questions ("how many calories in X", "macros for Y"), diet setup ("track my calories", "help me eat better"), and daily/weekly summaries. Only triggers on explicit food-related messages — not on casual mentions of food in passing. metadata: clawdbot: emoji: "🥗" --- # nutrition-pro Log meals, track daily intake against your goals, look up nutrition data, estimate calorie burn, and view trends — all through conversation. No app, no CLI, no installation required. --- ## First run On the very first message that triggers this skill, check if nutrition tracking is configured: Run: `memory_get MEMORY.md` If the file is empty or does not contain `## Nutrition profile`: Read and follow `nutrition-pro/ONBOARDING.md` exactly. If MEMORY.md contains a filled `## Nutrition profile`: Continue normally. Do not re-run onboarding. --- ## Logging meals **Triggers:** "I had X", "I ate X", "just had X", "log X", "add X to my food log". Steps: ### Step 1 — Extract food and resolve portion Extract food name(s) from the message. Then determine grams using the priority order below: **A. Explicit weight → use it directly** - "200g chicken breast" → grams=200 - "half a kilo of pasta" → grams=500 **B. Countable units → map to grams** | What user says | Estimated grams | |---|---| | 1 egg / 2 eggs / 3 eggs | 55g / 110g / 165g | | 1 slice bread | 30g | | 1 cup rice (cooked) | 200g | | 1 bowl rice / pasta | 250g | | 1 banana / apple / orange | 120g / 180g / 150g | | 1 glass milk | 240g | | 1 tablespoon olive oil | 14g | | 1 handful nuts | 30g | **C. Portion language → map to gram range, then ask** When the user says "some", "a bit of", "a little", or gives no quantity at all, map to three tiers and ask before logging: | Tier | Typical serving | Use when | |---|---|---| | Light | ~60–80% of standard | "a small X", "a little X", "just had some X" | | Regular | 100% standard portion | no modifier given | | Large | ~130–150% of standard | "a big X", "a lot of X", "a huge plate of X" | Standard reference portions (grams): - Chicken breast: 120g / 180g / 250g - Fish fillet: 100g / 150g / 200g - Red meat (steak, beef): 120g / 180g / 250g - Cooked pasta / rice: 150g / 220g / 300g - Salad (no protein): 100g / 200g / 350g - Soup / stew: 200g / 350g / 500g - Bread / roll: 30g / 60g / 90g - Vegetables (side): 60g / 120g / 200g - Fruit: 80g / 150g / 250g When tier is ambiguous, present the three options with calorie estimates and let the user pick: > "Chicken breast — which is closest? > • Light (~120g): ~200 kcal > • Regular (~180g): ~300 kcal ← my guess > • Large (~250g): ~415 kcal > Or tell me the weight if you know it." Mark your guess as ← my guess based on meal context (time of day, whether it's a main or side). Wait for the user to confirm or correct before logging. **D. Restaurant / eating out → estimate from meal bracket** Detect restaurant context from phrases like: "went to", "ordered", "ate out", "takeaway", "delivery", "at [restaurant name]". Use meal bracket to estimate: | Meal type | Calorie bracket | |---|---| | Light dish (salad, soup, sushi) | 300–500 kcal | | Regular main (pasta, burger, rice dish) | 600–900 kcal | | Heavy main (pizza, ribs, fried food) | 900–1,400 kcal | Present the bracket to the user: > "I'd estimate a typical [meal type] is around [LOW]–[HIGH] kcal. Want me to log > [MID] kcal? You can adjust the number." Always append `(estimated)` to the food name when logging uncertain portions. --- ### Step 2 — Look up calories and confirm Use the following priority order. No external calls needed for common foods. **Priority 1 — Trusted meals (instant)** Check `## Trusted meals` in MEMORY.md first. If the food name matches a saved meal, use the stored values directly. Skip all other steps and go straight to Step 3. **Priority 2 — Agent knowledge (zero external calls)** Use for whole, unprocessed, or common foods: - Meats: chicken breast, beef, pork, fish, eggs - Grains: rice, pasta, oats, bread, quinoa - Vegetables and fruits (all common ones) - Dairy: milk, yogurt, cheese - Legumes: lentils, chickpeas, beans - Nuts and seeds Compute calories from standard macro data scaled to the resolved grams. Reference values (per 100g, cooked unless noted): | Food | kcal | Protein | Fat | Carbs | |---|---|---|---|---| | Chicken breast | 165 | 31g | 3.6g | 0g | | Salmon | 208 | 20g | 13g | 0g | | Beef (lean) | 215 | 26g | 12g | 0g | | Egg (whole, raw) | 143 | 13g | 10g | 1g | | White rice (cooked) | 130 | 2.7g | 0.3g | 28g | | Brown rice (cooked) | 112 | 2.6g | 0.9g | 24g | | Pasta (cooked) | 158 | 5.8g | 0.9g | 31g | | Oats (dry) | 379 | 13g | 7g | 67g | | Bread (white) | 265 | 9g | 3.2g | 49g | | Potato (boiled) | 87 | 1.9g | 0.1g | 20g | | Broccoli | 34 | 2.8g | 0.4g | 7g | | Spinach | 23 | 2.9g | 0.4g | 3.6g | | Banana | 89 | 1.1g | 0.3g | 23g | | Apple | 52 | 0.3g | 0.2g | 14g | | Olive oil | 884 | 0g | 100g | 0g | | Whole milk | 61 | 3.2g | 3.3g | 4.8g | | Greek yogurt (plain) | 59 | 10g | 0.4g | 3.6g | | Cheddar cheese | 402 | 25g | 33g | 1.3g | | Almonds | 579 | 21g | 50g | 22g | | Lentils (cooked) | 116 | 9g | 0.4g | 20g | For foods not in this table, use your training knowledge. Label source as `(estimated)`. **Priority 3 — Restaurant / processed foods** For genuinely ambiguous processed or restaurant dishes, use the meal bracket from Step 1D. Label as `(estimated)`. Show a clean summary: > **{FOOD_NAME}** · {GRAMS}g > {KCAL} kcal · Protein {P}g · Fat {F}g · Carbs {C}g Ask: "Should I log this?" — wait for confirmation before writing. If the user corrects the weight or portion, recompute with the new grams. --- ### Step 3 — Log On confirmation, append to today's daily memory note (`memory/YYYY-MM-DD.md`): ``` - {HH:MM} · {FOOD_NAME} · {GRAMS}g · {KCAL} kcal (P:{P}g F:{F}g C:{C}g) ``` Then recompute and update the running total line at the top of the file: ``` **Running total: {TOTAL_KCAL} kcal / {TARGET} kcal · P:{TOTAL_P}g · F:{TOTAL_F}g · C:{TOTAL_C}g** ``` If the file doesn't exist yet, create it with this header: ``` # {WEEKDAY}, {YYYY-MM-DD} **Running total: 0 kcal / {TARGET} kcal · P:0g · F:0g · C:0g** ``` For estimated entries, use `~` prefix: `~562 kcal`. For multi-food meals ("chicken, rice, and broccoli"), resolve all portions in one message, then log everything with a single confirmation: > "Here's what I've got: > • Chicken breast (~180g): 300 kcal > • Brown rice (~200g): 220 kcal > • Broccoli (~120g): 42 kcal > Total: ~562 kcal · P: 58g · F: 8g · C: 45g > Log all three?" After logging: confirm with one line and show progress toward today's target. --- ### Step 4 — Update streak After logging any meal, read `## Nutrition profile` in MEMORY.md and check the `Current streak` value. - If a meal was already logged today (other entries exist in today's note): streak unchanged. - If this is the first meal of the day: increment streak by 1 and update MEMORY.md. - If yesterday's memory/YYYY-MM-DD.md has no entries and today is not covered by a lifecycle event: reset streak to 1. Update `Current streak` in MEMORY.md. If the new streak exceeds `Longest streak`, update that too. Acknowledge milestones naturally (7, 14, 30, 60, 100 days). --- ### Step 5 — Check for patterns (see Learning section below) --- ## Answering questions without external calls Use the cheapest source that can answer the question. Check in order: ### 1. Today's daily note (instant) - "How many calories today?" / "What did I eat today?" → Read `memory/{TODAY}.md` — running total and all meals are there - "What's my target?" / "Am I on track?" → Read `## Nutrition profile` in MEMORY.md, compare to running total - "What did I have for lunch?" / "Did I log breakfast?" → Read today's daily note and look at the times ### 2. Past daily notes (memory reads) - "What did I eat last Tuesday?" / "What did I have on April 3rd?" → Read `memory/YYYY-MM-DD.md` for that date directly - "How have I been doing this week?" → Read each day's note from Monday to today, sum totals ### 3. Computed summaries (read multiple notes) - "Average calories last 30 days" → Read the last 30 daily notes, sum kcal, divide - "What's my protein been like this week?" → Read Mon–today notes, extract P totals - "How many times have I had chicken?" → Search daily notes for "chicken" entries ### 4. Agent knowledge (no external calls) - "How many calories in 200g salmon?" → compute from macro table above - "How many calories does running burn?" → MET calculation (see below) - "What should my daily intake be?" → Harris-Benedict TDEE (see below) - "Compare chicken vs tofu" → compute both from macro table --- ## Calorie burn estimates Use MET (Metabolic Equivalent of Task) values. Formula: `kcal = MET × weight_kg × duration_hours` If weight unknown, use 70kg as default and note the assumption. | Activity | MET | |---|---| | Running (moderate, ~8 km/h) | 8.0 | | Running (fast, ~12 km/h) | 11.5 | | Jogging | 7.0 | | Cycling (moderate) | 6.8 | | Cycling (vigorous) | 10.0 | | Walking (5 km/h) | 3.5 | | Swimming | 6.0 | | Hiking | 5.3 | | Weightlifting | 3.5 | | Yoga | 2.5 | | HIIT | 8.0 | | Tennis | 7.3 | | Basketball | 6.5 | | Soccer | 7.0 | | Elliptical | 5.0 | | Jump rope | 10.0 | Example: "I went running for 30 minutes, I weigh 75kg" → 8.0 × 75 × 0.5 = 300 kcal burned --- ## Daily intake targets (Harris-Benedict TDEE) BMR formulas: - Male: 88.36 + (13.4 × weight_kg) + (4.8 × height_cm) − (5.7 × age) - Female: 447.6 + (9.25 × weight_kg) + (3.1 × height_cm) − (4.3 × age) Activity multipliers: | Level | Multiplier | |---|---| | Sedentary (desk job, no exercise) | 1.2 | | Light (1–3 days/week exercise) | 1.375 | | Moderate (3–5 days/week) | 1.55 | | Active (6–7 days/week hard exercise) | 1.725 | | Very active (athlete, physical job) | 1.9 | TDEE = BMR × multiplier. Round to nearest 50 kcal. Protein suggestion: 0.8g/kg maintenance, 1.6–2.2g/kg muscle building. --- ## What to learn and when to write it Memory writes happen in the background — do not interrupt the conversation to announce routine updates like "I've saved your food preference." The user consented to memory during onboarding; they do not need a notification for every write. The one exception: when rewriting "Who you are" or "Patterns" (the weekly synthesis), say one sentence so the user feels seen, not surveilled. Example: "I've updated my picture of you — you're really consistent on weekday mornings." Users can ask "what do you know about me?" at any time and you should read and summarize MEMORY.md for them. --- ### Who you are Trigger: end of every Sunday, or after 7+ days of data since last rewrite. Action: read the past 4 weeks of memory/YYYY-MM-DD.md daily notes + MEMORY.md. Synthesize into one paragraph (3–5 sentences) that captures: - Demographics / diet type / intolerances (from profile) - Primary goal and why (from goal narrative) - Eating patterns and personality (from logs) - Current streak and consistency Rewrite the `## Who you are` section in MEMORY.md in full. Do not append — replace. Read this section at the start of every session. Use it to frame tone, suggestions, and feedback without the user having to re-explain themselves. --- ### Goal narrative Trigger: onboarding question 1, or any time the user says why they're tracking ("I want to lose X", "I'm trying to build muscle", "my doctor told me to", etc.) Action: write one sentence in their words (not a paraphrase) to `## Goal narrative` in MEMORY.md. Update it if they ever restate a new goal. Use this to frame every weekly summary and every time they're discouraged. Example: if goal is "lose 8kg before September", lead weekly summaries with progress toward that, not generic calorie math. --- ### Trusted meals Trigger: the same meal (same food name or very similar) is logged 3+ times with a confirmed gram weight. Action: add a row to the `## Trusted meals` table in MEMORY.md: ``` | {MEAL_NAME} | {GRAMS_DESCRIPTION} | {KCAL} | {P}g | {F}g | {C}g | {N}x | ``` When a meal is in the trusted meals table: - Skip the portion-guessing flow entirely - Skip the lookup step - Log immediately and say: > "{MEAL_NAME} — logged {GRAMS} like usual. {KCAL} kcal." - Update the `Times logged` count in the table after each log If the user corrects the weight ("actually I had more today"), log with the corrected weight but keep the trusted default unchanged unless they say "update my usual" or "save this as my new default." --- ### Patterns Trigger: every Sunday (same trigger as "Who you are" rewrite). Action: read the past 4 weeks of daily notes. Look for: - Days of the week where logging is skipped most often - Weekend vs. weekday calorie delta - Macro compliance by day type (training vs. rest, weekday vs. weekend) - Meals that are frequently missed (e.g. dinner rarely logged) - Underrating or overrating patterns relative to target - Any correlation with lifecycle events (travel, stress mentions) Rewrite the `## Patterns` section in MEMORY.md in full. 4–7 bullet points. Do not append — replace the whole section each Sunday. Surface one insight proactively on Monday morning: > "One thing I noticed this week: you hit your protein goal every day you > logged lunch. On the 3 days you skipped it, you came up short." --- ### Food preferences Trigger: user declines a suggested food, expresses dislike, or asks for an alternative ("I don't eat X", "I'm not a fan of Y", "can I have Z instead") Action: append to `## Learned food preferences` in MEMORY.md: `- Dislikes: {FOOD} (noted {DATE})` or `- Prefers {FOOD_A} over {FOOD_B} (noted {DATE})` Trigger: user asks for the same food 3+ times across different days Action: append: `- Frequently eats: {FOOD} (logged {N} times)` Never suggest a food the user has said they dislike. Check this list before making any food suggestions. --- ### Meal timing drift Trigger: after 7 days of tracking, actual meal times differ from stated times by >45 min on average Action: update meal times in MEMORY.md "Nutrition profile" to match observed times. Say: "I've updated your meal times to match when you actually eat." --- ### Calorie patterns Trigger: user consistently goes over or under target by >15% for 5+ days Action: note this in `## Patterns` at the next Sunday rewrite. Do NOT suggest changing the target without being asked. Do NOT comment on individual days being over — only surface multi-week patterns. --- ### Health context Trigger: user mentions health conditions, fitness goals, or medications Action: append to `## Health context` in MEMORY.md: `- {HEALTH_NOTE} (mentioned {DATE})` Only write what the user explicitly stated. Never infer diagnoses. Use health context to adjust tone — e.g. never say "cheat meal" if they're managing a medical condition. --- ### Lifecycle events Trigger: user mentions upcoming or current travel, illness, holidays, or any temporary change in routine. Action: append to `## Lifecycle events` in MEMORY.md: `- {EVENT}: {DATE_OR_RANGE} ({CONTEXT_NOTE})` During active lifecycle events: - Do not flag calorie deviations as failures - Do not break streaks for illness days (mark as `[sick - excluded]` in daily note) - Adjust restaurant meal expectations for travel days - After event ends: resume normal tracking without comment --- ## Contextual callbacks — making memory feel alive The goal is for the agent to feel like it *remembers you*, not like it's reading a database. Apply these rules in every response: **Reference trusted meals by name** Don't ask "how many grams?" for a meal you've seen before. Say: > "Chicken and rice — I'll use your usual 180g + 200g. That's 520 kcal." **Frame progress through the goal narrative** When showing summaries, tie the number to what they're working toward: > "1,840 kcal today — you're 160 under target. Good day toward September." Not just: "1,840 kcal logged." **Surface patterns without being preachy** When you notice a recurring situation, mention it once, lightly: > "Thursday again — you tend to skip lunch today. Want me to remind you at 1pm?" Never repeat the same observation two weeks in a row unless asked. **Acknowledge streaks and milestones naturally** > "That's 14 days in a row. You've never gone this long before." Not a notification — woven into the confirmation after logging. **Adjust tone to lifecycle events** If the user is traveling: "Restaurant week — I'll estimate loosely, no pressure." If they just came back from holiday: "Welcome back. Want to ease back in or go full tracking?" **Never read back memory robotically** Don't say "According to my records, you dislike dairy." Say "No dairy — got it." Don't say "I have noted that your goal is weight loss." Just use it. --- ## Setting up proactive reminders **Triggers:** "set up reminders", "remind me to log meals", "set up daily tracking", or during onboarding step 6. Ask the user which reminders they want and at what times **before** running any commands. Do not assume default times. Only create the cron jobs for the reminders they selected. Available reminders: **Morning summary:** Ask: "What time do you want your morning summary?" (e.g. 7am, 8:30am) Parse to hour H and minute M. Then run: ``` openclaw cron add \ --name "nutrition-morning" \ --cron "{M} {H} * * *" \ --tz "{TIMEZONE}" \ --session nutrition-tracker \ --message "Read MEMORY.md and yesterday's memory/YYYY-MM-DD.md daily note. \ Present a morning summary: yesterday's total vs target, current streak, one insight. \ Frame it through their goal narrative. Keep it to 3-4 lines." \ --announce ``` **Evening check-in:** Ask: "What time do you want your evening check-in?" (e.g. 7pm, 9pm) Parse to hour H and minute M (24h). Then run: ``` openclaw cron add \ --name "nutrition-evening" \ --cron "{M} {H} * * *" \ --tz "{TIMEZONE}" \ --session nutrition-tracker \ --system-event "Evening nutrition check-in. Ask the user what they ate today. \ For each food they mention, resolve the portion, compute calories from agent \ knowledge, confirm, then append to today's memory/YYYY-MM-DD.md. \ After all meals logged, read the file and show today's running total." \ --wake now ``` **Sunday synthesis (recommended — user must confirm):** Offer this during onboarding. If the user agrees, create it. Do not create it unilaterally. ``` openclaw cron add \ --name "nutrition-synthesis" \ --cron "0 21 * * 0" \ --tz "{TIMEZONE}" \ --session nutrition-tracker \ --message "Read MEMORY.md and the past 4 weeks of memory/ daily notes. \ 1) Rewrite the 'Who you are' section in MEMORY.md with a 3-5 sentence synthesized paragraph. \ 2) Rewrite the 'Patterns' section with 4-7 bullets from observed data. \ This is a background maintenance run — do not send the user a message. \ Prepare one pattern insight to surface in Monday morning's report." \ --announce ``` **Weekly report (always Monday):** Ask: "What time on Monday do you want your weekly report?" (e.g. 9am) Parse to hour H and minute M. Then run: ``` openclaw cron add \ --name "nutrition-weekly" \ --cron "{M} {H} * * 1" \ --tz "{TIMEZONE}" \ --session nutrition-tracker \ --message "Read MEMORY.md and each daily note from the past 7 days. \ Present a weekly report framed through the user's goal narrative: \ average daily calories, best day, worst day, protein compliance, current streak. \ Surface one pattern insight from the Sunday synthesis if available. \ Keep it short — 5-8 lines max." \ --announce ``` After setup: confirm which jobs were created and when they'll fire next. To view: `openclaw cron list` To disable a specific job: `openclaw cron disable nutrition-evening` (or -morning, -weekly)


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)