Recipe.sh

By
156 views
28 chef agents, four per request, gpt-oss-120b on Cerebras for generation and OpenAI for the in-recipe assistant, session storage for anonymous users and Supabase when you sign in.

**Note:: this project's DB may not be active. Reach out to jake@jjhdigital.com if so.

We've all been there: standing in front of an open fridge at 6 PM, staring at ingredients, with no idea what to make. Recipe.sh started as my answer to that, and then turned into an excuse to find out how far a small app built mostly around models could be pushed.

The short version: you describe what you have, you get four recipe ideas back, you pick one, and it gets written out in full. Then an assistant sits next to it so you can change your mind. Swap the nuts, scale it for two people, make it spicier. Below is how that actually works, not how I wish it worked.

Four ideas, four agents

The idea generator is a small multi-agent system. There are 28 agent definitions in the code: one baseline professional-kitchen chef who always shows up, plus 27 personalities, from a retired Italian grandmother to a Texas BBQ pitmaster to a Scandinavian forager. Each request picks the baseline plus three personalities at random, so you get four takes on the same ingredients from four different cooks.

They do not talk to each other. Every agent gets the same input and answers independently, and the variety comes entirely from the system prompt. That is cheaper and, in practice, more varied than having them critique each other.

Every idea then gets graded in one batched call: a difficulty label from Beginner to Master Chef, plus an estimated cooking time. It grades the idea (title and description), not the finished recipe, which is the honest limit of it. A model is doing judgment there, not a scoring formula, and calling it an algorithm would flatter it.

Two models, picked per job

Ideation, the full recipe write-up and that grading call all run on gpt-oss-120b served by Cerebras. It is open-weight, it comes back fast enough that the page never feels stuck, and it is the cheapest good option I have found for long structured output.

The in-recipe assistant, the recipe edits and the search refinement run on OpenAI (o4-mini). Same app, different jobs: one model for high-throughput structured generation, another for the conversational instruction-following work where the reasoning actually matters.

A single flag in lib/feature-flags.ts swaps the whole generation path between OpenAI and Cerebras, because in this space the right model changes every few months and changing provider should be a one-line change, not a rewrite.

The assistant on every recipe

Each recipe page carries a chat assistant with the full recipe in its context. Allergic to nuts, ask for a substitute. Cooking for two instead of four, it recalculates the measurements. Want it spicier, it edits instead of rewriting. A recipe on a web page is a dead document, and the version that can answer questions about itself is the only one that stays useful after you open the fridge.

Storage: anonymous first

The whole thing works without an account. Anonymous recipes live in sessionStorage, keyed by the slug in the URL, which means the link works for you and not on your friend's phone.

Sign in and the same content moves to Supabase (Postgres plus auth), where favorites and history live in their own tables with views on top. That migration runs on login, not on signup, so the first recipe you made before deciding to register survives the decision.

Next.js 15, and what that buys

It is a Next.js 15 app on the App Router with React 19, Tailwind, and the shadcn component set. Everything that touches a model is a route handler under app/api, one per job: ideas, full recipe, streaming full recipe, chat, edit, grade, refine search, favorites, save, history. Turbopack is dev-only, so it makes my afternoon faster and does nothing for you; the speed you feel is mostly model latency.

What I actually got out of it

The interesting part was never the model call. It was everything around it: which agent to pick, which model to route to, what to do when someone is not signed in, how to keep a shared URL working, what happens when the cheap model starts writing recipes that read fine and cook badly.

Try it at recipe.sh. It is still the project I use to test ideas before they go anywhere near something that matters.