Course Matrix
Agentic timetable builder platform for students

Course Matrix is an intelligent course timetable builder that generates an optimal timetable for you based on a specific set of restrictions. It also leverages an AI agent that easily translates complex requirements into personalized timetables.
I built out the AI infrastructure behind this project. It uses the following tools:
I added a lot of functionality to the client-side experience when interacting with the chatbot. The app supports multiple conversations, thread branching, message edit + resend, message copying, and more. Conversation threads are persisted to assistant-ui cloud.

A major goal of ours was to provide an AI agent that balanced speed and response quality. I tested various approaches and ended up with a dual-mode chat flow, with one mode being question-and-answer-based (e.g., “What 3rd year math courses can I take in Winter 2026 that satisfy my degree requirements?”) and the other being action-based (e.g., “Generate me a timetable that follows criteria X, Y, Z.”). These are the pipeline steps:
/timetable to trigger the agentic flow in which the system uses tool calling to perform a task. Otherwise, the flow defaults to Q&A.

Reformulate Query: I found that if the user’s raw query were used as the search prompt within our vector DB, the search results often lacked full context. In a multi-message conversation, previous messages add context to the most recent message.
Filter by namespace: Our vector indices are sorted into namespaces on Pinecone, which are essentially buckets for similar documents. We have namespaces for courses, offerings, programs, prerequisites, corequisites, and departments. This allows us to speed up vector searches by narrowing our search to the most relevant group of documents.
Build response: Given the last few messages in the conversation history and the retrieval results, another call is made to the LLM to write a response.
generateTimetable: tool({
description:
"Return a list of possible timetables based on provided courses and restrictions.",
parameters: TimetableFormSchema,
execute: async (args) => {
console.log("restrictions :", JSON.stringify(args.restrictions));
const data = await availableFunctions.generateTimetable(
args,
req,
);
console.log("Generated timetable: ", data);
return data;
},
}),
const result = streamText({
model: openai("gpt-4o-mini"),
system: `System prompt ...`,
messages,
tools: {...},
maxSteps: CHATBOT_TOOL_CALL_MAX_STEPS,
})
result.pipeDataStreamToResponse(res);

Course data is scraped from the school’s course search site. Offering data is scraped from the school’s timetable archive, which is downloadable as PDFs. I wrote a script that extracts data from these sources using regex matching and PDF tooling in Python, namely pdfplumber.
This uses a backtracking algorithm to output the top 10 timetables consisting of all selected course sessions and meeting all time restrictions. Restrictions include blocking off certain times, setting a maximum number of days per week, and more. Results are shuffled for better randomness (variation).
