chef Documentation

The only AI app builder that knows backend

4,561 stars TypeScript TypeScript 1 file ยท ~14,954 tokens
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy chef on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name chef -p 22:22 --restart always chef/chef:latest

File: README.md

Chef is the only AI app builder that knows backend. It builds full-stack web apps with a built-in database, zero config auth, file uploads,
real-time UIs, and background workflows. If you want to check out the secret sauce that powers Chef, you can view or download the system prompt here.

Chef's capabilities are enabled by being built on top of Convex, the open-source reactive database designed to make life easy for web app developers. The "magic" in Chef is just the fact that it's using Convex's APIs, which are an ideal fit for codegen.

Development of the Chef is led by the Convex team. We
welcome bug fixes and
love receiving feedback.

This project is a fork of the stable branch of bolt.diy.

Getting Started

Visit our documentation to learn more about Chef and check out our prompting guide.

The easiest way to build with Chef is through our hosted webapp, which includes a generous free tier. If you want to
run Chef locally, you can follow the guide below.

[!IMPORTANT]
Chef is provided as-is, using an authentication configuration specific to Convex's internal control plane that manages user accounts.

If you are planning on developing a fork of Chef for production use or re-distribution, your fork will need to replace the existing authentication system with your own. We recommend using the OAuth Authorization Code Grant flow to authorize access to Convex teams or projects. Read more about available Platform APIs.

Chef is easy to use for local development without changes. Read on for instructions for using Chef locally.

Running Locally

Note: This will use the hosted Convex control plane to provision Convex projects. However, Chef tokens used in this enviroment will not count towards usage in your Convex account.

1. Clone the project

Clone the GitHub respository and cd into the directory by running the following commands:

bash
git clone https://github.com/get-convex/chef.git
cd chef

2. Set up local environment

Run the following commands in your terminal:

bash
nvm install
nvm use
npm install pnpm
pnpm i
echo 'VITE_CONVEX_URL=placeholder' >> .env.local
npx convex dev --once # follow the steps to create a Convex project in your team

Note: nvm only works on Mac and Linux. If you are using Windows, you may have to find an alternative.

3. Set up Chef OAuth application

Go to the Convex dashboard and create an OAuth application. The team you use to create the application will be the only team you can sign-in with on local Chef. Redirect URIs will not matter, but you can set one to http://127.0.0.1:5173 (or whatever port youโ€™ll run the Chef UI on) so that the form can be submitted.

4. Set up Convex deployment

Use npx convex dashboard to open the Convex dashboard and go to Settings โ†’ Environment Variables. Then, set the following environment variables:

env
BIG_BRAIN_HOST=https://api.convex.dev
CONVEX_OAUTH_CLIENT_ID=<value from oauth setup>
CONVEX_OAUTH_CLIENT_SECRET=<value from oauth setup>
WORKOS_CLIENT_ID=<value from .env.development>

5. Add API keys for model providers

Add any of the following API keys in your .env.local to enable code generation:

env
ANTHROPIC_API_KEY=<your api key>
GOOGLE_API_KEY=<your api key>
OPENAI_API_KEY=<your api key>
XAI_API_KEY=<your api key>

Note: You can also add your own API keys through the Chef settings page.

6. Run Chef backend and frontend

Run the following commands in your terminal:

bash
pnpm run dev

## in another terminal
npx convex dev

Congratulations, you now have Chef running locally! You can log in to Chef with your existing Convex account.

Note: Chef is accessible at http://127.0.0.1:{port}/ and will not work properly on http://localhost:{port}/.

Repository Layout

  • app/ contains all of the client side code and some serverless APIs.

    • components/ defines the UI components
    • lib/ contains client-side logic for syncing local state with the server
    • routes/ defines some client and server routes
  • chef-agent/ handles the agentic loop by injecting system prompts, defining tools, and calling out to model providers.

  • chefshot/ defines a CLI interface for interacting with the Chef webapp.

  • convex/ contains the database that stores chats and user metadata.

  • template/ contains the template that we use to start all Chef projects.

  • test-kitchen/ contains a test harness for the Chef agent loop.


File: chefshot/README.md

Chefshot

Goal is to run evals with this.

Examples

Run all of these from the repo root (not this directory, one level up)

Download filesystem to my-app and print all messages

text
npx convex dev --once; pnpm run build; pnpm run start;
# and then in another terminal
npx chefshot generate "Let's make a chat app" --messages-file foo.json --prod | jq

Just save the messages you get from a prompt in prod

text
npx chefshot "Let's make a chat app!" --messages-file foo.json --prod

Debug

text
npx convex dev --once; pnpm run dev
# and then in another terminal
npx chefshot generate "Let's make a chat app" --dev --no-headless

Credentials

This script only works for username/password dashboard logins.
It reads from these environment variables, you can get them
with npx vercel env pull from the root repo directory (not in
this directory).

text
CHEF_EVAL_USER_PASSWORD
CHEF_EVAL_USER_EMAIL

You can log into the dashboard with these credentials by visiting

https://dashboard.convex.dev/api/auth/login?useEmail=true


File: convex/README.md

Welcome to your Convex functions directory!

Write your Convex functions here.
See https://docs.convex.dev/functions for more.

A query function that takes two arguments looks like:

ts
// functions.js
import { query } from "./_generated/server";
import { v } from "convex/values";

export const myQueryFunction = query({
  // Validators for arguments.
  args: {
    first: v.number(),
    second: v.string(),
  },

  // Function implementation.
  handler: async (ctx, args) => {
    // Read the database as many times as you need here.
    // See https://docs.convex.dev/database/reading-data.
    const documents = await ctx.db.query("tablename").collect();

    // Arguments passed from the client are properties of the args object.
    console.log(args.first, args.second);

    // Write arbitrary JavaScript here: filter, aggregate, build derived data,
    // remove non-public properties, or create new objects.
    return documents;
  },
});

Using this query function in a React component looks like:

ts
const data = useQuery(api.functions.myQueryFunction, {
  first: 10,
  second: "hello",
});

A mutation function looks like:

ts
// functions.js
import { mutation } from "./_generated/server";
import { v } from "convex/values";

export const myMutationFunction = mutation({
  // Validators for arguments.
  args: {
    first: v.string(),
    second: v.string(),
  },

  // Function implementation.
  handler: async (ctx, args) => {
    // Insert or modify documents in the database here.
    // Mutations can also read from the database like queries.
    // See https://docs.convex.dev/database/writing-data.
    const message = { body: args.first, author: args.second };
    const id = await ctx.db.insert("messages", message);

    // Optionally, return a value from your mutation.
    return await ctx.db.get(id);
  },
});

Using this mutation function in a React component looks like:

ts
const mutation = useMutation(api.functions.myMutationFunction);
function handleButtonPress() {
  // fire and forget, the most common way to use mutations
  mutation({ first: "Hello!", second: "me" });
  // OR
  // use the result once the mutation has completed
  mutation({ first: "Hello!", second: "me" }).then((result) => console.log(result));
}

Use the Convex CLI to push your functions to a deployment. See everything
the Convex CLI can do by running npx convex -h in your project root
directory. To learn more, launch the docs with npx convex docs.


File: iframe-worker/README.md

The vite server of the template/snapshot vite app (the initial state of every Chef app)
injects code during development only so a Chef app in an iframe can listen to postMessage
messages from its parent Chef window.

The injected code just checks the message is from its parent, then loads this script
to response to the message.

This way we control the script if we ever needed to updated dependencies etc.

Updating this script requires a deploy because the script is served from
https://chef.convex.dev/scripts/worker.bundled.mjs. The WebContainer can't make requests of localhost,
so use a proxy if you're updating it live in development. You'll need to add that to vite.config.ts
server.allowedHosts to use it.


File: proxy/README.md

The vite dev server serving the user's Chef-generated app responds to both
HTTP and HMR WebSocket traffic.

We proxy this traffic for previews so that different domains can be used
to simulate different users, since different domains -> different cookies.

I couldn't get WebContainers to accept connections on different ports for
HTTP and WebSockets (although Vite is easy to configure to do this) so
we also need to proxy WebSocket traffic.

The Node.js in WebContainers does not support reading from stdin.
WebContainer.writeFile() seems incapable of writing to /tmp/foo
so it's ideal to use node -e 'the(proxy); code()' or
echo 'the(proxy); code() > /tmp/proxy.cjs'.

Writing a very short proxy that works with WebSockets should be easy
(TODO) but I couldn't get it to work. So we bundle up a simple proxy server
built with node-http-proxy aka http-proxy.


File: template/convex/README.md

Welcome to your Convex functions directory!

Write your Convex functions here.
See https://docs.convex.dev/functions for more.

A query function that takes two arguments looks like:

ts
// convex/myFunctions.ts
import { query } from "./_generated/server";
import { v } from "convex/values";

export const myQueryFunction = query({
  // Validators for arguments.
  args: {
    first: v.number(),
    second: v.string(),
  },

  // Function implementation.
  handler: async (ctx, args) => {
    // Read the database as many times as you need here.
    // See https://docs.convex.dev/database/reading-data.
    const documents = await ctx.db.query("tablename").collect();

    // Arguments passed from the client are properties of the args object.
    console.log(args.first, args.second);

    // Write arbitrary JavaScript here: filter, aggregate, build derived data,
    // remove non-public properties, or create new objects.
    return documents;
  },
});

Using this query function in a React component looks like:

ts
const data = useQuery(api.myFunctions.myQueryFunction, {
  first: 10,
  second: "hello",
});

A mutation function looks like:

ts
// convex/myFunctions.ts
import { mutation } from "./_generated/server";
import { v } from "convex/values";

export const myMutationFunction = mutation({
  // Validators for arguments.
  args: {
    first: v.string(),
    second: v.string(),
  },

  // Function implementation.
  handler: async (ctx, args) => {
    // Insert or modify documents in the database here.
    // Mutations can also read from the database like queries.
    // See https://docs.convex.dev/database/writing-data.
    const message = { body: args.first, author: args.second };
    const id = await ctx.db.insert("messages", message);

    // Optionally, return a value from your mutation.
    return await ctx.db.get("messages", id);
  },
});

Using this mutation function in a React component looks like:

ts
const mutation = useMutation(api.myFunctions.myMutationFunction);
function handleButtonPress() {
  // fire and forget, the most common way to use mutations
  mutation({ first: "Hello!", second: "me" });
  // OR
  // use the result once the mutation has completed
  mutation({ first: "Hello!", second: "me" }).then((result) =>
    console.log(result),
  );
}

Use the Convex CLI to push your functions to a deployment. See everything
the Convex CLI can do by running npx convex -h in your project root
directory. To learn more, launch the docs with npx convex docs.


File: test-kitchen/README.md

Test Kitchen

Instructions

bash
pnpm i

BRAINTRUST_API_KEY=<..> ANTHROPIC_API_KEY=<..> npx braintrust eval initialGeneration.eval.ts

You can also run it as a oneoff (without Braintrust) via main.ts:

bash
ANTHROPIC_API_KEY=<..> bun run main.ts