| name | meal-planner |
| description | Generate weekly meal plans (3-5 dinners + prep-friendly lunches) using Publix/Kroger sales in ZIP 37188, family preferences, and rotation history. Backed by projects/meal-planning/. |
| version | 1.0.0 |
| author | Kevin |
| tags | ["meal-planning","food","cooking","projects"] |
meal-planner
Plan the week's meals. Pull context from the meal-planning project folder, decide collaboratively with Kevin, log outcomes so rotation logic works next week.
Reference data and menu storage
Design philosophy (Hermes-native): Skills own their configuration/reference data, user outputs go to standard OS locations.
Skill reference data lives in ~/.hermes/skills/meal-planner/references/:
CONTEXT.md — goals, preferences, adaptation logic (authoritative for prefs)
MEALS.md — meal database, the rotation source
SIDES.md — sides database, canonical list for side recommendations
User-facing weekly menus live in ~/Documents/meal-planning/menus/:
menus/YYYY-MM-DD.md — confirmed past menus (one per Sunday-start week)
Why this structure: Reference data (MEALS.md, SIDES.md, CONTEXT.md) is skill configuration — it belongs with the skill. Menus are user outputs — they belong in a standard macOS location (~/Documents) where they're visible in Finder, backed up by Time Machine, and accessible outside Hermes. This keeps "how the skill works" separate from "what the skill produced."
Read reference files at the start of any meal-planning session. Update MEALS.md or SIDES.md only after confirming a new entry with Kevin; update CONTEXT.md when preferences change.
Menu lifecycle (iterative → confirmed → written)
Menu planning is a multi-turn conversation. Nothing is "the menu" until Kevin confirms AND it's written to disk. Read this before every meal-planning session.
Phase 1 — Drafting (everything is an Option)
While iterating with Kevin:
- Label every proposal as Option A, Option B, Option C, etc.
- Number each meal within an option: 1, 2, 3, 4. Every draft line gets a stable address like
A2 or C4. Sides stay inline in parentheses — they are not numbered.
- Never call any candidate "the menu", "the plan", "this week's menu", or "what we're having". They are options.
- Options live only in the conversation until confirmed. Do NOT write them to disk yet.
- Iterate freely: refine options, swap meals, generate new options, ask clarifying questions.
- When referencing prior chat context, treat it as options too. A menu discussed last session but never written is not a menu — it's a lapsed option.
Draft format (what Kevin sees in chat):
Option A
1. Ground Chicken Taco Bake (Black Beans, Corn)
2. Nashville Hot Sausage Skillet (Roasted Veg Medley)
3. Beef & Tortellini Bake (Steamed Broccoli)
4. Creamy Garlic Pork Chops (Roasted Broccoli)
Option B
1. ...
Numbering is stable across a session: if Kevin locks A2, it stays A2 for the rest of the conversation — don't renumber when meals get swapped. Replacements keep the slot (A2 updated, still called A2).
Phase 1.5 — Partial locks & iterative refinement
Kevin will frequently lock part of an option and ask for changes elsewhere. Recognize these addressing patterns:
A2, A1 and A3, A2-A4 — specific slots in an option
keep A2-A4, swap A1 — partial lock, regenerate only the named slots
lock A1 and A3; replace A2; drop A4 — multiple operations at once
combine A1, B3, C2, C4 into Option D — cross-option merge into a new letter
replace A1 with something under $10 — constraint-driven swap of one slot
When Kevin gives a partial lock, do this — in order:
- Echo the lock back explicitly before generating anything new. Example:
"Locking A1 (Ground Chicken Taco Bake), A3 (Beef & Tortellini Bake), A4 (Creamy Garlic Pork Chops). Drafting a replacement for A2."
- Regenerate only the requested slots. Everything locked stays verbatim — same name, same sides, same slot number.
- Present the refined option as the same letter with an iteration note — e.g. "Option A (v2)". Don't jump to "Option D" unless Kevin explicitly asked for a merge into a new option.
- Show the full refined option after the swap, with locked lines marked (🔒 or bold) so Kevin sees what's stable vs. what changed.
Refined format example:
Option A (v2)
1. 🔒 Ground Chicken Taco Bake (Black Beans, Corn)
2. Buffalo Chicken Wraps (Roasted Veg Medley) ← new, was Nashville Hot Sausage Skillet
3. 🔒 Beef & Tortellini Bake (Steamed Broccoli)
4. 🔒 Creamy Garlic Pork Chops (Roasted Broccoli)
This keeps collaboration incremental — Kevin can iteratively carve a locked set over multiple turns without ever losing meals he's already accepted.
Phase 2 — Confirmation (explicit only)
The menu is real only when Kevin explicitly confirms. Accept signals like:
- "Go with Option A"
- "Lock that one in"
- "That's the plan"
- Or unambiguous equivalent.
Ambiguous signals ("yeah that looks good", "sounds fine") are NOT confirmation. Confirm explicitly: "Locking Option A for the week of YYYY-MM-DD — confirming?"
Phase 3 — Write to disk
Once confirmed, immediately write to:
projects/meal-planning/menus/YYYY-MM-DD.md
where YYYY-MM-DD is the Sunday that starts the week. Weeks run Sunday → Saturday.
Example: a menu confirmed for the week of Sunday April 19 2026 → Saturday April 25 2026 lives at ~/Documents/meal-planning/menus/2026-04-19.md.
Before writing: match every meal name to MEALS.md (see Meal matching below).
Menu file template:
# Week of YYYY-MM-DD (Sun–Sat)
## Dinners
- [canonical meal from MEALS.md] ([side], [side])
- [canonical meal from MEALS.md] ([side])
- [canonical meal from MEALS.md]
## Notes
- Source: Publix BOGO / Kroger sales highlights
- Adaptations: [variations from favorites]
- Confirmed: YYYY-MM-DD HH:MM (when Kevin locked it in)
Sides appear inline in parentheses after the meal. Drop the parens when a meal has none.
Day-of-week assignment is optional. Kevin decides per week whether to map meals to specific days. When he does want days, use this format:
## Dinners
- **Sunday** — Beef Tacos (Black Beans, Corn)
- **Monday** — Pork Burgers (Roasted Potatoes)
Default to the dayless list. Don't invent day assignments.
Optional ## Prep-friendly lunches section — include only when Kevin provides lunch plans; don't leave an empty section.
If a file already exists for that Sunday, ask Kevin before overwriting.
After writing:
memory_store a rotation summary so next week's planning sees it.
- Confirm back with the exact file path.
Meal and side matching
Every meal name in a menu file must map to an entry in projects/meal-planning/MEALS.md. Every side must map to an entry in projects/meal-planning/SIDES.md. Match before writing:
- For each proposed meal or side, find the closest match in the canonical list.
- If exact or close (same thing, different phrasing) → use the canonical name from the list. Don't preserve shorthand.
- If no reasonable match exists, it's new — confirm with Kevin before (a) adding it to the list and (b) including it in the menu.
Examples:
- "Spicy Turkey Ramen Green Beans" →
Spicy Turkey with Ramen and Green Beans (MEALS.md)
- "broc" →
Steamed Broccoli or Roasted Broccoli (SIDES.md — pick based on context, or ask)
This keeps MEALS.md and SIDES.md as the single sources of truth and prevents near-duplicate entries drifting over time.
Side recommendations
When drafting options, include 1-2 relevant sides per dinner drawn from SIDES.md. Kevin can accept, swap, or decline per meal.
Pairing judgment (not exhaustive — use taste):
- Tex-Mex / tacos → Black Beans or Pinto Beans + Corn
- Burgers → Roasted Potatoes, Roasted Veg Medley, or Roasted Onions
- BBQ / ribs → Corn + Black Beans or White Beans
- Grilled chicken → Roasted Carrots + Roasted Broccoli
- Pasta / Italian → Steamed Broccoli or Roasted Veg Medley
- Hearty one-pot dishes → often self-contained; skip sides
Don't force sides onto every dinner. Some meals are complete on their own (e.g. Spicy Turkey with Ramen and Green Beans has greens built in). When in doubt, propose and let Kevin decide.
Execution workflow (first call of a planning session)
- Read project context.
CONTEXT.md, MEALS.md, TOOLS.md, and ls projects/meal-planning/menus/ for recent history.
- Query sales.
grocery_deals tools for Publix/Kroger (ZIP 37188).
- Analyze constraints. Filter BOGO/Sales, exclude seafood (occasional fish OK), check rotation via
memory_recall + recent menu files.
- Generate Options. Propose 2-3 labeled options (A, B, C) — 3-5 dinners + prep-friendly lunches each, numbered 1-N within each option. Highlight sale-based ingredients. Suggest variations of favorites (beef tacos → chicken nachos).
- Iterate. Ask clarifying questions when constraints are genuinely ambiguous; don't interrogate. Refine options based on Kevin's feedback. Stay in Option-language. When Kevin names specific slots to keep or swap (e.g.
A2-A4, lock A1), follow the partial-lock workflow in Phase 1.5 — don't regenerate locked meals.
- Confirm. Drive toward an explicit lock-in on one option.
- Write + log. Write the menu file,
memory_store the summary, report the path.
Proactive clarification template
Use sparingly, only when constraints are truly unclear:
- "What's the primary protein goal this week?"
- "Any specific sales I should prioritize?"
- "Leftovers from last week to incorporate?"
- "Full week or a lighter plan?"
Tool integration
grocery_deals_publix_deals / grocery_deals_kroger_deals / grocery_deals_search_deals (Hermes MCP naming — see references/mcp-setup.md for server config)
mcp_session_search — rotation tracking, past menu recall
mcp_memory — user preferences (action='add' for new prefs)
mcp_read_file on projects/meal-planning/MEALS.md — meal database
mcp_write_file to update MEALS.md / CONTEXT.md when Kevin confirms a change
Anti-patterns
- Treating a chat-only proposal as "the menu". If it's not in
~/Documents/meal-planning/menus/, it's an option, not a menu.
- Inferring confirmation from soft signals ("that sounds good"). Require explicit lock-in.
- Dropping Option-labeling once one candidate seems favored — stay in A/B/C until the file is written.
- Writing the menu file before explicit confirmation. Drafts stay in chat.
- Duplicating preferences inline in this file (they drift —
CONTEXT.md is the source of truth).
- Suggesting meals Kevin has already ruled out (check MEMORY.md +
memory_recall first).
- Skipping the sale lookup — this skill is sales-driven, not vibes-driven.
- Using workspace-relative or
~/projects/meal-planning/ paths. Reference data lives at ~/.hermes/skills/meal-planner/references/, menus at ~/Documents/meal-planning/menus/. If you see projects/meal-planning/ in a path, it's wrong — that's a zeroclaw artifact.
- Regenerating a whole option when Kevin only asked to change specific slots. If Kevin says "replace A2", only A2 changes — A1, A3, A4 stay verbatim. Don't re-draft what's already accepted.
- Renumbering slots mid-session.
A2 is A2 for the entire conversation, even after swaps. A replacement for A2 is still called A2, not A2.5 or a bumped index.
- Inventing a new Option letter when refining. Edits to Option A produce "Option A (v2)" — not Option D. Only create a new letter when Kevin explicitly asks to merge or fork.
- Skipping the lock echo. Before generating a replacement, restate what's locked so Kevin can catch mis-parses before waiting on new ideas.