| name | shopping-questions |
| description | Answer the user's questions about their shopping — both what they've already bought and what they could buy — by querying the shopping.db store. Use this whenever the user wants to recall a past purchase ("what was that nice gochujang I bought?", "did I get a fancy soy sauce last year — was it Japanese or Korean?"), asks what / when / how much they've bought, wants recommendations or to explore a cuisine or ingredient ("I'm in the mood for Malay food, what do you suggest?"), or asks whether a shop stocks something or what a good substitute would be for an unstocked item ("they don't have Camargue rice — what's close?"). Reach for it even when the question is vague or chatty. NOT for onboarding or removing shops (that's the manage-shops skill) or refreshing a catalogue. |
Answering shopping questions
Everything lives in the SQLite store shopping.db. You answer questions with a
two-part move: queries.py retrieves, you judge. The retrieval is
deliberately broad and noisy; the value you add is reading the results and
reasoning over them.
There are two question shapes:
- Recall — search what they bought ("what was that X I got?").
- Discovery — search the catalogue, including substitution when the literal
thing isn't stocked ("explore Filipino food", "what's like Camargue rice?").
The golden rule: retrieval is noisy — always read and discard
queries.py uses LIKE, which is blunt. Never trust a row's mere presence:
"red rice" surfaces a £120 cooking pot; "camargue" alone matches
chocolate; "adobo" matches Mexican products (a cross-cuisine
homonym); gift sets and cookbooks list dozens of ingredients in their blurb.
- A term in the title means the product is that thing ("Bombom Korean
Gochujang…"). A term only in the description is weak ("this marinade pairs
well with soy sauce" is not a soy sauce).
Two levers cut the worst of it, both built into the helper:
- Ingredient filter (default): restricts the catalogue to
product_type='Ingredients', dropping cookware / tableware / bundles /
cookbooks. Pass --all only when the user genuinely wants those.
- Title-matches first: results are ordered so "the product is an X" beats
"the description mentions X".
Even after these, you still read every candidate and bin the junk before
answering.
The helper
uv run python queries.py purchases "gochujang" [--since 2025-01-01] [--until 2026-01-01] [--shop souschef]
uv run python queries.py catalogue "carnaroli" [--all] [--shop souschef]
uv run python queries.py profile
The same functions are importable (search_purchases, search_catalogue,
list_purchases) if you need to compose something custom.
Recipe 1 — Recall: "what was that X I bought?"
queries.py purchases "<keyword>".
- Read and filter. Discard rows that only matched on a description mention.
- Answer with the product, when it was last bought, and the reorder URL — and
temper any "you still have it" implication by recency (see "Bought" is not
"still has" below). If they asked an attribute ("Japanese or Korean?",
"which brand?"), read the title/description and say which, with a word on why.
- If nothing genuinely matches, say so and offer the near-misses or a wider
search. Don't manufacture a memory.
Verified example: "that nice gochujang paste" → purchases "gochujang" →
Bombom Korean Gochujang Hot Sauce, last bought 2026-03-31, with its link.
Recipe 2 — Time-bounded recall
Add --since / --until (UK sense: "last year" = the previous calendar year;
today's date is in the system prompt). If the window is empty, widen it and say
you widened.
Verified example: "that fancy soy sauce last year" →
purchases "soy sauce" --since 2025-01-01 --until 2026-01-01. Reading the
results shows they're marinades and hot sauces that merely mention soy sauce —
no standalone soy sauce. The honest answer: "You didn't buy a dedicated soy sauce
in 2025; the closest were these Korean sauces — want me to look further back?"
Recipe 3 — Taste-aware discovery & substitution
This is where culinary knowledge turns a thin catalogue into good suggestions.
- Read their taste.
queries.py profile, then infer the pattern — both the
forms (pastes, ferments, chilli oils, marinades, special rice…) and the
cuisines they lean on. Weight everything below toward it.
- Search the literal thing.
catalogue "<cuisine or ingredient>".
- Assess coverage honestly, then go adjacent. If results are thin or absent,
don't stop — use your knowledge to brainstorm specific adjacent terms and
search each:
- Ingredient: named varieties and classic substitutes — for "Camargue rice"
search
"red rice", "carnaroli", "wild rice", "black rice", not
the proper noun (which matches noise).
- Under-stocked cuisine: its flavour anchors and shared-pantry staples — for
Filipino:
"calamansi", "banana ketchup", "coconut vinegar",
"fish sauce", "soy sauce", "coconut", "pandan". Neighbouring cuisines
that share a pantry are fair game.
- Present substitutes in this shape (it mirrors how the user likes
hard-to-find-ingredient notes): the product, why it's close, and what it
won't quite cover flavour/texture-wise. Be candid about genuine gaps — "Sous
Chef doesn't really do Filipino; banana ketchup and calamansi vinegar are
about it" is a better answer than a padded list. And when you note they already own a
component for a dish, run it through the recency check below — they may have
bought that gochujang months ago and finished it.
Verified examples:
- "They don't stock Camargue rice" — actually they do (Organic Camargue Red
Rice, £5.90), found via
catalogue "red rice" not "camargue". If they
didn't: Carnaroli (similar chew, less earthy/nutty), Chinese Black Rice
(nuttier, stickier, bleeds colour), Red Wild Rice (chewier, grassier).
- "Explore Filipino" — honest: the catalogue is thin. Real finds are Baron
Banana Ketchup (a genuine Filipino staple) and Calamansi Vinegar (the citrus
acid behind so much Filipino food — sharper, less floral than fresh calamansi).
Then, leaning on their Korean/SE-Asian taste, point at the soy–vinegar–garlic
adobo backbone they can build from stocked soy sauces and vinegars, noting
what's missing (no fresh calamansi, no bagoong shrimp paste).
After a discovery investigation, offer to save the findings
A Recipe 3 run usually ends in a sizeable, link-heavy spread of recommendations —
worth keeping, not just scrolling past once. So once you've given more than a handful
of suggestions, offer to write the full findings to a sensibly-named markdown file
in the output directory (e.g. output/souschef-se-asia-ideas.md). Save the whole thing — the
colour and the reasoning (why each suits their taste, the honest gaps, the overlap
flags), not a bare list; that context is the point of the exercise. Format the links
per Reorder links, prices and availability below (inline markdown urls are fine in the external file). Offer it; don't write the file unprompted.
"Bought" is not "still has" — temper by recency and shelf-life
Purchase history tells you what the user bought and when — never what's in the
cupboard right now. Don't state possession as fact ("you've already got X");
they may have run through it long ago. queries.py purchases gives
last_ordered and a friendly "~N months ago" — lead with that, and slide your
confidence by how long that kind of thing lasts:
- Long-life pantry (dried rice/noodles, sealed spices, vinegar, soy, sugar,
honey): fine to assume they probably still have it for many months.
- Perishable / short-life (fresh kimchi, pickled veg, opened ferments, fresh
produce, anything chilled): assume it's likely gone after a few months.
- Non-consumable (cookware, tableware, books): they still have it — no rebuy.
Always include the date and the reorder link so they can judge for themselves —
your shelf-life guess can be wrong (some people burn through a sauce in a week).
Rough phrasing ladder, slid by the product's longevity:
- recent, or long-life → "you picked up X in (~N weeks ago), so you've
probably still got some — if you want to top up."
- a good while ago, and consumable → "you last bought X back in <month/year>
(~N months ago), so you've likely worked through it — worth re-adding: ."
- non-consumable, any age → "you've already got X (bought )."
Be useful and honest: surface the date, make a sensible guess at whether it's
run out, and never assert the cupboard's contents as fact.
Reorder links, prices and availability
Every matched product carries a url and current price. Include the link when
recall is about rebuying. If useful, compare what they paid (the purchase's
unit_price) to the current price and flag rises, or flag if a past purchase
is now delisted.
Write URLs in full, on their own line — never as an inline [text](url) link.
The user's terminal hides inline links: it shows only the link text and swallows the
actual URL, so a hidden link is useless to them. This applies everywhere you hand over
a link — in chat and in any file you write. (Note the prices/links come from the
catalogue snapshot in shopping.db; if it's gone stale a refresh may be due.)
When the answer is "no" or "not sure"
Empty results, description-only matches, and real catalogue gaps are legitimate
answers. Offer a wider search or an adjacent suggestion — never invent a purchase
or a stock item.
Files
queries.py — retrieval helpers + CLI (this skill's workhorse).
db.py — connection/schema for shopping.db.
- Onboarding or removing a shop is the separate manage-shops skill.