Case study
Home Supply Predictor
A private PWA that tells you what’s about to run out around the house — before it does — from low-effort, natural-language logging. No forms. No stock counts. You just talk to it.
Your supplies
1 to keep an eye on
Keep an eye on
Tracking
The problem
Every “home inventory” app dies the same way: they make you do data entry. Barcode scans, quantity fields, stock counts — chores nobody keeps up. So the data goes stale and the app becomes useless.
The insight that reframes it: you don’t need to know how much you have — you need to know when you’ll run out. That’s a prediction problem, not a bookkeeping one.
The core design decision
It’s a ledger with math on top, not an inventory app. You never count stock. You log events in plain language — “bought coffee,” “ran out of TP,” “used half a gallon of milk” — and the app infers consumption rates and predicts run-out dates.
This one decision drives everything: the entire UI is a single natural-language text box. No forms, no dropdowns, no edit screens. An LLM parses what you type into structured events; a confirmation chip shows what it understood, with one-tap undo.
The clever part: a signal hierarchy that degrades gracefully
The app never requires effort. It works off whatever signal you give it, and gets sharper as you give more — automatically picking the best available signal per item:
| Effort | Signal | What it does |
|---|---|---|
| Lowest | Purchase cadence | Guesses from the gaps between buys. Useful on day one. |
| Low | Depletion markers | “ran out” / “almost out” — ground-truth pack lifespan, far cleaner than guessing. |
| Optional | Quantity balance | Log amounts and it tracks on-hand and predicts balance ÷ your usage rate. |
Crucially, quantity tracking is an optional overlay, per item — lazy items still work, precise items get precise. This solved the classic “backup blind spot”: because a prediction divides total stock by your consumption rate, having spares automatically pushes the run-out date out — no false “you’re low!” nag while three packs sit in the closet.
AI-native architecture (not AI-bolted-on)
The interesting engineering is in how the LLM is used — sparingly and structurally, not as a magic black box:
- Natural language is the whole interface. Typed entries → Claude parses to structured JSON commands (log / update / delete / correct) using structured outputs for reliability, with on-the-fly item creation and context so it resolves shorthand like “TP” and “that.”
- Chat that queries the database, not the context window. The “ask about my supplies” feature uses tool use — Claude calls parameterized lookup tools that filter in Postgres — instead of stuffing the whole history into the prompt. It scales to any amount of data and costs pennies per question regardless of history size.
- Conversational corrections. The same chat can fix data: “a&d cream should be 2,” “that milk was actually almond milk,” “delete the coffee purchase from July 5th.” Non-destructive count fixes apply instantly as append-only, auditable adjustment events; anything destructive is gated behind a preview-and-confirm handshake.
- Right-sized models. Parsing started on the cheapest model and was upgraded only once the task grew real judgment (disambiguating “toilet paper” vs “paper towel,” resolving weight-vs-fluid ounces by context). The prediction math itself uses no LLM at all — it’s pure, unit-tested TypeScript. AI where judgment is needed; deterministic code where it isn’t.
Engineering notes
- Prediction engine: a pure, dependency-free TypeScript module (recency-weighted rates, outlier down-weighting for bulk buys/vacations, guardrails against predicting on thin data) with a full unit-test suite — decoupled from the DB and UI so the math is provable in isolation.
- Security: Postgres Row-Level Security is the real trust boundary (every row scoped to its owner); the browser only ever holds a publishable key, and the LLM API key never leaves the server.
- Data model: an append-only event log; on-hand balance is derived (
SUMof signed quantities), never manually entered — which keeps corrections auditable and reversible. - Ships continuously: push to
main→ Vercel auto-deploys; schema changes as versioned SQL migrations.
How it was built
The whole thing was designed and built through conversational iteration with an AI coding agent (Claude Code) — starting from a written product spec and evolving through real daily use. That process is itself the interesting part:
- Real usage drove the design. Nearly every good decision came from dogfooding, not planning: a “toilet paper logged as paper towel” bug exposed over-eager fuzzy matching; a false “low stock” alert traced to a duplicate write from a network retry; mixed “oz” and “g” entries on coffee forced a proper units model. Each was diagnosed and fixed in the loop.
- Product judgment stayed human. The decisions that mattered — query-the-DB instead of context-stuffing, treat “used” as implying “open,” make counting an optional overlay rather than a requirement, confirm-only-on-destructive corrections — were product calls made through the work, with the agent as an extremely fast implementer and thinking partner.
It’s a working demonstration of building a real, shipped product with AI as the development environment — and of using AI deliberately inside the product, only where it earns its place.
What’s next
Retailer integration for one-tap re-ordering — the count model was built specifically to make that safe (you don’t auto-buy when you have spares), which is why quantity tracking exists at all.
It’s a private app, but I’m happy to give a live walkthrough.
Request a walkthrough