| name | init |
| description | One-time onboarding for meal-planner. Scaffolds the data-home layout (meals/, menus/, boards/, deals/, docs/knowledge/, plans/), writes config.yml with the user's ZIP code and stores, and seeds meal cards from an existing meal-history corpus, a short interview, or empty. Use when the user runs /meal-planner:init, sets up meal planning for the first time, or points the plugin at a new data repo. |
meal-planner: init
Onboard a data home for weekly meal planning. Run this once per data repo. All
work happens in the current working directory (the data home) — never in the
plugin install directory.
${CLAUDE_PLUGIN_ROOT} is the plugin's install path; the wrapper script lives at
${CLAUDE_PLUGIN_ROOT}/scripts/meal_deals.py and runs via uv run.
Steps
-
Scaffold the layout. Run:
uv run "${CLAUDE_PLUGIN_ROOT}/scripts/meal_deals.py" scaffold --data-home .
This creates meals/, menus/, boards/, deals/, docs/knowledge/,
plans/, initialises a git repo if the directory isn't one yet, and writes a
config.yml stub. It is idempotent — safe to re-run.
-
Set the ZIP and stores. Read config.yml. If zip is empty, ask the user
for their ZIP code (the grocery-deal fetch needs it) and which stores they
shop — default publix and kroger, the only two the fetcher supports. Write
the values into config.yml.
-
Seed the canonical rosters — MEALS.md and SIDES.md. These are the
source of truth: one meal (or side) per line. Ask how they want to start:
- From a corpus — if the user has prior meal-history notes, session logs,
or a list of meals they like, seed from it:
meal_deals.seed(data_home, [corpus_text], context_text=preferences_text, sides=sides_text, extra_meals=other_meals_text). It parses the liked
dishes into MEALS.md, writes SIDES.md, folds in the tracked-brand
watchlist and avoid/limit preference rules to config.yml. Pass every meal
source you have (multiple session logs, a hermes/openclaw MEALS.md) so the
roster is the full union, not a subset.
- Interview — no corpus: ask for the meals the family likes and their go-to
sides, then
meal_deals.write_roster(data_home, "MEALS.md", names, title="Meals") (and SIDES.md). Record preferences in config.yml.
- Empty — scaffold only; the rosters fill in as they plan.
Cards stay lazy. Do not write a meals/<slug>.md card per dish — that's
the limiting dump this design replaces. A card is born the first time a meal
is actually cooked (the retro does this), and holds its ingredients, cook
history, and verdicts from then on. The roster answers "what can we make";
cards answer "what does this specific meal need / how has it gone".
-
Reconcile any existing menus. If menus/ already has files, run
meal_deals.reconcile_menus(data_home) and report any dinners not in the
roster — never fabricate entries; offer to add them to MEALS.md explicitly.
-
Confirm. Report roster size (meals + sides), ZIP, stores, and preference
rules captured, and point the user at /meal-planner:week.
Notes
MEALS.md / SIDES.md are plain one-per-line rosters. Users can hand-edit
them; a re-seed merges without dropping manual additions or duplicating.
- Meal cards (lazy) carry YAML frontmatter (
name, ingredients, brands,
last_cooked, times_cooked, verdicts, variations, prices_paid). They
accrue from cooking, not from onboarding.
- Preference rules (e.g. "avoid ground chicken (max 1/week)") drive the rotation
guard and drafting in
/meal-planner:week.