Case study 05 · Consumer software · assistant design

The Larder: an assistant that only answers from what it can see

An assistant that guesses is worse than no assistant. So I built one that answers from the cupboard and nothing else, then handed it to three critics whose job was to make it lie

Read
0invented ingredients under adversarial testing
3independent critics, every finding fixed same day
Local-firstno account, no server, the larder stays yours
Owned
The brief, the build, the agent's rules, and the fixes after crit
Scope
Stock, eat-first, shop list, waste ledger, and The Cook
Method
Build spec with named non-goals, three-critic panel, same-day fix wave
ProblemA household never quite knows what it owns to eat. Food expires behind other food, staples run out on the day you need them, and the weekly shop gets rebuilt from memory. The information already exists. It sits in the cupboard, where nothing can read it.
The callAn assistant is only worth having if the answer holds. So The Cook answers from stock and nothing else. Every ingredient it names is in the larder at the moment of asking, and every gap it hits gets said out loud.
ResultThree independent critics went at it with adversarial phrasing and it invented nothing. Every blocker they raised was fixed and re-verified the same day.

Try to make it invent something

The larder on the right is everything it knows. Ask it anything, then check the answer against the shelf

What can I make tonight?

A faithful reconstruction of the shipped agent, running the same rules on the same demo larder. It resolves recipes against live stock, so an ingredient it names is one it can point at.

Everything it knows

    Flagged items carry their reason in words as well as colour

    The Larder is a cupboard you can ask questions. Stock in, eat-first out, a shop list that fills itself from the gaps, and a waste ledger that keeps score honestly. It runs on the phone, with no account and no server behind it.

    The data was in the cupboard

    Ask a household what it owns to eat and you get a shrug. Food expires behind other food. Staples run out on the day you need them. The weekly shop gets rebuilt from memory, and dinner gets answered by a delivery app.

    None of that is a knowledge problem. The information exists. It is printed on the packets, sitting in the cupboard, in a form nothing can read.

    The rule came before the build

    The Cook answers one question. What can I make tonight.

    That question is exactly where an assistant is tempted to be helpful and wrong. Suggest a lovely pasta, quietly assume the garlic, and the person finds out at the hob.

    So the rule went into the spec before any code. Every ingredient The Cook names as owned exists in stock with a quantity above zero at the moment of asking. It never assumes one, never half-remembers one from earlier in the conversation, and never rounds a nearly-empty jar up to a yes. Recipes resolve against live stock and return their gaps as a list, so nothing unfillable gets folded into a suggestion.

    The temptation is always to be helpful. The discipline is answering from what you can actually see.
    The rule the whole build hangs on, written before the first line of code.

    The refusal is the feature

    The harder half of the rule is what happens when there is no good answer.

    When nothing in the larder makes a complete meal, The Cook says so in one line and stops. It offers the missing pieces onto the shop list rather than dressing the gap up as a suggestion. When someone asks about an ingredient that is not there, it opens with that fact before answering anything else. Ask it something outside the cupboard entirely and it says one plain sentence: it can only speak to what is in the larder.

    This is the part most assistants get wrong. A confident wrong answer costs more than a plain no, because the person acts on it.

    Try to make it invent something

    The larder on the right is everything it knows. Ask it anything, then check the answer against the shelf

    What can I make tonight?

    A faithful reconstruction of the shipped agent, running the same rules on the same demo larder. It resolves recipes against live stock, so an ingredient it names is one it can point at.

    Everything it knows

      Flagged items carry their reason in words as well as colour

      The dates it chooses to trust

      Eat-first sounds like sorting by best-before. It is not.

      An opened jar does not care what the label says. So each item's real date is whichever comes first, the printed best-before or the shelf life it has left since being opened. The agent sorts on that, and only items inside the eat-first window surface at all. The rest of the cupboard stays quiet, which is how the app avoids nagging about a spice rack that is perfectly fine.

      It is a small decision. It is also the difference between a list that reflects the cupboard and one that reflects the packaging.

      Three critics, one day

      The build went to a three-critic panel before it went near a person. Two returned one more pass. One escalated.

      What they found was worth finding.

      • BlockerThe bottom sheet had no focus trap, no Escape, and no dialog semantics
      • MajorThe clay urgency colour failed AA on small text at 3.15:1
      • MajorThe tab bar exposed no current state and the agent's thread had no live region
      • MajorNo save path guarded against a full quota, and emptying the larder had no undo
      • MajorThe sheet handle promised a swipe gesture that did not exist, and checkout stayed enabled on an empty list
      • MajorThe agent's subhead had drifted into a doubled negative that reads as machine-written, and one screen carried a speed claim nothing supported
      • PassedStock-only honesty held under adversarial phrasing, with zero invented ingredients

      Every blocker and major was fixed and re-verified the same day. Two of the findings were copy, which is the half of a crit most builds skip.

      What I decided not to build

      The non-goals were written into the spec before the first line of code, and they are the reason it shipped at all.

      No barcode database, because the browser API behind it works on Android and not on iPhone, and a feature half the users cannot reach is not a feature. No supermarket integration. No household sync. No cloud, because the moment stock syncs anywhere the privacy promise needs a lawyer instead of a sentence.

      The kill criterion went into the same document. If my own household stops opening it within four weeks of cataloguing the real kitchen, it does not get sold to anyone. It gets rethought.

      Writing the kill criterion before the build is how you find out whether you believe in the thing.
      From the build spec, section 8, alongside the review date.

      What it changed

      The Larder is the first place I set an assistant's honesty as a build rule rather than a hope.

      It became the pattern I reach for now. Ground the agent in state you can verify, make the refusal as considered as the answer, and test it with someone trying to break it rather than someone hoping it works.

      Reflection

      I expected the hard part to be the recipe logic. It was the register.

      An assistant that answers from live stock is straightforward to write. An assistant that stays plain when it has nothing good to say takes longer, because every instinct in the copy pulls towards filling the silence. The panel caught the two places I had filled it anyway.

      The rule I would keep on anything I build after this one: decide what it is allowed to know before deciding what it is allowed to say.

      Next

      02 · A symptom checker 5.5M people use