👋 Show HN — built by a two-person household in Norway

Plan the week.
Shop once.
Cook well.

Taverna is an iOS meal planner with a shared, realtime shopping list and a recipe library that actually understands its ingredients. We built it because meal kits were teaching us an expensive lesson — this page is the story of what we learned along the way.

Download on theApp Store iOS · English & Norwegian
App Store link coming with launch
The Fill my week sheet proposing a dinner for each weekday
Taverna home screen: tonight's meal, the week ahead, smart shopping and a discover feed
A recipe page with servings, time, and allergy chips

01 · Why we built it

Meal kits were half right

We genuinely liked meal kits. Dinner decided, ingredients at the door, no 5 pm staring contest with the fridge. But two things kept nagging us.

The math. Per portion, a kit costs restaurant-adjacent money for grocery-store food. Cook the very same dinners from a regular store and you pay roughly half.

The trip you make anyway. Kits only cover dinners. Breakfast, lunches, snacks, coffee — you're going to the store regardless. Once you're standing in that aisle, the kit's one big convenience has mostly evaporated.

Taverna keeps the part we loved — a week of dinners decided up front, every ingredient accounted for — and drops the markup. Plan the week, push the whole thing onto one shopping list, add your milk and coffee to the same list, shop once.

Meal kitper portion
Same dinners, from the grocery store≈ half

…and the store trip was already happening for everything the kit doesn't cover.

02 · The planner

A week of dinners in one tap

The planner is the spine of the app. Drop recipes onto days yourself, or hit the wand: Fill my week proposes a dinner for every empty day — a blend of your own favorites and our recipe library, with variety caps so you don't get chicken four nights straight or three pasta dishes in a row. Don't like Tuesday? Reroll just Tuesday.

When the plan looks right, one more tap adds every ingredient from every planned meal to a shopping list — merged, deduplicated, and sorted by store aisle. That's the meal-kit feeling, minus the invoice.

Fill my week: proposed dinners for Monday through Thursday with per-day reroll buttons and an Add to plan button

03 · The shopping list

Built to survive two people in one store

Version one synced the shared list on pull-to-refresh. It felt fine — right up until we were both in the store at the same time, splitting the aisles. I'd check off the milk; her phone, showing a stale copy, would happily let her grab another one. Then one of our writes would clobber the other's. We had built ourselves a race condition with a shopping cart.

So we rebuilt the lists on Supabase Realtime: every check, add, and edit streams to the other phone over a websocket in well under a second, with Postgres row-level security deciding who's allowed to see what. No refresh button, no cache to invalidate, no second milk.

Your phone

Bananas
Oat milk
Coffee beans

Her phone

Bananas
Oat milk
Coffee beans

Checked on one phone, struck through on the other — live, while you're both shopping.

04 · AI in the kitchen

Models write recipes.
A QA gate tastes them first.

Language models are honestly good at recipes — describe a craving, list what's in the fridge, or upload grandma's handwritten card, and you get a clean, structured recipe with sensible steps. Suggestions stream in as they're generated; the first idea lands in about three seconds.

Mostly good, that is. One evening a peanut sauce instructed us to add much more water than it could ever need. Watery peanut soup is a memorable way to discover your QA gap.

Every recipe now passes a post-processing QA step before we trust it: deterministic checks first (every ingredient used, every referenced amount present), then a second model does a culinary sanity pass — are quantities plausible for the servings, are steps complete and in order, is the food safety sound? Recipes in Norwegian get a language pass too, because a model writing outside English drifts more than you'd hope.

Create screen: cook something specific, get suggestions, explore meal ideas, create from an ingredient list, or upload your own recipe

05 · The pivot

From recipe generator to recipe library

Generation was originally the whole app. But watching ourselves use it, we noticed something: most nights you don't want to describe a dinner to a model — you want to look at good dinners until one looks like tonight. Generating on demand is a blank-page problem wearing an AI costume.

So we flipped it. We pre-generate recipes in bulk, run every one through the QA gate, review them, give them proper photography, and publish them into a browsable library — so the app opens on inspiration instead of an empty text field. On-demand generation is still there for the specific cravings; it's just no longer the front door.

That pivot is also what forced the most interesting engineering in the app — because a big recipe library is only as smart as its ingredients. Read on.

My Recipes: a grid of recipe cards with photos, cooking times and servings

06 · The keystone

Three peppers walk into a shopping list

Put a few recipes on the plan, add them to a list, and the cracks show immediately: one recipe wants black pepper, the next coarse black pepper, the third just pepper. To a database those are three different things. To you, standing in the spice aisle, they are very much one jar.

The fix is a canonical ingredient bank: ~600 ingredients (and growing), each with a language-neutral identity — a slug like black_pepper — and everything useful hanging off it:

black_pepper
namesen black pepper · nb sort pepper (+ aliases)
aisleSpices & condiments → sorts your list
stapleyes — skipped when filling lists
allergensnone

One boring table, a surprising amount of product:

Allergen & diet filters that don't lie. Each bank ingredient carries its allergen classes, so a recipe's warnings and its vegetarian/vegan/gluten-free/dairy-free flags are derived from what's actually in it — not from the generating model's self-report. That matters: when we compared, the model under-claimed diets roughly half the time. Computed beats confessed.

Lists sorted like the store. The category doubles as a store aisle, so a week's shopping walks front-to-back instead of ping-ponging between dairy and produce.

No salt, seven times. Staples like salt, oil, and water are flagged, so filling a list from five dinners doesn't bury the actual groceries under pantry noise.

07 · Under the hood

Growing the library on purpose, not vibes

“Generate 1,000 recipes” sounds like a button. It's actually a coverage problem: left alone, a model gravitates to the same crowd-pleasers, and you end up with forty carbonaras and no soup.

We steer batches with coverage matrices — cuisine × protein for mains, separate type grids for breakfasts, desserts, drinks, and baking, plus per-diet targets. Every cell has a target; gaps become the next generation batch. The batch runner streams ~65 recipes a minute, and prompt-caching the ingredient bank cut input cost by about 10×.

Each per-language matrix tells us exactly where the library is thin before a user ever notices.

MAINS — CUISINE × PROTEIN ItalianNorwegianThai MexicanIndianFrench GreekJapanese chick.beefpork fishseaf.veglegum.
target met partial gap → next batch

And when a recipe invents an ingredient we've never seen? That's not an error — it's how the bank grows. The unknown ingredient is flagged unresolved with a proposed slug parked right on the recipe, and a small pipeline takes it from there:

  1. Flagged

    Generation emits garam_masala; it's not in the bank, so the recipe carries it as unresolved.

  2. Drafted by LLM

    A model drafts the full canonical record: English + Norwegian names, aliases, allergens, aisle category, staple flag.

  3. Reviewed

    A human eyeballs the draft in the admin tool. Ten seconds, catches the silly stuff.

  4. Banked

    Approved records join the bank — dedup by slug, so it can only ever exist once.

  5. Backfilled

    Every recipe waiting on that slug auto-links, and its allergen + diet flags are re-derived from the now-complete picture.

08 · The details

Small things that make the kitchen nicer

The big systems are only half the app. The other half is what it feels like at 17:42 with onions in the pan and a phone on the counter. Cook Mode shows one step at a time, full screen, with exact amounts inlined into each step and scaled to your servings — no scrolling with buttery thumbs. Steps that need timing carry a one-tap timer that keeps counting in a floating pill wherever you go next.

Cook Mode step with an inline ingredient amount and a Start 4 min timer button
Recipe details with servings stepper, dietary and allergy chips, and gram-precise ingredients
🔥

Cook Mode

Full-screen, one step at a time, with exact amounts inlined into each step — scaled to your servings.

⏲️

One-tap timers

Steps that need timing carry their own timer. Tap it, cook on; a floating pill counts down over whatever screen you're on.

🥜

Honest allergy chips

“Avoid: nuts” on a recipe comes from its ingredients' allergen classes, not from a model's mood.

🧺

Aisle-sorted lists

Sort a list by store section and walk the shop once, front to back.

🤝

Sharing built in

Share recipes, week plans, and lists with friends — with pushes, and realtime where it counts.

💬

Ask the recipe

A small chat on every recipe for the “can I substitute crème fraîche?” moments.

For the curious

The stack, briefly

Two people, nights and weekends, so the architecture optimizes for staying small.

SwiftUI

Native iOS app. Serif titles, warm palette, no web views.

Supabase

Postgres + Auth + Realtime. The app talks to the database directly; row-level security is the API.

Azure Functions

A small Python app that exists only for AI work: generation, QA, images, pushes.

Claude

Sonnet writes recipes as structured output; Haiku streams suggestions and runs the QA gate.

Taverna home screen

Dinner, decided.

Taverna is on its way to the App Store. The badge below goes live the moment it lands — until then, we're in the HN thread answering questions.