Inspiration:

Indian higher-education classrooms run at 60 to 120 students per teacher. In that setting, a teacher is flying blind: attendance and end-of-term marks are lagging indicators, and by the time it's clear that half the class never understood functions, the syllabus has already moved on to decorators and async.

What bothered us most wasn't the blindness - it was the misdirected remediation. When a gap finally surfaces, the instinct is to re-teach the topic students failed. But students usually fail a topic because they're missing its prerequisite. Re-teaching recursion to a class that never learned functions wastes the lecture and quietly confirms the students' belief that they're bad at programming.

Every analytics dashboard in education can tell a teacher what is broken. None of them tell the teacher what to do on Monday morning. We wanted to build the thing that makes the decision.

What it does:

A normal dashboard says: "The class is failing recursion."

Classroom Memory says: "This week, teach functions. The class is failing recursion the hardest, but they are not ready for it yet. Functions is the foundation that unblocks it, and it opens up thirteen more concepts."

Concretely:

Every student gets a private, persistent memory of what they know - an adaptive mastery graph, a personal recall surface ("explain closures to me"), a learning timeline, and an auto-generated report card. The teacher gets one view that reasons across all of those memories at once - a class heat map over the curriculum graph, a ranked teaching plan, and one-click targeted interventions aimed at the specific named students who need them. The curriculum is a prerequisite graph, not a topic list. Because the system knows recursion requires functions, it can find the root cause of a class-wide failure instead of its loudest symptom. The teaching plan deliberately does not rank concepts by failure rate. It ranks by readiness × unblocking power: which concept can this class actually learn right now, and how many downstream concepts does learning it open up. On our seeded class, the top failure is recursion - but the top recommendation is Functions, because 3 students are ready for it and it unlocks 13 further concepts. That gap between symptom and recommendation is the entire product.

How we built it:

Backend - FastAPI, with a ClassroomProvider interface and two implementations behind it:

DemoProvider - deterministic, in-memory, zero external dependencies. CloudProvider - real graph memory via Cognee Cloud. Both return byte-identical response shapes, so the whole product runs and is fully testable with no credentials, and swapping to live cloud memory changes nothing in the UI.

Memory model - three layers, which is what makes the teacher view possible:

Private student memories - one isolated cloud dataset per learner (student_alice). Shared class memory - a dense graph summarizing all students and concepts. Intervention memory - teacher-assigned reviews written to their own dataset. Why a graph and not a vector database: a vector store only knows two things are similar. This product depends on a different relationship - one concept requires another. "Recursion requires functions" is a directed edge, not a similarity, and the teaching logic is impossible without it. Ask a student's memory "what must I learn before decorators?" and it answers by walking edges, not by matching keywords.

Mastery - a SQLite ledger holds tenant-aware mastery weights. Thresholds: < 0.35 red, 0.35–0.75 amber, > 0.75 green. Decay is view-layer only -the clock never mutates stored mastery; concepts render as "rusty" based on time since the last successful attempt, so the forgetting curve is displayed without being destructive.

Frontend - a vanilla-JS SPA with vis-network graph rendering. No mastery state lives in the browser.

Deployment - FastAPI on Render, static SPA on Vercel, with /api/* rewritten to the backend.

Challenges we ran into:

Async cloud, sync framework. Cognee's SDK is async; our FastAPI endpoints are sync. Naively bridging them deadlocked. CloudProvider now runs all cloud calls on a dedicated background event loop, and slow non-critical writes use fire-and-forget wrappers so the UI never blocks on a 16-second ingestion.

Deletion is eventually consistent. Resetting a student calls forget(), but the dataset doesn't disappear immediately - re-seeding into the same name raced against the pending delete and silently resurrected old state. We solved it with progressive backoff plus a fallback to versioned dataset names.

Ingestion latency shaped the data model. At measured latency (~16s per remember()), seeding one concept at a time would have taken ~6 minutes per student. We seed each student once with a single combined, relationship-rich curriculum document instead.

A capability that didn't exist. Cognee Cloud's remote improve() endpoint returned 404 on our tenant. We had a choice: fake it, or say so. Mastery re-weighting runs app-side with identical feedback-weight semantics, persisted in the ledger, and the provider boundary is written so native improve() drops in with zero UI change. This is stated plainly in the README and in the code comments. We'd rather ship a working product with one documented limitation than a demo that lies.

Graph rendering. vis-network renders off-centre inside a flex parent unless four settings are held together: autoResize:false, stabilization fit, absolute-fill CSS, and fit({animation:false}).

Accomplishments that we're proud of:

It's deployed and you can break it. Not a scripted demo- durable state, class setup, enrollment, curriculum import, and a teacher workflow a stranger can drive end to end. A 22-concept prerequisite graph with a dense class-level graph of roughly 290 relationship edges. A 12-check automated verification that runs the full memory lifecycle against the real tenant, plus a deterministic smoke test that passes with no credentials at all. Subject-agnostic by construction. The engine reasons over a prerequisite graph, not over Python. Import a different JSON curriculum through the UI - with validation of concept IDs, prerequisites, question structure and answer indexes - and the class is live. We documented what doesn't work, which is rarer than it should be.

What we learned:

The hardest part was never the AI. It was deciding what question the system should answer. "Which concept is failing most?" is easy and useless. "Which concept should I teach next, and why?" requires prerequisite structure, per-student state, and a readiness model - and it's the only question a teacher actually acts on.

We also learned that multi-tenancy is an architectural decision you make on day one or never. Because every learner was a separate dataset from the first commit, scaling from one classroom to a department is configuration, not a rewrite.

What's next for Classroom Memory LMS/syllabus import, so a college doesn't hand-author its prerequisite graph. True spaced repetition - model forgetting over real elapsed time rather than inferring it from attempt history. Pilot-blocking work: institutional SSO, per-college data isolation and retention policy, and an evaluation harness. The experiment we actually want to run: one semester, two sections. Remediate one on the prerequisite, one on the failed topic. Compare mastery lift. The core claim is narrow and testable — and nobody has tested it.

Built With

Share this project:

Updates

Submission history