Build an AI Lesson Plan Generator
Vibe code a live AI web app that generates lesson plans with Gemini.
Introduction
30 Second Summary
Teachers spend hours building lesson plans from scratch for every new topic, grade level, and class length. What if they could describe what they need and get a complete, structured plan in seconds?
In this project, you will build and deploy a live web app that generates AI-powered lesson plans for educators. You will use OpenAI Codex as your cloud coding agent, Claude as your design advisor, and Google Gemini as the AI that writes the plans.
What You'll Build
Picture a teacher typing "Photosynthesis" into your app for Grade 7 Science, clicking Generate, and receiving a complete 50-minute lesson plan with learning objectives, timed activities, and assessment strategies.
By the end of this project, you'll have:
- A live web app URL where any educator can enter their topic, grade level, subject, and class duration, then receive a fully structured lesson plan generated by AI.
- A vibe coding workflow where Claude designs the UI, Codex writes the code, and Streamlit Community Cloud hosts the finished app.
- A polished, professional interface with formatted markdown sections, a sidebar input form, and a download button so teachers can save their plans.
- Secret Mission: Add a pedagogical framework selector that lets teachers choose between 5E Model, Backward Design, and Direct Instruction lesson plan formats.
Are there any prerequisites?
You need an OpenAI account with Codex access (the $100 sign-up credit works perfectly), a GitHub account, and a Google account for your Gemini API key. No local Python installation is needed for this project.
Before We Start
Before you dive into prompting and building, take a moment to lock in exactly what you're creating and who it's for. Having a clear target gives you sharper prompts when you start directing Codex to write your code.
Set Up Your Tools and Environment
Your lesson plan generator needs three things before any code gets written: an AI brain (the Gemini API), a place to store code (a GitHub repository), and an agent to write that code for you (Codex).
In this step, you will create a Gemini API key, set up a GitHub repo, and configure Codex to work with both.
In this step, get ready to:
- Get your Gemini API key from Google AI Studio.
- Create a GitHub repository for your project.
- Connect Codex to your repository and add your API key as a secret.
Get your Gemini API key from Google AI Studio
The Gemini API powers the AI behind your lesson plan generator. To call it, you need an API key from Google AI Studio.
- Go to ai.google.dev and sign in with your Google account.
- Click Get API key to open the API keys page.
- Click Create API key.
- In the dialog that appears, select the default project and confirm.
- Copy the generated API key and paste it somewhere safe (a temporary notes file works).
Why no billing account?
Google AI Studio starts you on the free tier automatically. You do not need to attach a billing account. The free tier provides free input and output tokens, which is more than enough for this project.
Can't create a key?
If you see a permission error, make sure you are signed in with a personal Google account (not a managed work/school account). Managed accounts sometimes lack the IAM permissions needed to create keys in AI Studio.
help me troubleshoot creating a Gemini API key in Google AI Studio
Create a new GitHub repository
Codex works by cloning a GitHub repository, making code changes, and showing you a diff to review. You need an empty repo for it to work in.
- Go to github.com/new (sign in if prompted).
- Enter lesson-plan-generator as the repository name.
- Set the visibility to Public.
- Check the box for Add a README file.
- Click Create repository.
You should now see your new repository page with a single README.md file listed.
Don't see the repository page?
Make sure the repository name does not contain spaces or special characters. GitHub only allows letters, numbers, hyphens, and underscores in repo names.
help me create a GitHub repository called lesson-plan-generator
Connect Codex to your repository
Now you will connect Codex to your new repository and give it your Gemini API key as a secret. This lets Codex clone your repo, write code, and access the key during setup.
- Open ChatGPT and sign in with your OpenAI account.
- In the left sidebar, click Codex to open the Codex panel.
- Connect your lesson-plan-generator repository. If prompted, authorize the Codex GitHub app and select the lesson-plan-generator repo.
- Open the environment settings for your connected repository.
- In the Secrets section, add a new entry with the name GEMINI_API_KEY and paste your Gemini API key as the value.
- Save the environment settings.
Why use Secrets instead of Environment Variables?
Codex has two categories for stored values: Environment Variables and Secrets. Secrets are stored with an additional layer of encryption and are only decrypted for task execution. Since your Gemini API key is a credential, the Secrets section keeps it more secure.
Confirm that Codex shows your lesson-plan-generator repository as connected and can accept prompts.
Codex not showing your repo?
Make sure you authorized the Codex GitHub app for the correct GitHub account. If you have multiple GitHub accounts, check that you granted access to the one that owns lesson-plan-generator.
help me connect my GitHub repository to OpenAI Codex
Your environment is ready. You have a Gemini API key for AI generation, a GitHub repo for your code, and Codex connected and waiting for instructions. Next up, you will prompt Codex to build your first working app.
Build the Basic App with Codex
Your environment is set up and Codex is connected to your repository, ready to accept tasks.
Right now, your repo is empty except for a README. In this step, you'll give Codex a detailed description of your app's form and watch it produce working code from plain English alone. This is your first proof that vibe coding works.
In this step, get ready to:
- Submit a prompt to Codex describing your app's form inputs.
- Review the generated code diff and merge it to main.
- Confirm both files appear in your GitHub repository.
Submit your first Codex task
Codex works by receiving a natural-language task description, then writing code inside a cloud container that has your repo checked out. The more specific your prompt, the closer the output matches what you want.
- Switch back to the Codex panel in your ChatGPT sidebar.
- Click the task input field and paste the following prompt:
Create a Streamlit app in streamlit_app.py with a form that collects: Topic (text input), Grade Level (dropdown: K-2, 3-5, 6-8, 9-12, Post-Secondary), Subject Area (text input), Class Duration in minutes (number input, default 50), and Additional Notes (text area, optional). Add a Generate Lesson Plan submit button. When submitted, display a placeholder message saying 'Lesson plan will appear here.' Also create a requirements.txt with streamlit listed.
- Submit the task.
What happens after you submit?
Codex creates a cloud container, checks out your repo, and starts writing code. This typically takes 1-3 minutes. You'll see a progress indicator while it works.
You do not need to stay on the page. Codex will notify you when the task is complete.
Review the diff and merge to main
Once Codex finishes, it shows you a diff of all the changes it made. This is your chance to verify the code before it hits your main branch.
- Click on the completed task to view its diff.
- Check that streamlit_app.py contains all five form fields: Topic, Grade Level, Subject Area, Class Duration, and Additional Notes.
- Check that a Generate Lesson Plan submit button is present.
- Check that requirements.txt lists streamlit as a dependency.
- Accept the changes and merge to main.
Why review before merging?
Codex is powerful but not perfect. Reviewing the diff is your quality check. You're confirming that the AI understood your intent and produced the right structure before it goes into your repository.
✔️ The diff looks right!
Great. Move on to the next substep to confirm the files landed in your GitHub repo.
ⓧ I'd like to double check the expected code
Here is what the two files should look like after merging. Your code may vary slightly in formatting, but the structure and fields should match.
import streamlit as st
with st.form('lesson_form'):
topic = st.text_input('Topic', placeholder='e.g., Photosynthesis')
grade_level = st.selectbox('Grade Level', ['K-2', '3-5', '6-8', '9-12', 'Post-Secondary'])
subject_area = st.text_input('Subject Area', placeholder='e.g., Science')
duration = st.number_input('Class Duration (minutes)', min_value=15, max_value=180, value=50, step=5)
additional_notes = st.text_area('Additional Notes (optional)')
submitted = st.form_submit_button('Generate Lesson Plan')
if submitted:
st.write('Lesson plan will appear here.')
streamlit
If your Codex output is significantly different (missing fields, wrong structure), submit a follow-up task asking it to correct the issue.
Confirm the files on GitHub
The merge pushed your new files to the remote repository. Time to verify they arrived.
- Before you check, predict: what two new files should you see alongside the README?
- Open your lesson-plan-generator repository on github.com.
- Confirm that streamlit_app.py and requirements.txt are now listed on the main branch.
You should see both files in the file list alongside your original README.md. That confirms Codex successfully wrote and merged working code from your plain-English description.
Don't see the files on GitHub?
- Make sure you accepted and merged the changes in Codex. If the task shows as completed but not merged, go back and merge it.
- Check that you're viewing the main branch in your GitHub repo, not a different branch.
- If the task failed, check the error log in Codex and submit the same prompt again.
Still stuck? Help me figure out why my Codex task didn't merge to my GitHub repo.
You just proved that Codex can turn a natural-language description into a working app skeleton. Next up, you'll connect the Gemini API so the form actually generates real lesson plans instead of a placeholder message.
Connect Gemini to Generate Real Lesson Plans
Your form is live in the repository, collecting all five inputs from educators. But right now, clicking Generate Lesson Plan does nothing more than display a placeholder message.
In this step, you will prompt Codex to connect the Google Gemini API to your form. When an educator submits their inputs, the app will send them to Gemini and display a real, AI-generated lesson plan.
In this step, get ready to:
- Submit a Codex task that integrates the Gemini API into your Streamlit app.
- Review the diff to confirm the API call and output display are correct.
- Merge the changes to your main branch.
Prompt Codex to add Gemini integration
Right now, your app's submit handler just prints a placeholder string. You need Codex to replace that placeholder with a real API call to Gemini that sends the educator's inputs and returns a structured lesson plan.
- In Codex, click to start a new task connected to your lesson-plan-generator repository.
- Paste the following prompt into the task input:
Update streamlit_app.py to integrate with Google Gemini. Install google-genai in requirements.txt. When the form is submitted, use the google-genai SDK to call gemini-3.5-flash with a prompt that asks it to generate a detailed lesson plan based on the user's inputs (topic, grade level, subject, duration, notes). The prompt should request these sections: Learning Objectives, Materials Needed, Lesson Outline with timing for each activity, Assessment Strategy, and Differentiation suggestions. Display the raw response text below the form using st.write(). Use genai.Client() which reads the GEMINI_API_KEY environment variable automatically.
What does this prompt ask Codex to do?
- Install the google-genai package by adding it to requirements.txt.
- Import the SDK and create a client with genai.Client(), which automatically reads the GEMINI_API_KEY environment variable.
- Build a prompt from the form inputs and call client.interactions.create with the gemini-3.5-flash model.
- Display the raw AI response using st.write() so the lesson plan appears below the form.
- Submit the task and wait for Codex to complete it.
How long does a Codex task take?
Codex creates a container, checks out your repo, installs dependencies, then edits code and runs checks. Most tasks finish within 1-3 minutes. When the agent finishes, it shows a diff of all file changes.
Review and merge the changes
Before you accept anything Codex produces, you should verify that the diff contains the right pieces. This is your quality check.
Before you look at the diff, what do you expect Codex changed in streamlit_app.py and requirements.txt?
- Open the diff that Codex produced.
- In requirements.txt, confirm that google-genai is now listed as a dependency.
- In streamlit_app.py, confirm that from google import genai appears at the top.
- Verify that the API call uses client.interactions.create with model gemini-3.5-flash.
- Verify that the response is displayed using st.write(interaction.output_text).
Codex might add extras
Codex sometimes adds error handling, input validation, or slightly different variable names. That is fine as long as the core pieces are present: the import, the client, the prompt, the API call, and the output display.
- Once you have confirmed the diff looks correct, accept the changes and merge to main.
Your app now generates real lesson plans from Gemini. However, notice that st.write() dumps the AI response as a wall of plain text with no visual structure. For a teacher scanning the plan between classes, that is hard to read.
- Go to your lesson-plan-generator repository on GitHub and confirm that streamlit_app.py and requirements.txt both show the updated code on the main branch.
Codex task failed or diff looks wrong?
- If Codex timed out or errored, try submitting the same prompt again. Transient container issues sometimes resolve on retry.
- If the diff is missing the API call, check that your prompt mentions google-genai and genai.Client() explicitly. Re-submit with the exact prompt above.
- If the model name is different (not gemini-3.5-flash), ask Codex a follow-up to change it.
Still stuck? Help me troubleshoot my Codex task for Gemini integration.
✔️ Awesome, I've got everything!
Great. Double check you have both files updated on GitHub before moving on.
ⓧ I'd like to double check the full code
After merging, your files on GitHub should look like this.
requirements.txt:
streamlit==1.58.0
google-genai
streamlit_app.py:
import streamlit as st
from google import genai
with st.form('lesson_form'):
topic = st.text_input('Topic', placeholder='e.g., Photosynthesis')
grade_level = st.selectbox('Grade Level', ['K-2', '3-5', '6-8', '9-12', 'Post-Secondary'])
subject_area = st.text_input('Subject Area', placeholder='e.g., Science')
duration = st.number_input('Class Duration (minutes)', min_value=15, max_value=180, value=50, step=5)
additional_notes = st.text_area('Additional Notes (optional)')
submitted = st.form_submit_button('Generate Lesson Plan')
if submitted:
if not topic:
st.warning('Please enter a topic.')
else:
with st.spinner('Generating your lesson plan...'):
client = genai.Client()
prompt = f'Create a detailed lesson plan for Topic: {topic}, Grade Level: {grade_level}, Subject: {subject_area}, Duration: {duration} minutes, Notes: {additional_notes}. Include sections: ## Learning Objectives, ## Materials Needed, ## Lesson Outline, ## Assessment Strategy, ## Differentiation.'
interaction = client.interactions.create(model='gemini-3.5-flash', input=prompt)
st.write(interaction.output_text)
Codex might produce slightly different code
As long as your version imports genai, calls client.interactions.create with model gemini-3.5-flash, and displays the result with st.write(), the core logic is correct. Small differences in variable names or prompt wording are fine.
Your app can now generate real AI-powered lesson plans. Next up, you will fix that raw text wall by designing a polished, professional UI with Claude and implementing it through Codex.
Design a Polished UI with Claude and Codex
Your app generates real lesson plans, but the output lands as a wall of plain text with no headings, no sections, and no way to save it. Teachers need a layout they can scan in seconds and print for their records.
You will use Claude as a design advisor to craft a professional UI specification, then hand that spec to Codex to implement. This two-agent workflow lets you get polished results without writing code yourself.
In this step, get ready to:
- Get UI design specifications from Claude including colors, layout, and formatting decisions.
- Submit a redesign task to Codex with Claude's design specs.
- Review the diff and merge the polished UI to your main branch.
Ask Claude for UI design specifications
Claude excels at crafting detailed design specs that a coding agent can follow precisely. You will ask Claude to decide the color scheme, page layout, form placement, and output formatting for your lesson plan app.
- Open Claude in your browser at claude.ai.
- Start a new conversation and paste this prompt:
Design a clean, professional UI layout for a Streamlit lesson plan generator app for teachers. Include: a color scheme, page title styling, how the input form should be arranged (sidebar vs main?), how the generated lesson plan should be formatted (cards, sections, headers?), and a download button placement. Give me specific CSS colors and layout decisions I can give to a coding agent.
What does this prompt ask for?
You are asking Claude to make concrete decisions about your app's look and feel. The key phrase "specific CSS colors and layout decisions I can give to a coding agent" tells Claude to output actionable specs, not vague suggestions.
Claude will respond with a color palette, font sizing, whether the form should live in a sidebar, how the lesson plan sections should be styled, and where the download button goes.
- Wait for Claude to respond with its full design specification.
- Read through the response to confirm it includes colors, layout choices, and formatting decisions.
- Select all of Claude's design response and copy it to your clipboard.
Your design may differ slightly
Claude might suggest different specific hex colors or layout details than what ends up in the final app. That is fine. Codex will interpret the design intent and produce working code. The important part is giving Codex a clear direction.
Submit the redesign task to Codex
Now you will feed Claude's design spec directly to Codex as part of a task prompt. Codex will rewrite your app to match the design.
- Switch back to ChatGPT and open Codex from the sidebar.
- Submit a new task with the following prompt, pasting Claude's design response where indicated:
Redesign the app UI based on these specifications:
[[CLAUDE_DESIGN="paste Claude's full design response here"]]
Add st.set_page_config with a title and page icon. Add custom CSS via st.markdown for styling. Format the Gemini output as proper markdown with headers for each section. Move the input form to a st.sidebar. Add a st.download_button that lets users download the generated plan as a .txt file. Store the generated plan in st.session_state so it persists when the user changes inputs. Also create a .streamlit/config.toml file with a matching Streamlit theme (primary color, background, text colors).
What will Codex do with this?
Codex will clone your repository, read the existing streamlit_app.py, and rewrite it to include page configuration, custom CSS classes, a sidebar form, markdown-formatted output, a download button, and session state.
It will also create a .streamlit/config.toml file that sets the Streamlit theme colors to match the design. When Codex finishes, it shows you a diff of every file it changed.
- Wait for Codex to finish processing the task. This typically takes 1-3 minutes.
Review the diff and merge
Before you think about what changed, take a moment to predict. Based on the prompt you gave, what files do you expect Codex to have modified or created?
- Review the diff that Codex presents. Confirm you see changes to streamlit_app.py and a new .streamlit/config.toml file.
- Check that streamlit_app.py now includes st.set_page_config near the top of the file.
- Look for a st.markdown block containing <style> with CSS class definitions.
- Confirm the form inputs are now wrapped in with st.sidebar: instead of st.form.
- Verify a st.download_button appears in the code for saving lesson plans.
- Check for st.session_state usage that stores the generated plan.
Why session state?
Without st.session_state, Streamlit re-runs the entire script on every interaction. That means the generated lesson plan would disappear if a teacher tweaks an input.
Session state persists the plan across reruns so teachers can adjust settings and compare results without regenerating each time.
- Click Accept to approve the changes, then merge them to your main branch.
- Go to your lesson-plan-generator repository on GitHub to confirm the updated files are visible.
You should see streamlit_app.py, requirements.txt, and a .streamlit folder containing config.toml on the main branch.
✔️ I see all three files on main
Your polished UI is merged and ready for deployment.
ⓧ Codex task failed or diff is missing elements
If Codex did not produce the expected changes, try these fixes.
- Check that your Codex prompt included all the specific instructions (page config, CSS, sidebar, download button, session state, config.toml).
- Submit the task again with a simpler prompt that focuses on one change at a time (e.g., just the sidebar move first).
- Make sure Codex is still connected to the correct lesson-plan-generator repository in the environment settings.
Codex produced different code than expected?
Codex is an AI agent. It may name CSS classes differently or structure the code slightly differently from what you expect. The important thing is that all six features are present: page config, custom CSS, sidebar form, markdown output, download button, and session state.
If a feature is missing, submit a follow-up task asking Codex to add just that one feature. Help me troubleshoot my Codex task results
Your app now has a professional design with proper formatting, a sidebar form, and a download button. Next up, you will deploy it to Streamlit Community Cloud so anyone with a URL can generate lesson plans.
Deploy to Streamlit Community Cloud
Your lesson plan generator is fully built and polished, but it only lives in a GitHub repository right now. Anyone who wants to use it would need to clone the repo and run it locally.
In this step, you will deploy the app to Streamlit Community Cloud, a free hosting platform that gives you a live public URL. Any educator can visit this URL in a browser and start generating lesson plans immediately.
In this step, get ready to:
- Deploy your app to Streamlit Community Cloud with your API key configured as a secret.
- Test the live app by generating a lesson plan from the public URL.
- Copy and bookmark your app's live URL to share with others.
Sign in to Streamlit Community Cloud and create your app
Streamlit Community Cloud connects directly to your GitHub repository and builds the app for you in the cloud. You do not need Python installed locally.
- Open your browser and go to share.streamlit.io.
- Sign in with your GitHub account.
- In the upper-right corner, click Create app.
- When asked "Do you already have an app?" click Yup, I have an app.
- In the Repository field, select your lesson-plan-generator repo.
- Set the Branch to main.
- Set the Main file path to streamlit_app.py.
What is Streamlit Community Cloud?
Streamlit Community Cloud is a free hosting platform for public Streamlit apps. It connects to your GitHub repo, installs your dependencies from requirements.txt, and runs your app on a public URL.
Any time you push changes to your repo, the app automatically redeploys. Your .streamlit/config.toml theme settings are picked up automatically too.
Add your Gemini API key as a secret
Your app needs the GEMINI_API_KEY environment variable to call the Gemini API. Streamlit Community Cloud provides a secure way to store secrets without committing them to your repo.
- Before clicking Deploy, click Advanced settings.
- In the Secrets field, paste the following (replacing the placeholder with your actual key):
GEMINI_API_KEY = "your-api-key-here"
How do secrets become environment variables?
Streamlit Community Cloud uses TOML format for secrets. Top-level keys in the Secrets field are automatically exposed as environment variables in the deployed app.
Your code calls genai.Client() which reads the GEMINI_API_KEY environment variable automatically. No code changes are needed between development and deployment.
- Click Save.
- Click Deploy.
Wait 2-3 minutes for the app to build. You will see deployment logs on the right-hand side of the screen while the app installs dependencies and launches.
App stuck on building or showing an error?
If the build fails, check the logs for a dependency error. Make sure your requirements.txt in GitHub lists streamlit==1.58.0 and google-genai on separate lines.
If you see an API key error after the app loads, go back to Advanced settings and verify your secret is formatted exactly as GEMINI_API_KEY = "your-key" with the quotes included.
Help me debug my Streamlit deployment
Test your live app and copy the URL
Once the build finishes, your app is live at a public URL ending in .streamlit.app. Before you share it, test that the full flow works.
What do you think will happen when you fill in the form and click Generate Lesson Plan?
- In the sidebar, enter Fractions as the Topic.
- Select 3-5 as the Grade Level.
- Enter Math as the Subject Area.
- Set the Class Duration to 45 minutes.
- Click Generate Lesson Plan.
After a few seconds, you should see a fully formatted lesson plan appear below the sidebar. It includes Learning Objectives, Materials Needed, a Lesson Outline with timing, an Assessment Strategy, and Differentiation suggestions.
- Confirm the Download Lesson Plan button appears below the lesson plan.
- Click it to verify you can download a .txt file of the plan.
- Copy your app's URL from the browser address bar.
- Bookmark it for yourself.
What is your app's URL?
Streamlit Community Cloud assigns your app a URL based on your GitHub username and repo name. It follows the pattern yourname-lesson-plan-generator-streamlit-app-xxxx.streamlit.app.
Anyone with this URL can visit your app and generate lesson plans. Since your repo is public, the app is public by default.
Form works but no lesson plan appears?
If you see a spinner that never resolves, your GEMINI_API_KEY secret may be incorrect. Click Manage app in the lower-right corner of your deployed app and check the logs for an authentication error.
Make sure you copied the full API key from Google AI Studio without any extra spaces.
Help me debug my Gemini API connection
This is your deployed AI application. You built, designed, and shipped a complete web app using vibe coding, without writing a single line of code manually. Any educator can now visit your URL and generate lesson plans instantly.
Secret mission
Add Pedagogical Framework Selection
Your lesson plan generator produces great plans, but every plan follows the same structure. Different educators use different instructional design frameworks. Can you add a framework selector that changes the entire output structure based on the teacher's preferred pedagogical approach?
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely on free services, so there are no ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- GitHub repository: lesson-plan-generator (free, no ongoing cost).
- Streamlit Community Cloud app (free for public apps, stays running indefinitely).
- Google AI Studio API key (free tier, no billing attached).
Keep everything running
No action needed. Choose this if you are still actively building or want to keep your app live for others to use.
- Your Streamlit Community Cloud app stays live at no cost. Free-tier Gemini API rate limits apply, which are suitable for personal and demo use.
- Your GitHub repository remains available and can be updated at any time.
- Your Google AI Studio API key stays active on the free tier with no billing account attached.
Pause - I'll come back to this later
Shut down the running app without deleting it. Your code stays intact for when you return.
- Go to your Streamlit workspace at share.streamlit.io.
- Click the overflow menu icon next to your app and select Settings.
- Under the Sharing section, toggle your app to private. This hides it from public access while keeping it deployed.
- Your GitHub repo and API key stay untouched. When you are ready to resume, toggle the app back to public.
Delete - I don't want to use this again
Remove all project resources and start fresh. Follow each step below.
- Delete your Streamlit Community Cloud app:
- Delete your GitHub repository:
- Delete your Google AI Studio API key:
That's a Wrap!
That's a Wrap!
Nice work! You just designed and shipped a complete AI-powered lesson plan generator without writing a single line of code manually.
You've learned how to:
- Build a full web application using a vibe coding workflow where Claude designs the UI, Codex writes the code, and Streamlit Community Cloud hosts the result.
- Integrate the Google Gemini API to generate structured, educational lesson plans from natural-language prompts.
- Deploy a live web app accessible to any educator with just a URL, proving you can take an idea from concept to production using AI agents.
- Secret Mission: Added pedagogical framework selection giving teachers customizable lesson plan structures across 5E Model, Backward Design, and Direct Instruction.
Ready to quiz yourself?