# Food App — Requirements (pivot to web-first) > Written 2026-06-22, after reviewing `research.md` and interviewing Tom. > This supersedes the Caine-centric design. Pairs with `research.md` (current > state) — this doc is the *target*. ## The pivot, in one line Caine (the Matrix LLM assistant) was never really used — it cost too much per call. **The web UI becomes the primary interface.** An LLM can come back later as an MCP server riding on the existing claude.ai subscription (no per-call cost), but that's a later phase, not now. ## The one constraint that wins **Ease of use beats everything.** This is a single-user personal app, low stakes. When a requirement trades correctness, completeness, or robustness for less friction, friction wins. Specifically: fewer fields, fewer taps, fewer decisions, nothing that nags, and updating the pantry should feel like nothing. **Mobile-first, not mobile-also.** The pantry is used standing in the kitchen or at the shop, on a phone — that's the primary device, and it's fiddly today. Design for a one-handed phone screen first; desktop is the afterthought. Concretely: big tap targets (state changes and add are thumb-sized, not table-cell links), no tiny number inputs or cramped rows, single-column layouts, no horizontal scroll, controls reachable in the lower half of the screen. If something works on the phone it'll be fine on desktop; the reverse is what's been failing. Everything below is judged against that. --- ## Priorities (Tom, 2026-06-22 — current call) In value order: 1. **Pantry: make it a bit nicer in the web UI.** Not a ground-up rebuild — incremental polish (the In/Low/Out state + fast add from §2), enough that keeping it accurate isn't a slog. It needs to be *reasonably* accurate precisely because of #3. 2. **Add some auth** (§1) — login once, long session. 3. **MCP server with claude.ai — the highest-value piece.** The whole point: stop hand-reciting "here's what's in my pantry" every time. Claude reads the pantry directly in cooking mode. Almost certainly also the *lowest-friction update path* — say "I used the last of the noodles" and Claude writes it back — which is the real answer to the pantry-is-tedious problem. Everything else in this doc (web what-can-i-cook, shopping rethink, web cook-logging, fixed recipes, §4.1 substitutions) is **deferred** — nice, not now. Detailed below for when we get there. **The synergy that justifies the order:** #3 is *why* #1 only needs to be "a bit nicer" rather than perfect. If Claude can both read and update the pantry conversationally, the web UI becomes the glanceable / manual fallback, not the primary data-entry surface. So don't over-invest in pantry UI — invest in making the data MCP can serve trustworthy and easy to nudge. --- ## 1. Auth — log in once, then forget it Decision: **a simple login page + a very long-lived session** (≈1 year cookie). Log in once per device; never get prompted again on that device. - Standard Django session auth (`login_required`) on all `/app/` views — no HMAC, no signed requests, no per-request secret. (The HMAC idea was heavier than needed for one user.) - Set `SESSION_COOKIE_AGE` long (~1 year) and `SESSION_EXPIRE_AT_BROWSER_CLOSE = False` so the session survives restarts. - One user account is enough. `/api/` keeps its existing token auth for the future MCP client. - This also lets us drop the `@csrf_exempt` hacks — a logged-in session has a real CSRF token, so HTMX POSTs can be protected normally. Security is explicitly *not* the top priority, but this gives a real baseline (no more wide-open `/app/`) at near-zero friction. ## 2. Pantry — the redesign (this is the heart of it) Today the pantry is "all just frustrating": adding is slow, quantities drift out of date the moment you cook, expiry dates are fiddly to set and chase, and it's a separate chore that's easy to forget. The fix is to **stop tracking the pantry like a spreadsheet and track it like a fridge you glance into.** ### 2.1 Track presence, not precise amounts Replace exact decimal quantities as the primary signal with a simple state: > **In stock · Running low · Out** - One tap to change state (e.g. cycle In → Low → Out, or three buttons). - Quantity becomes *optional metadata* (a free note like "½ bag", "3 left"), never required, never the thing the app reasons about. - This kills the "quantities drift after cooking" problem outright — you don't maintain a number, you flip a flag when you notice. > **Open decision:** some items genuinely want a rough count (eggs, noodle > nests). Proposal: keep the optional quantity note for those, but the matcher > and shopping logic only ever look at the In/Low/Out state. Confirm before > building. ### 2.2 Fast add - A single search box: type → autocomplete against known ingredients (and aliases) → tap to add. Defaults its unit/location from the `Ingredient` record, state defaults to "In stock". Zero further fields needed. - If the name isn't known, add it inline in the same flow (it auto-creates the ingredient, like the API already does). - **Quick-add chips** for staples and recently-used items — one tap, no typing. - On mobile this is the make-or-break screen: the search box and chips sit near the bottom (thumb reach), adding an item is one tap, and the In/Low/Out control on each row is a proper button, not a fiddly inline link. The current table-of-tiny-actions layout is exactly what's being replaced. ### 2.3 Expiry stops nagging - Expiry dates become fully optional and de-emphasised. No required date entry. - Instead of chasing exact dates, a lightweight **"use soon"** flag you can tap on an item (and an optional date if you actually care for something specific). - Keep the existing freezer rule (frozen = no expiry). Defrosting (freezer → fridge) can set a soft "use soon" instead of computing a hard date. ### 2.4 Updating the pantry as a by-product, not a chore The biggest win against "I forget to update it": make other actions update the pantry for you, so the standalone chore mostly disappears. - **Logging a cook** optionally flips the ingredients it used toward Low/Out (replaces the brittle decimal-deduction logic). - **Checking off a shopping item** marks that ingredient back to "In stock" in the pantry — closing the buy → restock loop automatically. ## 3. Recipes & "what can I cook" — keep it, but make it one implementation Decision: **keep meta-recipes and the what-can-i-cook matcher** — it's the part Tom actually wants. But: - There are currently **two separate matchers** (`views.what_can_i_cook` JSON and `views_htmx.recipes_page` HTML) that have already drifted. Collapse to **one shared function**; both the page and any API/MCP call use it. (This is also the "two implementations hanging around" Tom flagged.) - The matcher moves to **presence-based**: a required slot is satisfied if any of its options is In (or Low) — no quantity comparison. Simpler, and matches the new pantry model. - Servings is currently hardcoded to 2 in the web page; with a presence-based matcher, servings stops mattering for "can I cook this", so we can just drop the servings input from that view. - Fixed `Recipe`s: keep the model, but **de-scope the URL import for now** — it never links ingredients (see `research.md` §7), so imported recipes are half-broken. Cooking ideas live in claude.ai cooking mode anyway. Don't invest here until the MCP phase, if ever. ## 4. Shopping list — rethink the flow Tom was explicitly unhappy with the current flow. Requirements: - Generation stays smart (staples that are Out, "use soon" items, gaps for required recipe slots) but should be **additive and forgiving** — generating again shouldn't wipe manual additions or duplicate. - Checking an item off should (a) cross it out and (b) restock it in the pantry (see §2.4). - Needs a clear "done shopping" action that tidies the list. - Keep it dead simple — a phone checkbox list, grouped by aisle/section. ### 4.1 "Can't find it at the shop" — substitutions (important to Tom) A recurring real pain: Tom goes to the shop to buy something and it's not there, and then he's stuck. He wants help *in the moment* knowing what else works. - **Partial fix available now, no LLM needed:** the meta-recipe slot model *is* a substitution table — a protein slot already lists pork mince OR chicken, etc. So a shopping-list item that came from a recipe slot can show "alternatives that fit the same slot" inline. If you can't find pork mince, the list shows the other proteins that recipe accepts. - **Richer substitutions need the LLM/MCP (Phase 2):** general swaps the app has no data for ("no fresh basil → dried is fine", "no crème fraîche → use yoghurt") require world knowledge. That's a claude.ai-via-MCP job: it reads the shopping item + recipe context and suggests a real-world substitute. - So: ship slot-based alternatives in the web UI now; treat "smart, open-ended substitution at the shop" as a headline use case for the MCP phase. ## 5. Cook log — make it usable from the web - Add a **web UI way to log a cook** (currently API/admin only): pick a meta-recipe, tap the slot choices you used, optional rating + note, save. - `log-cook` must accept and store `rating` (the model field exists; the endpoint ignores it today). - Route cook-logging through model validation so the "exactly one recipe link" rule is actually enforced (today's `log_cook` bypasses `clean()`). ## 6. Cleanup / housekeeping (do first) - **Run `/simplify` first**, before feature work, to clear the obvious cruft (duplicate matcher, dead `filterset_fields`/`search_fields` with no django-filter installed, the freezer-first deduction bug if deduction survives the redesign). - Production baseline: `DEBUG = False`, real `SECRET_KEY` from env. Low priority but cheap. ## 7. Later — MCP (Phase 2, optional) Once the web UI is solid, wrap the existing API in an **MCP server** so claude.ai "cooking mode" can read the pantry and (maybe) log cooks. This is the integration Tom actually wanted from Caine, without the per-call cost. Explicit non-goal for now — listed so the API stays MCP-friendly in the meantime. Two things this phase unlocks (and why it's worth keeping the API clean): - **Cooking blocks still work.** MCP only *feeds data into* the claude.ai conversation — it gives Claude tools to read the pantry. It does not change how claude.ai renders cooking mode. So Claude pulling ingredients from the food app and Claude producing its nice formatted cooking blocks are independent: you get the blocks *and* they're grounded in your actual pantry. - **Smart shop-floor substitutions** (see §4.1) — the open-ended "this isn't on the shelf, what else works?" question is the main thing MCP buys over the built-in slot alternatives. --- ## Build order (current) 1. `/simplify` pass (running) — behavior-preserving cleanup of the existing code so the next steps build on something tidy. 2. **Pantry polish** — In/Low/Out state + fast add in the web UI (§2). Scoped to "a bit nicer", not the full redesign. 3. **Auth** — login page + ~1-year session, drop `@csrf_exempt` (§1). Fold the cheap production baseline (DEBUG off, real SECRET_KEY) in here since we're touching settings anyway. 4. **MCP server** — the goal. Expose pantry **read and update** to claude.ai cooking mode, so Claude can both see what's in stock and write changes back. Reuses the existing `/api/` + token auth. Deferred until after the above (still wanted, just not now): web what-can-i-cook, §4.1 slot-based substitutions, shopping flow rethink, web cook-logging. ## Open decisions to confirm before building - **Quantity**: drop exact decimals entirely in favour of In/Low/Out + an optional free-text note? (§2.1) — recommended yes. - **Fixed recipes**: park the URL-import feature rather than fix it? (§3) — recommended yes. - Anything here that's actually *more* friction than today — call it out. --- ## Original notes (Tom, preserved) + interface: never really ended up using caine due to cost issues. was a nice idea though. + if we went down the route of llms again, maybe a mcp. could claude.ai connect with it + current food flow is using claude.ai and its "cooking mode", issue is that it doesnt integrate with my pantry + pantry was tedious to update, not sure the best approach here. might just have to tough it out + webui interface was generally clunky + security not the highest prio but would be good to have some basic auth + lets run the /simplify skill firstly + tagging recipes never really worked, feels like theres two implementations of it hanging around + auth just scares me, i want the least friction way of doing this. a hmac secret or something might be nice for fe <> be and a simple log in page would be good. although i really dont want to have to log in every time + pantry: it's all just frustrating at the moment (adding slow, quantities drift, expiry fiddly, easy to forget)