Hecate's weekly reading + 2nd-pass allergen verification
Five new context dimensions for the planner agent (and one quality
fix), bumping ENRICH_VERSION 3→4 so existing meta gets refreshed on
the next walk:
(A) Per-user fit score. Computed at plan-gen time from picker_profiles
× meta — no extra Sonnet calls. _compute_fit_score scores each
recipe 1-5 per household member based on cuisine match, protein
match, comfort_tier match, and tag overlap with that user's
historical picks. Renders in the recipe pool prompt as
'fit:cobb=5,abby=2,leia=3'. Gives Sonnet per-user signal to
bias AI-chosen slots toward whoever's home that week, AND makes
pick rationale explainable.
(B) Pairings per recipe. New meta fields:
pairings.serves_well_with: ["crusty bread","green salad",...]
pairings.drinks: ["pinot noir","iced tea",...]
Sonnet enriches both during the main pass. Foundation for future
"auto-suggest matching side" UX in multi-meal slots.
(C) Leftover potential 1-5. Per-recipe score: 1=eat-now-only (crispy
things, fresh salads), 5=actually BETTER as leftovers (stews,
braises, lasagna). Lets the planner thread Sunday's slow-cooked
pot roast into Monday's lunch slots intentionally.
(D) Mood scores. Per-recipe 1-5 ratings on:
cozy / summer_fresh / energizing / comfort
Independent dimensions — a recipe can score high on multiple.
Foundation for future weather/mood-aware planning ("rainy week
→ bias cozy>=4").
(E) Hecate's weekly reading. New TEXT column hecate_reading on
cauldron_meal_plans (migration 032). The plan-gen prompt asks
Hecate to write a 1-paragraph narrative voice description of the
week — "this week leans into the brisk turn of the season, three
hearty one-pots front-load your weekday energy, salmon Wednesday
for Cobb's gym push..." Confident, wise, theatrical voice. Pure
flavor, no functional impact, but makes Hecate FEEL like an
advisor not an opaque function. Plus the planner system prompt
now opens with the Hecate persona ("You are Hecate, Greek-
mythology witch goddess of crossroads, herbs, and magic — and
the family's meal planner"). Output schema gains a "reading"
field alongside "slots".
ALLERGEN VERIFICATION (the quality fix Cobb explicitly asked for):
- Sonnet sometimes flags pork=true on a sweet potato recipe via the
conservative-default rule. Cobb wants CLEAN data.
- New forge.verify_allergens — second Sonnet pass after main enrich
with a strict prompt: "name the SPECIFIC ingredient triggering each
allergen flag, or set FALSE." For non-anaphylaxis exclusions like
pork, set FALSE unless an actual pork ingredient is named. For
ANAPHYLAXIS allergens, conservative TRUE still applies.
- Cost: ~3s/recipe extra. Wired into enrich_recipes.run_enrich after
initial enrich; failure is non-fatal (falls through to original).
- Eliminates the pork-on-sweet-potatoes class of false positives.
Code restructure: forge.generate_plan now returns {slots, reading}
instead of just slots. _extract_plan_payload pulls both. Server-side
generate + regenerate paths unwrap and persist reading via the new
db.set_plan_hecate_reading. Plan template renders the reading in a
purple-bordered serif callout above the day grid.
Schema:
- migration 032 adds hecate_reading TEXT to cauldron_meal_plans.
- Cauldron_recipe_meta gets new fields persisted in meta_json (no
schema change there — JSON column already accommodates).
|
||
|---|---|---|
| cauldron | ||
| scripts | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| compose.yml | ||
| Dockerfile | ||
| LICENSE | ||
| README.md | ||
| requirements.txt | ||
cauldron
Mealie-backed AI meal planner + shopping list for the family. LAN-only,
internal tool. Mealie at recipes.sulkta.com is the source of truth for
recipes / meal plans / shopping lists; cauldron is the AI layer + Abby's
branded UI on top.
Status
v0.1 — backend bones (current). Ingredient sterilizer endpoint working. No UI yet; bearer-auth API only. Frontend + Authentik OIDC arrives in v0.2. Native Kotlin Android in v0.5.
Surface (v0.1)
GET /healthz liveness + clawdforge upstream
GET /api/recipes list Mealie recipes (paginated)
POST /api/sterilize/preview/<slug> dry-run AI parse, return proposals
POST /api/sterilize/apply/<slug> write parses back to Mealie
All routes except /healthz require Authorization: Bearer <ADMIN_BEARER>.
Architecture
Abby's phone (later: Kotlin app)
│
▼
cauldron (Flask, port 7790, LAN-only)
├─ Mealie API client ─── recipes.sulkta.com (source of truth)
├─ clawdforge client ─── 192.168.0.5:8800 (claude -p runner)
└─ Authentik OIDC (v0.2)
cauldron does NOT hold its own database in v0.1 — all state lives in Mealie. A small Postgres/MariaDB schema lands in v0.2 for Abby-specific prefs + chat history.
Ingredient sterilizer
Mealie's CRF parser is mediocre. Cobb's hand-typed recipes have lots of free-form quantity strings ("about 2 cups cooked white rice", "1 small handful kale", "a pinch of salt") that don't aggregate cleanly into a shopping list.
The sterilizer batches all ingredients of one recipe into a single Sonnet call (via clawdforge), gets back parallel structured parses, then on apply links each parse to existing Mealie food/unit records (creating any missing by name) and PUTs the recipe back.
Preview is non-destructive — review proposals before apply.
# Dry-run preview
curl -sS -X POST -H "Authorization: Bearer $ADMIN_BEARER" \
http://192.168.0.5:7790/api/sterilize/preview/spaghetti-bolognese | jq .
# Apply (creates missing foods/units by default)
curl -sS -X POST -H "Authorization: Bearer $ADMIN_BEARER" \
http://192.168.0.5:7790/api/sterilize/apply/spaghetti-bolognese | jq .
Deploy
ssh lucycd /mnt/user/appdata && git clone <gitea-url> cauldron && cd cauldron/build(or wherever the deploy convention lands)- Drop
.envat/mnt/cache/appdata/secrets/cauldron.env(chmod 600 root:root)CLAWDFORGE_TOKENis already populated by the bootstrap (seememory/2026-04-28.md)MEALIE_API_TOKEN— mint atrecipes.sulkta.com→ user → API tokensADMIN_BEARER— pick 32 bytes of entropySECRET_KEY— 32 bytes for Flask sessions
docker compose up -d --build- Smoke:
curl http://192.168.0.5:7790/healthz
Roadmap
- v0.1 ✓ — sterilizer backend + Flask shell
- v0.2 — Authentik OIDC, Abby-branded web UI, palette CSS, postgres for prefs
- v0.3 — meal plan generator (week → Mealie meal plan write)
- v0.4 — shopping list aggregator (read meal plan → consolidated grocery list)
- v0.5 — native Kotlin + Compose Android app (read-only shopping list + plan view)
Repo layout
cauldron/
├─ cauldron/
│ ├─ config.py env-driven config
│ ├─ forge.py clawdforge HTTP client
│ ├─ mealie.py Mealie API client
│ ├─ sterilizer.py ingredient parse + apply pipeline
│ └─ server.py Flask app
├─ Dockerfile
├─ compose.yml
├─ requirements.txt
└─ .env.example