Gradus: reasoning practice for rigorous STEM courses
A Flutter app that models a course as a concept graph, grades answers deterministically, diagnoses why a miss happened, and routes the learner to the smallest useful prerequisite repair.
Status · Closed beta plus public demo. Solo project since March 2026; last verified closed-beta deploy May 8, 2026; last commit May 30, 2026. No pilot outcome data yet.
Gradus turns rigorous STEM courses into concept-graph practice: deterministic grading, a diagnosis of why an answer missed, a repair target chosen by walking the prerequisite graph, and a transfer check before moving on.
Gradus is a learning app for courses where the hard part is the reasoning, not the recall: real analysis, topology, convex optimization, algorithms, automata. Instead of tracking flashcards, it tracks mastery per concept in a graph with prerequisites and author-defined fail points, grades every answer with rules rather than a language model, and turns each miss into a specific diagnosis and a specific repair. It runs on web, Android, and iOS from one Flutter codebase, with a public no-sign-in demo and a closed beta.
Students in proof-based and systems courses rarely lack explanations; what they lack is a precise account of where their reasoning broke and which earlier idea caused it.
The idea: make the miss legible
Gradus started in March 2026 as an adaptive course engine for proof-based mathematics, piloted on a chapter of Rudin's Principles of Mathematical Analysis, and grew into what its docs call a reasoning mastery platform for rigorous courses. The framing I settled on is that the product is not an answer machine. A chat model can already explain any theorem on demand. The durable problem is that a student, and their instructor, usually cannot see which step failed, which prerequisite was missing, or whether the idea would transfer to a differently worded problem.
The whole app is organized around one loop: Predict → Attempt → Explain → Diagnose → Repair → Transfer → Reflect. The learner states an expectation before answering, answers, gives a short justification, gets a structured diagnosis rather than just right/wrong, is sent to the smallest useful repair target, is asked a transfer item that needs the same underlying idea, and finally names what changed. Product copy, the demo, Progress Review, and the teacher views are all supposed to make that loop visible; features that do not strengthen one of its stages are treated as secondary.
The concept graph
A course is a package of JSON documents, not a deck of cards. The hierarchy is course → chapter → lesson → concept → item family → question instance. A concept is the atomic unit: a definition, theorem, technique, or proof pattern. Each one lists its prerequisites and neighbors and carries author-defined fail points, which are the specific wrong moves a learner is expected to make on that concept.
Each concept has item families at four cognitive stages: A recognition, B recall, C structured completion, and D reasoning. An item family is a reusable question template tied to one concept; a question instance is one rendered prompt from it. Stage unlocks are threshold-based on the concept's mastery scores, so a learner does not see a stage-D proof-reasoning item until the recall and completion evidence supports it. Transfer prompts attach to stage-D items.
Concept
Atomic unit with prerequisites, neighbors, difficulty and importance weights, and a list of expected fail points.
Item family
A question template with an answer spec (mode, canonical answer, aliases) and a stage from A to D.
Mastery vector
Per-concept recall, reasoning, stability, and overall scores, updated by fixed increments per stage.
Deterministic grading and diagnosis
The first architecture decision, recorded in the project's ADR 0001 on 2026-03-07, was that the runtime would not use a language model to grade anything. Grading is rule-based: exact match, regex, multiple- and few-choice, and sequential fill-in-the-blank, with LaTeX-aware normalization so that equivalent notation is treated as equal. Language models are allowed only offline, for drafting content. The reasons were reproducibility, easier A/B testing of scheduling policies, and simpler debugging; the accepted cost is less flexibility for free-form responses.
Diagnosis is also deterministic. A miss is matched against the concept's fail points and assigned one of twelve error types: eight general ones (prerequisite gap, recall miss, reasoning miss, confusion, missing step, wrong application, scope error, careless miss), three proof-specific ones (quantifier error, theorem-condition error, counterexample gap), and a no-error value. The error type decides what happens next. A prerequisite gap triggers a backward breadth-first search from the missed concept along prerequisite and neighbor edges; candidates are ordered by graph distance and then by mastery, and any concept below a weakness threshold is preferred as the repair target. Confusion and scope errors look at neighboring concepts first, since the learner mixed up two nearby ideas rather than missing an earlier one. After repair, a transfer check asks for the same idea in a different form before the concept is treated as recovered.
Figure 1 — The seven-stage loop, with the Diagnose → Repair path expanded: a prerequisite-gap error type walks backward through the concept graph to the nearest weak prerequisite.
The content pipeline
Writing concept graphs with fail points by hand is slow, so most course packages come from a generation pipeline. This is infrastructure, not the product: the learner-facing promise is the diagnosis and repair, and the packages are plain JSON that a human can read and edit. The generator runs in a manual-chat mode where a coding agent reads a prompt file and writes a JSON response file; there is also a direct API path for unattended runs. Generation is checkpointed and resumable, and chapters can be produced in parallel and merged.
Nothing generated is trusted by default. A validate-and-repair tool maps every failure back to a concept or item family, applies coercion fixes for issues that can be repaired mechanically, and flags the rest for regeneration. A strict LaTeX gate and JSON schema checks block publishing. A separate readiness rubric scores whether a package can support an instructor-facing pilot rather than whether its JSON parses, covering graph quality, prerequisite links, diagnosis coverage, repair paths, transfer practice, and accessibility. Publishing uploads an immutable versioned snapshot plus a current pointer to Firebase Storage, with a Firestore catalog entry that the app reads at runtime, so a bad package can be rolled back.
The product surfaces
One Flutter codebase builds the web, Android, and iOS apps. Progress lives in SQLite on device and in Cloud Firestore when the learner signs in; a sync service merges guest progress into the account on first sign-in. Firebase Hosting serves three routes: a static landing page at /, a public demo at /demo that needs no sign-in or email and stores progress only in the visitor's browser, and the closed-beta app at /app, gated by per-account access records. TypeScript Cloud Functions handle waitlist notifications, demo telemetry, and short-lived signed URLs for course assets.
Around the practice loop there is a Learning Mode reader that shows generated text for each concept, with optional narration rendered ahead of time by a local Kokoro model or OpenAI text-to-speech; a Progress Review area for historical diagnoses, coverage, weak patterns, and repair actions; and role-gated Teacher Hub and Organization Dashboard views that surface class-level fail-point patterns and transfer results. Math renders through a KaTeX-subset Flutter package.
Where it stands
Gradus is a closed beta with a public demo. The README's catalog table lists 13 published remote courses: proof-based mathematics (topology, complex analysis, probability), an ML-readiness wave (linear algebra, convex optimization, statistical inference), a computer-science foundations wave (programming concepts, algorithms, operating systems, automata, AI/ML systems, cybersecurity), and a business-analytics slice used by the demo. The original real-analysis (Rudin) course is published alongside them as a remote-first library entry. The last verified closed-beta deploy is from 2026-05-08 and the last commit from 2026-05-30. It has been a solo project since the first commit on 2026-03-07.
What is not established: any learning outcome. A pilot protocol and a readiness rubric exist, but no school pilot has run and no efficacy numbers exist, so the page makes no such claim. Near-term work is filling learning-text and narration gaps across the published catalog, continuing the machine-learning course sequence, and an in-progress audit that flags template-stamped item families in generated courses so they can be regenerated.
FAQ
Is Gradus an AI tutor?
No. It does not chat, and it does not explain on demand. It grades with rules, diagnoses a miss with author-defined fail points, and routes the learner to a prerequisite repair and a transfer check. AI is used offline to draft course packages, which are then validated and human-readable.
Does a language model grade my answers?
No. ADR 0001 (2026-03-07) fixed the runtime as deterministic: exact match, regex, choice, and sequential fill grading with LaTeX-aware normalization. The trade-off is less flexibility for free-form written answers.
How is the repair target chosen?
For a prerequisite-gap error, a backward breadth-first search from the missed concept walks the prerequisite edges and picks the nearest concept whose mastery is below a weakness threshold. Confusion, wrong-application, and scope errors rank the concept's neighbors first instead, and reasoning-type errors search prerequisites only.
Can I try it?
The public demo at gradus.raulv.dev/demo needs no sign-in or email and keeps progress only in your browser. The full app at /app is a closed beta.
Does it work?
Unknown in the measured sense. The engine, content, and dashboards are built and deployed, and a pilot protocol is written, but no pilot has run and there are no learning-outcome results.
What I built
A course data model — course, chapter, lesson, concept, item family, question instance — where each concept carries prerequisites, neighbors, expected fail points, and staged item families from recognition through reasoning.
A deterministic session engine: rule-based grading (exact match, regex, choice, sequential fill-in-the-blank) with LaTeX-aware normalization, a per-concept mastery vector, and a scheduler for lesson-only, review-only, and mixed sessions.
A diagnosis and repair path that maps a miss to one of twelve error types, then runs a backward breadth-first search over the prerequisite graph to pick the repair target, followed by a transfer check.
A content pipeline where a coding agent drafts course packages through prompt and response files, with checkpoints, auto-repair of coercible issues, strict LaTeX and schema gates, a readiness rubric, and versioned publishing to Firebase Storage.
The app surfaces: a Learning Mode reader with generated text and optional narration, Progress Review, role-gated teacher and organization dashboards, and a public demo that stores progress only in the browser.
Persistence and sync: SQLite on device, Cloud Firestore when signed in, and a merge of guest progress on first sign-in, plus TypeScript Cloud Functions for waitlist notifications, demo telemetry, and signed course-asset URLs.
How it works
The learner predicts, attempts, and briefly explains; the engine grades the attempt with a rule, never a model call.
A miss is matched against the concept's author-defined fail points and labeled with an error type such as prerequisite gap, quantifier error, or theorem-condition error.
For a prerequisite gap, a backward breadth-first search from the missed concept walks the prerequisite edges, orders candidates by distance and then mastery, and prefers a concept below a weakness threshold as the repair target; confusion and scope errors check neighboring concepts first.
After repair, a transfer check asks a different-looking item that depends on the same idea, and the learner reflects on what changed.
Mastery is a small per-concept vector (recall, reasoning, stability, overall) updated by stage; the scheduler picks the next concept and operation from those scores and the session budget.
Independent project · adaptive learning · app systems
Status
Closed beta plus public demo. Solo project since March 2026; last verified closed-beta deploy May 8, 2026; last commit May 30, 2026. No pilot outcome data yet.
Focus
Concept-graph coursesDeterministic diagnosisPrerequisite repairTransfer checksFlutter web + mobile
Stack
Flutter
Dart
SQLite
Cloud Firestore
Firebase Auth / Hosting / Storage
TypeScript Cloud Functions
KaTeX subset (flutter_math_fork)
Kokoro / OpenAI TTS
Glossary
Concept graph
The course model: concepts linked by prerequisite and neighbor edges, each with staged item families and expected fail points.
Fail point
An author-labeled expected error pattern on a concept, used to turn a miss into a specific diagnosis.
Item family
A reusable question template tied to one concept; each rendered prompt from it is a question instance.
Stage
The cognitive level of an item family: A recognition, B recall, C structured completion, D reasoning.
Repair target
The concept selected to remediate a diagnosed weakness, chosen by a backward search over prerequisites.
Transfer check
A different-looking item that requires the same underlying idea, asked after repair to confirm the idea generalizes.