At a Glance
- Shipped at the Zero to Agent Global Hackathon — built a full-stack AI agent that generates constraint-aware weekly class schedules within seconds
- Integrated Groq's Llama 3.3 for AI scheduling and chat-based refinement — live at classmaker.ai
- Next.js, TypeScript, Groq (Llama 3.3), Tailwind CSS, Vercel
Problem
Building weekly block schedules for after-school programs is a combinatorial constraint problem — and coordinators are solving it manually in spreadsheets. Every student has a pickup time, grade, and activity preferences. Every class has a capacity limit, grade range, and fixed time blocks. The scheduler has to satisfy all of those constraints simultaneously across dozens of students and classes, and then field individual requests like "move Maya out of Monday art" after the fact. That last part — ad-hoc refinement — is where spreadsheets completely break down.
The real question is whether a large language model can serve as the scheduling engine: not just generate text about scheduling, but reason through constraints and produce a valid, structured schedule as output — and then accept natural-language corrections and revise it. That's an agentic task, and it requires a different kind of prompt design than question-answering.
Solution
ClassMaker.ai is a full-stack Next.js application that uses Groq's Llama 3.3 as a constraint-aware scheduling agent. Coordinators enter students and classes — manually or via CSV — and the AI generates a complete weekly class schedule within seconds, respecting capacity limits, grade ranges, fixed time slots, and individual pickup times. A built-in chat interface lets them refine the schedule afterward in plain English, with the model re-applying constraints on each revision.
The key design decision was treating schedule generation as a structured output problem rather than a conversation. The system prompt defines the constraint space and output format precisely; the model's job is to produce valid JSON that the frontend can render directly into a color-coded weekly grid — no post-processing layer required. Chat refinement works the same way: the existing schedule is fed back as context, the user's instruction is appended, and the model returns an updated JSON schedule.
Tech Stack
- Next.js (App Router) — the full-stack React framework powering both the frontend UI and the server-side API routes that handle Groq API calls. App Router's server components kept sensitive API keys server-side while React client components handled the interactive schedule grid and chat interface.
- TypeScript — used end-to-end across the application. TypeScript interfaces defined the data contracts for students, classes, and the schedule output schema, catching structural mismatches between the AI's JSON output and the frontend's rendering logic before they became runtime errors.
- Groq API (Llama 3.3-70b-versatile) — the AI inference engine powering schedule generation and chat refinement. Groq's inference speed was critical for a hackathon demo context: sub-second response times on the Llama 3.3 model made the scheduling feel instant rather than like waiting for a model. The API accepts a system prompt, a user message, and optional conversation history, making stateful chat refinement straightforward to implement.
- Tailwind CSS — utility-first styling that made it possible to build a polished, color-coded weekly grid UI in a single day without writing custom CSS classes. The schedule grid uses Tailwind's grid utilities and color palette to render each student's weekly block as a distinct visual row.
- Vercel — zero-configuration deployment of the Next.js app to a production URL. The
GROQ_API_KEYenvironment variable was set in Vercel's project settings; the deployment pipeline handled builds and edge routing automatically. Production was live within minutes of the first working build. - CSV Parsing — a browser-side CSV parser allows coordinators to bulk-import student rosters and class catalogs from existing spreadsheets, which is how real programs manage their data. The parser validates column structure on import and surfaces errors inline before any data reaches the scheduling agent.
- Prompt Engineering for Agents — unlike a Q&A or summarization prompt, the scheduling system prompt had to define an explicit constraint space (capacity, grade range, time blocks, pickup time), an output schema (JSON array of student-schedule objects), and instructions for maintaining those constraints across chat-based revisions. Structured output prompting for agentic tasks is meaningfully different from general instruction following.
The combination of a fast inference API, a structured output prompt, and a stateful chat interface is what makes the system feel agentic rather than just generative.
Deep Dive
AI agents don't have to be complex orchestration pipelines. The simplest definition of an agent is a model that takes actions — in this case, producing a structured, constraint-satisfying schedule rather than free-form text. ClassMaker.ai is a single-model agentic system: one well-designed prompt turns Llama 3.3 into a scheduling engine that can generate and revise weekly block schedules on demand.
This project began at an event in Irvine, CA (April 25, 2026) — my introduction to the Zero to Agent international build week, where developers around the world ship real AI agents from scratch. ClassMaker.ai was built and deployed as part of that global hackathon — a full-stack Next.js app powered by Groq's Llama 3.3, live on Vercel.
Why This Project?
After-school scheduling is a real operations problem. I've worked in educational settings long enough to know that coordinators waste significant time every week building and patching student schedules in spreadsheets. It's a textbook constraint satisfaction problem — exactly the kind of structured reasoning task that a capable LLM with a well-designed prompt can take over entirely.
I also wanted to demonstrate the difference between a generative AI feature (an LLM answering a question) and an agentic AI system (an LLM taking structured, consequential actions as its primary output). ClassMaker.ai is the latter. The model's output isn't text to be read — it's a schedule to be rendered, used, and revised. That distinction matters in production AI applications, and it was the central engineering challenge here.
What You'll Learn from This
- How to design a system prompt that turns an LLM into a constraint-aware agent producing structured JSON output
- How Next.js API routes keep AI API keys server-side while feeding results to React client components
- Why Groq's inference speed matters for interactive agentic applications — and how to pick the right model for a latency-sensitive use case
- How to implement stateful chat refinement: feeding the existing schedule back as context so the model revises rather than regenerates from scratch
- How CSV parsing at the browser level lets users import real-world data without a backend upload pipeline
- What it takes to go from zero to a production-deployed AI application in a single day
Key Takeaways
- Structured output is the core of agentic AI: The model's usefulness came entirely from its ability to return valid, constraint-satisfying JSON — not from its conversational ability. Prompt design drove that reliability.
- Groq's speed changes what's possible: Sub-second inference on Llama 3.3 made the scheduling interaction feel like a native app feature, not an AI API call. Latency is a UX decision as much as a technical one.
- Chat refinement requires context management: Each refinement request passes the full current schedule back to the model as context. Without it, the model has no basis for making targeted edits — it would regenerate from scratch every time.
- Next.js unifies the stack: API routes, server components, and client components in one framework eliminated the need for a separate backend service. For a hackathon project that had to be production-ready in hours, that mattered enormously.
- Vercel removes deployment friction: A
vercel deploycommand and one environment variable was the entire deployment story. Zero infrastructure decisions, zero DevOps overhead. - Scope clarity is the real hackathon skill: Finishing a working, deployed application in a day required cutting every feature that wasn't essential to the core demo — and knowing which features those were before writing a single line of code.
Architecture Overview
ClassMaker.ai follows a clean full-stack architecture with Next.js handling both the UI and the server-side AI integration. The client never touches the Groq API directly — all model calls go through Next.js API routes, which keeps the API key server-side and allows server-side validation of inputs before they reach the model.
↓ Student + class data as JSON (manual or CSV import)
Next.js API Route (Server-Side)
↓ Constructs constraint-aware system prompt + user message
Groq API — Llama 3.3-70b-versatile
↑ Returns structured JSON schedule
Next.js API Route → React Client
↓ Renders color-coded weekly grid per student
Chat Refinement Loop
↓ User plain-English instruction + current schedule → revised JSON
| Component | Role | Why This Choice |
|---|---|---|
| Next.js App Router | Full-stack framework | Server components + API routes in one codebase; no separate backend needed |
| TypeScript | Type safety | Enforces data contracts between AI output schema and frontend rendering logic |
| Groq (Llama 3.3) | AI scheduling engine | Industry-leading inference speed; Llama 3.3-70b follows structured output prompts reliably |
| Tailwind CSS | Styling | Rapid UI development; color-coded grid built with utility classes, no custom CSS |
| Vercel | Deployment | Zero-config CI/CD for Next.js; production URL in minutes, env vars in dashboard |
How It Was Built
Step 1
Define the Data Model in TypeScript
Before writing any AI integration, I defined TypeScript interfaces for the three core data structures: Student, Class, and ScheduleEntry. These interfaces served as the contract between user input, the AI prompt, and the frontend renderer — if the model returned a schedule that didn't match the ScheduleEntry shape, TypeScript would surface the mismatch before it became a runtime error in the grid component.
interface Student { id: string; name: string; grade: number; pickupTime: string; preferences: string[]; goals: string; } interface Class { id: string; name: string; day: string; blockStart: number; blockEnd: number; gradeMin: number; gradeMax: number; capacity: number; type: string; } interface ScheduleEntry { studentId: string; studentName: string; assignments: { day: string; block: number; className: string }[]; }
Step 2
Design the Constraint-Aware Scheduling Prompt
The system prompt is the most important engineering artifact in the project. It defines the constraint space the model must satisfy, specifies the exact JSON output schema, and explicitly prohibits preamble or commentary around the JSON. Without those last two instructions, Llama 3.3 will sometimes wrap its output in markdown code fences or add an explanation sentence — both of which break JSON parsing.
Constraints enforced through the prompt: class capacity limits, grade range eligibility, fixed time block assignments, and per-student pickup time cutoffs (a student with a 4:30pm pickup cannot be scheduled into a block that ends at 5pm). Each constraint was described explicitly in the system prompt with an example of the edge case it was meant to prevent.
const systemPrompt = `You are a school scheduling agent. Given a list of students and available classes, generate a weekly block schedule that: - Respects each class's capacity limit (never exceed it) - Only assigns students within the class's grade range - Never schedules a student into a block that ends after their pickup time - Assigns each student to at most one class per time block per day Return ONLY a valid JSON array matching this exact schema — no markdown, no explanation, no preamble: [{ "studentId": "...", "studentName": "...", "assignments": [{ "day": "Monday", "block": 1, "className": "Art" }] }]`;
Step 3
Wire the Next.js API Route to Groq
The /api/schedule route receives the students and classes payload from the client, constructs the full prompt, and calls the Groq SDK. Keeping this logic in an API route rather than a client-side function means the GROQ_API_KEY never leaves the server — it's set in Vercel's environment variables and accessed only from the server context.
import Groq from 'groq-sdk'; const groq = new Groq({ apiKey: process.env.GROQ_API_KEY }); export async function POST(req: Request) { const { students, classes } = await req.json(); const completion = await groq.chat.completions.create({ model: 'llama-3.3-70b-versatile', temperature: 0.2, messages: [ { role: 'system', content: systemPrompt }, { role: 'user', content: buildUserMessage(students, classes) }, ], }); const raw = completion.choices[0].message.content ?? ''; const schedule = JSON.parse(raw); return Response.json({ schedule }); }
Temperature was set to 0.2 — low enough to produce deterministic, constraint-consistent schedules without stripping the model of the flexibility to find creative assignments when the constraint space is tight.
Step 4
Implement Chat-Based Schedule Refinement
The chat interface accepts plain-English instructions like "move Maya out of Monday art and into something after 3pm" and returns a revised schedule. The implementation passes the full current schedule as part of the user message alongside the refinement instruction — the model receives complete context and returns a new, constraint-satisfying JSON schedule.
This stateful context passing is what makes refinement work correctly. Without feeding the existing schedule back, the model would treat every chat message as a fresh generation request. With it, the model understands which slots are already occupied and can make targeted, minimal edits rather than regenerating the entire schedule from scratch.
Step 5
Build the Weekly Grid Visualization & Deploy
The schedule JSON is rendered as a color-coded weekly grid — one row per student, one column per time block per day. Tailwind's grid utilities handled layout; each class type was assigned a distinct color class so coordinators can scan the full schedule visually rather than reading row by row.
Deployment to Vercel was a single command. The GROQ_API_KEY was added to Vercel's environment variable settings; the Next.js build pipeline handled the rest. The production URL was live within minutes of the first successful build.
What I Built & What I Learned
- A production-deployed agentic AI application built and shipped in a single day — full-stack Next.js, Groq API integration, CSV import, chat refinement, and live Vercel deployment
- Structured output prompting is a distinct discipline. Getting Llama 3.3 to produce constraint-satisfying JSON consistently required explicit output schema definitions, constraint descriptions with edge-case examples, and an explicit prohibition against any text outside the JSON array
- Inference speed is a product decision. Groq's sub-second latency on Llama 3.3 made the scheduling interaction feel synchronous. A slower inference provider would have required loading states and async UX patterns that complicate both the code and the user experience
- Next.js App Router collapsed the stack. Server components, client components, and API routes in one framework eliminated the need to build and deploy a separate backend service — critical for a single-day timeline
- Context management enables refinement. Passing the full current schedule back on each chat turn was the design insight that made iterative refinement possible. Without it, the model had no basis for making targeted edits
What I Learned & Why It Matters to Employers
ClassMaker.ai demonstrates the full cycle of agentic AI development: problem scoping, data modeling, prompt engineering for structured output, full-stack integration with a production LLM API, and zero-friction deployment. I didn't just connect an LLM to a frontend — I designed a system prompt that turns a general-purpose model into a domain-specific scheduling agent, handled the edge cases where the model needed to be corrected, and shipped a working application to a real URL within a single day. That combination — rapid agentic development with production deployment — is exactly what teams building AI-native products need.
Conclusion & Reflections
The most important lesson from ClassMaker.ai wasn't about scheduling or LLMs — it was about what "production-ready" means for an agentic AI application. It means the model's output is reliable enough to be consumed programmatically, not just read by a human. It means API keys never leave the server. It means the chat refinement loop maintains state correctly across turns. And it means the application is live at a real URL, not running on localhost.
Groq + Next.js + Vercel is a remarkably productive stack for this kind of work. The tooling decisions removed nearly all infrastructure overhead, which meant almost the entire day went into the actual product — the prompt design, the constraint model, the UI, and the refinement flow. For anyone building AI-native applications, that ratio is hard to beat.
| Feature | Status |
|---|---|
| Student entry (manual + CSV import) | COMPLETED ✓ |
| Class entry with constraint validation | COMPLETED ✓ |
| AI schedule generation via Groq (Llama 3.3) | COMPLETED ✓ |
| Constraint enforcement (capacity, grade, pickup time) | COMPLETED ✓ |
| Chat-based schedule refinement | COMPLETED ✓ |
| Color-coded weekly grid visualization | COMPLETED ✓ |
| Production deployment on Vercel | COMPLETED ✓ |
Want to Try the App?
The live app is deployed on Vercel.