1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
|
# 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)
|