Can AI build me a free meal planner app?

Yes. It can build a simple weekly planner where you drag in meals and get a combined grocery list, saved in your browser, instead of paying for a meal-planning app.

Verdict: Bot · AI does it well✓ Tested 2 times in Llama 3.3 70B · Oct 24, 2026Written for ChatGPT, Claude or Gemini

Jump to the prompt ↓

Bot

01Why bot

  • A weekly grid plus a list generator is a small app.
  • Browser storage keeps it free and private.
  • Recipe imports and nutrition data are extra work.
Sponsor slot · openFeatured tool for this task. A labeled card for one relevant tool.
Book this spot →

02The prompt

Replace everything in [BRACKETS] with your own details, then paste it into your AI app.

prompt.txt
You are a web developer. Build a weekly meal planner.

Features: a Monday to Sunday grid, a saved list of my meals with ingredients, and an auto-combined grocery list grouped by store section.

Requirements:
- MUST be a single index.html file, mobile-first, saving data in the browser.
- MUST combine duplicate ingredients on the grocery list.
- Don't add features I didn't list.

Then give me steps to publish it free and how to back up my data.

03Steps

  1. Run the prompt in an AI coding tool.
  2. Add 10 meals you make often.
  3. Plan a week and test the grocery list.

04What can go wrong

  • Export your data now and then.
  • Quantities may need manual tweaks.

05What to use

Claude, ChatGPT, Lovable or Replit.

06Our test runs

2 runs, each with a different made-up sample. 0 of 2 passed every check.

Run 1 · Llama 3.3 70B · graded by GPT-OSS 120BOct 3, 2026Passed with a catch

The made-up sample:

This prompt has nothing to fill in.

  • Provide a single index.html file
  • Save data in the browser
  • Combine duplicate ingredients on grocery list
  • Include steps to back up data
  • Didn't make up details we never gave it

What came back (excerpt):

DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.
Read the full answer
```html
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Weekly Meal Planner</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        table {
            border-collapse: collapse;
            width: 100%;
        }
        th, td {
            border: 1px solid #ddd;
            padding: 10px;
            text-align: left;
        }
        th {
            background-color: #f0f0f0;
        }
        #grocery-list {
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <h1>Weekly Meal Planner</h1>
    <table id="meal-planner">
        <tr>
            <th>Monday</th>
            <th>Tuesday</th>
            <th>Wednesday</th>
            <th>Thursday</th>
            <th>Friday</th>
            <th>Saturday</th>
            <th>Sunday</th>
        </tr>
        <tr>
            <td><input type="text" id="monday-meal" placeholder="Enter meal"></td>
            <td><input type="text" id="tuesday-meal" placeholder="Enter meal"></td>
            <td><input type="text" id="wednesday-meal" placeholder="Enter meal"></td>
            <td><input type="text" id="thursday-meal" placeholder="Enter meal"></td>
            <td><input type="text" id="friday-meal" placeholder="Enter meal"></td>
            <td><input type="text" id="saturday-meal" placeholder="Enter meal"></td>
            <td><input type="text" id="sunday-meal" placeholder="Enter meal"></td>
        </tr>
        <tr>
            <td><textarea id="monday-ingredients" placeholder="Enter ingredients"></textarea></td>
            <td><textarea id="tuesday-ingredients" placeholder="Enter ingredients"></textarea></td>
            <td><textarea id="wednesday-ingredients" placeholder="Enter ingredients"></textarea></td>
            <td><textarea id="thursday-ingredients" placeholder="Enter ingredients"></textarea></td>
            <td><textarea id="friday-ingredients" placeholder="Enter ingredients"></textarea></td>
            <td><textarea id="saturday-ingredients" placeholder="Enter ingredients"></textarea></td>
            <td><textarea id="sunday-ingredients" placeholder="Enter ingredients"></textarea></td>
        </tr>
    </table>
    <button id="save-meals">Save Meals</button>
    <button id="generate-grocery-list">Generate Grocery List</button>
    <div id="grocery-list"></div>

    <script>
        const meals = {};
        const groceryList = {};

        document.getElementById('save-meals').addEventListener('click', () => {
            meals.monday = {
                meal: document.getElementById('monday-meal').value,
                ingredients: document.getElementById('monday-ingredients').value.split(',')
            };
            meals.tuesday = {
                meal: document.getElementById('tuesday-meal').value,
                ingredients: document.getElementById('tuesday-ingredients').value.split(',')
            };
            meals.wednesday = {
                meal: document.getElementById('wednesday-meal').value,
                ingredients: document.getElementById('wednesday-ingredients').value.split(',')
            };
            meals.thursday = {
                meal: document.getElementById('thursday-meal').value,
                ingredients: document.getElementById('thursday-ingredients').value.split(',')
            };
            meals.friday = {
                meal: document.getElementById('friday-meal').value,
                ingredients: document.getElementById('friday-ingredients').value.split(',')
            };
            meals.saturday = {
                meal: document.getElementById('saturday-meal').value,
                ingredients: document.getElementById('saturday-ingredients').value.split(',')
            };
            meals.sunday = {
                meal: document.getElementById('sunday-meal').value,
                ingredients: document.getElementById('sunday-ingredients').value.split(',')
            };

            localStorage.setItem('meals', JSON.stringify(meals));
        });

        document.getElementById('generate-grocery-list').addEventListener('click', () => {
            const storedMeals = JSON.parse(localStorage.getItem('meals'));
            if (storedMeals) {
                Object.keys(storedMeals).forEach(day => {
                    storedMeals[day].ingredients.forEach(ingredient => {
                        const trimmedIngredient = ingredient.trim();
                        if (trimmedIngredient) {
                            if (groceryList[trimmedIngredient]) {
                                groceryList[trimmedIngredient].count++;
                            } else {
                                groceryList[trimmedIngredient] = {
                                    count: 1,
                                    section: getSection(trimmedIngredient)
                                };
                            }
                        }
                    });
                });

                const groceryListHtml = Object.keys(groceryList).map(ingredient => {
                    return `<p>${ingredient} (${groceryList[ingredient].section}) - ${groceryList[ingredient].count}</p>`;
                }).join('');

                document.getElementById('grocery-list').innerHTML = groceryListHtml;
            }
        });

        function getSection(ingredient) {
            const sections = {
                'produce': ['apple', 'banana', 'carrot'],
                'meat': ['chicken', 'beef', 'pork'],
                'dairy': ['milk', 'eggs', 'cheese'],
                'pantry': ['rice', 'pasta', 'canned goods']
            };

            for (const section in sections) {
                if (sections[section].includes(ingredient.toLowerCase())) {
                    return section;
                }
            }

            return 'unknown';
        }
    </script>
</body>
</html>
```

### Steps to Publish for Free:

1. **Create a GitHub account**: If you don't already have one, sign up for a free GitHub account.
2. **Create a new repository**: Click the "+" button in the top right corner of your GitHub dashboard and select "New repository".
3. **Upload your index.html file**: Drag and drop your `index.html` file into the repository, or use the "Upload files" button.
4. **Create a GitHub Pages site**: Go to your repository's settings, scroll down to the "GitHub Pages" section, and select "Master Branch" as the source.
5. **Wait for GitHub Pages to deploy**: This may take a few minutes. Once deployed, you'll see a message indicating

The answer omits backup instructions and is incomplete.

Run 2 · Llama 3.3 70B · graded by GPT-OSS 120BOct 24, 2026Passed with a catch

The made-up sample (a messier one):

This prompt has nothing to fill in.

  • Must be a single index.html file
  • Must be mobile‑first
  • Must combine duplicate ingredients on grocery list
  • Must give steps to publish it free and back up data
  • Didn't make up details we never gave it

What came back (excerpt):

DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.
Read the full answer
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Weekly Meal Planner</title>
    <style>
        body {
            font-family: Arial, sans-serif;
        }
        table {
            border-collapse: collapse;
        }
        th, td {
            border: 1px solid #ddd;
            padding: 10px;
        }
        .day {
            width: 14%;
        }
        .meal {
            width: 70%;
        }
        .ingredients {
            width: 16%;
        }
        #grocery-list {
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <h1>Weekly Meal Planner</h1>
    <table id="meal-planner">
        <tr>
            <th class="day">Monday</th>
            <td class="meal"><input type="text" id="monday-meal"></td>
            <td class="ingredients"><input type="text" id="monday-ingredients"></td>
        </tr>
        <tr>
            <th class="day">Tuesday</th>
            <td class="meal"><input type="text" id="tuesday-meal"></td>
            <td class="ingredients"><input type="text" id="tuesday-ingredients"></td>
        </tr>
        <tr>
            <th class="day">Wednesday</th>
            <td class="meal"><input type="text" id="wednesday-meal"></td>
            <td class="ingredients"><input type="text" id="wednesday-ingredients"></td>
        </tr>
        <tr>
            <th class="day">Thursday</th>
            <td class="meal"><input type="text" id="thursday-meal"></td>
            <td class="ingredients"><input type="text" id="thursday-ingredients"></td>
        </tr>
        <tr>
            <th class="day">Friday</th>
            <td class="meal"><input type="text" id="friday-meal"></td>
            <td class="ingredients"><input type="text" id="friday-ingredients"></td>
        </tr>
        <tr>
            <th class="day">Saturday</th>
            <td class="meal"><input type="text" id="saturday-meal"></td>
            <td class="ingredients"><input type="text" id="saturday-ingredients"></td>
        </tr>
        <tr>
            <th class="day">Sunday</th>
            <td class="meal"><input type="text" id="sunday-meal"></td>
            <td class="ingredients"><input type="text" id="sunday-ingredients"></td>
        </tr>
    </table>
    <button id="save-meals">Save Meals</button>
    <button id="generate-grocery-list">Generate Grocery List</button>
    <div id="grocery-list"></div>

    <script>
        const mealPlanner = document.getElementById('meal-planner');
        const saveMealsButton = document.getElementById('save-meals');
        const generateGroceryListButton = document.getElementById('generate-grocery-list');
        const groceryListDiv = document.getElementById('grocery-list');

        let meals = {};
        let groceryList = {};

        saveMealsButton.addEventListener('click', () => {
            const mondayMeal = document.getElementById('monday-meal').value;
            const mondayIngredients = document.getElementById('monday-ingredients').value;
            const tuesdayMeal = document.getElementById('tuesday-meal').value;
            const tuesdayIngredients = document.getElementById('tuesday-ingredients').value;
            const wednesdayMeal = document.getElementById('wednesday-meal').value;
            const wednesdayIngredients = document.getElementById('wednesday-ingredients').value;
            const thursdayMeal = document.getElementById('thursday-meal').value;
            const thursdayIngredients = document.getElementById('thursday-ingredients').value;
            const fridayMeal = document.getElementById('friday-meal').value;
            const fridayIngredients = document.getElementById('friday-ingredients').value;
            const saturdayMeal = document.getElementById('saturday-meal').value;
            const saturdayIngredients = document.getElementById('saturday-ingredients').value;
            const sundayMeal = document.getElementById('sunday-meal').value;
            const sundayIngredients = document.getElementById('sunday-ingredients').value;

            meals = {
                monday: { meal: mondayMeal, ingredients: mondayIngredients },
                tuesday: { meal: tuesdayMeal, ingredients: tuesdayIngredients },
                wednesday: { meal: wednesdayMeal, ingredients: wednesdayIngredients },
                thursday: { meal: thursdayMeal, ingredients: thursdayIngredients },
                friday: { meal: fridayMeal, ingredients: fridayIngredients },
                saturday: { meal: saturdayMeal, ingredients: saturdayIngredients },
                sunday: { meal: sundayMeal, ingredients: sundayIngredients }
            };

            localStorage.setItem('meals', JSON.stringify(meals));
        });

        generateGroceryListButton.addEventListener('click', () => {
            const storedMeals = localStorage.getItem('meals');
            if (storedMeals) {
                meals = JSON.parse(storedMeals);
            }

            groceryList = {};

            for (const day in meals) {
                const ingredients = meals[day].ingredients.split(',');
                for (const ingredient of ingredients) {
                    const trimmedIngredient = ingredient.trim();
                    if (trimmedIngredient) {
                        if (groceryList[trimmedIngredient]) {
                            groceryList[trimmedIngredient]++;
                        } else {
                            groceryList[trimmedIngredient] = 1;
                        }
                    }
                }
            }

            const groupedGroceryList = {};
            for (const ingredient in groceryList) {
                const section = getStoreSection(ingredient);
                if (groupedGroceryList[section]) {
                    groupedGroceryList[section].push({ ingredient, quantity: groceryList[ingredient] });
                } else {
                    groupedGroceryList[section] = [{ ingredient, quantity: groceryList[ingredient] }];
                }
            }

            const groceryListHtml = [];
            for (const section in groupedGroceryList) {
                groceryListHtml.push(`<h2>${section}</h2>`);
                groceryListHtml.push('<ul>');
                for (const item of groupedGroceryList[section]) {
                    groceryListHtml.push(`<li>${item.ingredient} (x${item.quantity})</li>`);
                }
                groceryListHtml.push('</ul>');

The answer is incomplete and missing publishing and backup steps.

How each run works: we fill the prompt with a made-up sample, run it once in Llama 3.3 70B, and GPT-OSS 120B grades the answer against the prompt's own rules. Word limits are counted by code, and every quote flagged as made up is checked against the full answer. Your results can differ. How we test.

Prompt packReplace Paid Apps 10 step-by-step prompts that go further than this one, $19.
See what’s inside →