SSkilltecabyclaudinhocode
Enviar skill
← Voltar para o catálogo

mmmmealplan

DevOps e Infra

Generate a personalized weekly meal plan and Migros shopping list from user preferences (macros, restrictions, meal cadence, fixed slots). Uses the Migros MCP for promotions, ingredient lookup, and nutrition verification. Triggers on '/mmmmealplan', 'plan my meals', 'meal plan', 'weekly menu', 'grocery list for the week'.

2estrelas
Ver no GitHub ↗Autor: philippdubachLicença: MIT

Mmmmealplan

Generate a weekly meal plan and Migros shopping list.

Mmm + Migros + Meal-planning. A Claude Code skill that turns a YAML config + a recipe library into a real weekly plan: it pulls live promotions and nutrition data from the unofficial Migros MCP, respects your macros and restrictions, and writes the plan and a categorised shopping list straight to disk.

Invocation

  • /mmmmealplan — plan the next 7 days starting Monday
  • /mmmmealplan --days N — plan the next N days starting today

Prerequisites

  • ~/.claude/skills/mmmmealplan/config.yaml must exist (copy from config.yaml.example)
  • The Migros MCP server (mcp__migros__*) must be available — see README for install steps

Configuration

Read ~/.claude/skills/mmmmealplan/config.yaml at the start of every run. If the file does not exist, output:

config.yaml not found at ~/.claude/skills/mmmmealplan/config.yaml.
Copy config.yaml.example and edit it to your preferences:

  cp ~/.claude/skills/mmmmealplan/config.yaml.example ~/.claude/skills/mmmmealplan/config.yaml

Then re-run /mmmmealplan.

Then stop. Do not proceed.

Schema

FieldTypeRequiredNotes
household_sizeintyesDefault servings count if slot_servings is not set for a slot
slot_servings.breakfastintoptionalOverride servings just for breakfast (e.g., 2 people share breakfast but only 1 has dinner). Default: household_size
slot_servings.lunchintoptionalSame; default: household_size
slot_servings.dinnerintoptionalSame; default: household_size
macros.protein_gintyesDaily target in grams (applies to the primary eater — see is_primary below)
macros.carbs_gintyesDaily target in grams
macros.fat_gintyesDaily target in grams
macros.kcalintyesDaily target
restrictionslist[str]yesHard constraints; recipes violating these are rejected
dislikeslist[str]yesSoft; avoid when possible
meal_cadence.breakfastint 0-7yesDays per week this slot is consumed (per-week; scaled pro-rata for shorter windows)
meal_cadence.lunchint 0-7yesSame
meal_cadence.dinnerint 0-7yesSame
fixed_slots.<slot>str OR listoptionalEither a single recipe filename (everyone in the slot eats the same) or a list of {recipe: <filename>, servings: <int>, is_primary: <bool>} entries to split the slot across people. Sum of servings in a list must equal the slot's effective servings count
constraints.weeknight_dinner_max_minutesintoptionalTime ceiling Mon-Thu
equipmentlist[str]yesAvailable cooking equipment

Validation rules

Before generating a plan, validate:

  1. All required fields present.
  2. For each fixed_slots entry (or each item if it's a list), the corresponding recipe file exists.
  3. For each fixed_slots entry (or each item if it's a list), the recipe's tags do not violate any item in restrictions. (E.g., a fixed breakfast tagged contains-lactose with restriction lactose-free is a conflict.) This is a tag-based check; for ingredient-level allergen verification using real Migros data, see Step 6.5 of the Run flow.
  4. If fixed_slots.<slot> is a list, the sum of servings across items must equal the slot's effective servings (slot_servings.<slot> if defined, else household_size). Exactly one item should have is_primary: true (the recipe whose nutrition counts toward the user's macro targets); if none is marked, the first item is treated as primary.

If any validation fails, abort with a specific error pointing at the conflict. Do not produce partial output.

Recipe library

At run start, scan ~/.claude/skills/mmmmealplan/recipes/<slot>/*.md for each slot in meal_cadence. For each file, parse the YAML frontmatter to extract: name, slot, servings, time_minutes, tags, ingredients, nutrition_per_serving (optional).

Build an in-memory list of available library recipes per slot. This list is used in two places:

  1. Fixed slot resolution — match fixed_slots.<slot> against filenames (without .md).
  2. LLM generation prompt — pass the list of (filename, name, tags, time_minutes) per slot as candidate library recipes the LLM can select from.

If a recipe file is malformed (invalid YAML frontmatter, missing required fields), skip it and emit a warning in the output: Skipped recipe <path>: <reason>. Do not abort.

Required frontmatter fields

name, slot, servings, time_minutes, tags, ingredients. nutrition_per_serving is optional.

If nutrition_per_serving is absent, the run flow will compute it from Migros product data during ingredient resolution (Step 6 of the Run flow).

Migros MCP usage

Read lib/migros-helpers.md when you need to call any Migros MCP tool. It documents the patterns for ingredient resolution, caching, nutrition parsing, and failure handling.

Run flow

When invoked, execute these steps in order. Do not skip steps. If any step fails irrecoverably, abort with a clear error.

Step 1 — Determine planning window

  • Default: next Mon–Sun (7 days).
  • If invoked with --days N, plan N days starting today.
  • Compute the ISO week label for output filenames: YYYY-WXX (e.g., 2026-W18). For non-week-aligned windows use YYYY-MM-DD instead.

Step 2 — Load config and recipe library

  • Read ~/.claude/skills/mmmmealplan/config.yaml. Apply the validation rules from the Configuration section. Abort on validation failure.
  • Scan ~/.claude/skills/mmmmealplan/recipes/<slot>/*.md per the Recipe library section. Build the in-memory candidate list.
  • Read the last 2 plan files from ~/.claude/skills/mmmmealplan/plans/ (sorted by filename). Extract the recipe names used. Build a recently_used set per slot.

Step 3 — Compute slot demand

meal_cadence is expressed per week (assumes a 7-day window). For shorter or longer windows, scale pro-rata.

For each slot in meal_cadence:

  • scaled_cadence = round(meal_cadence[slot] × window_days / 7) — scale per-week cadence to the actual window
  • total_needed = scaled_cadence
  • fixed_count = number of days in window with fixed_slots[slot] set — usually all days if a fixed slot is set
  • free_count = max(0, total_needed - fixed_count)
  • free_count is what the LLM must fill
  • effective_servings = slot_servings[slot] if defined else household_size — drives ingredient quantity scaling for that slot

Examples:

  • Cadence breakfast: 7, fixed breakfast: overnight-oats, window 7 days → scaled_cadence = 7, fixed_count = 7, free_count = 0.
  • Cadence dinner: 4, no fixed dinner, window 3 days → scaled_cadence = round(4 × 3/7) = 2, fixed_count = 0, free_count = 2.
  • Cadence lunch: 0, any window → scaled_cadence = 0, free_count = 0 (slot is skipped).

Step 4 — Query Migros promotions

Call mcp__migros__get_promotions. See lib/migros-helpers.md for parsing and failure handling. Result is a list of promoted products (name, discount). If failed/empty, set promotions = [] and continue.

Step 5 — Generate the candidate plan (LLM step)

Construct a prompt for the model with these inputs:

  • Planning window (start date, end date, day count)
  • Free slots per day (from step 3)
  • Fixed slots per day (recipes already chosen)
  • Config: macros targets, restrictions, dislikes, equipment, time constraints
  • Library candidates per slot: list of {filename, name, tags, time_minutes}
  • recently_used set per slot (avoid repeating)
  • Promotions list

Ask the model to produce, in JSON:

{
  "days": [
    {
      "date": "2026-04-28",
      "weekday": "Mon",
      "meals": {
        "breakfast": { "source": "library", "filename": "overnight-oats" },
        "dinner":    { "source": "new", "name": "Sheet-pan chicken & broccoli", "ingredients": ["chicken breast 200g", "

Como adicionar

/plugin marketplace add philippdubach/mmmmealplan

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Comentários · Nenhum comentário

Entre para comentar. Entrar

  • Ainda não há comentários. Seja o primeiro.