Socratic Desmos Tutor GitHub

A tutor for the hard problems. It won't do them for you.

The tutor sits beside a Desmos graphing calculator and watches the student's graph as it changes. When they're stuck, it asks one good question about what's on the screen, so the student does the thinking and gets unstuck faster. It runs on a model on your own machine.

Find a quadratic with vertex (2, −3) that passes through (0, 5).
(0, 5) (2, −3)
Can you just tell me the equation?
Not the equation, but you're close. I marked the vertex on your graph. Your parabola opens down. Does the point (0, 5) sit above or below the vertex?
above… so it should open up?
What in your equation controls which way it opens?

Why it exists

On a hard problem, an answer machine is the shortest path to "done," so students use one. Banning it doesn't change that. This tutor is built to make thinking it through yourself the faster path: no stalling on one misread step, no waiting a day for feedback, and no skipping the part where you actually learn.

It never gives the answer

It doesn't give the answer when a student begs, says they're out of time, or claims the teacher said it was OK. It says no warmly in a few words, then asks a question that moves them one step forward.

It reads the graph, not a guess

Each turn starts from the student's live expressions and recent edits. "Your parabola opens down. What controls that?" beats a generic hint.

Hints only after a real try

Every problem has a hint ladder, from vague to specific. The tutor climbs one rung at a time, and only after the student has made a genuine attempt.

It can draw, carefully

When a student is stuck, the tutor can plot a given, like the stated vertex, as a dashed cue. Code enforces that it can only touch its own tutor_ expressions, never the student's work.

It checks the math, not vibes

Language models are unreliable at algebra. Before the tutor says "yes, that point is on your curve," a real math checker evaluates it.

Teachers see the thinking

Every session is logged. The teacher view replays the graph and chat step by step, so you can see where a student got stuck and how they got out of it.

How a session goes

  1. The student picks a problem. Each one comes with starter expressions, sometimes including a hidden target curve.
  2. They work in Desmos as usual: type equations, drag sliders. The tutor sees each change.
  3. When they ask for help, or (if you turn on nudges) sit idle too long, the tutor asks one short question tied to what's on their graph.
  4. It checks their work against the misconceptions listed for the problem, and offers the next hint only when they've earned it.
  5. When they solve it, the session is marked solved, and the whole path is saved for the teacher.

Student data stays home

By default every model call goes to a model on your own machine or network: llama.cpp, Ollama, vLLM, LM Studio, or anything else that speaks the OpenAI chat API. There are no cloud APIs, no telemetry, and no analytics.

Cloud presets are included for development with fake students only. Point it at an outside provider and demo mode turns on by itself: a warning banner appears and nicknames are auto-generated, so no real names get typed in.

Run it locally

You need Node.js and a local model server that supports tool calling (for example, llama-server --jinja or Ollama with a Qwen 3 model).

git clone https://github.com/killercatfish/desmos-tutor.git
cd desmos-tutor
npm install
npm run dev

Open http://127.0.0.1:5173 for the student view and /teacher for the replay view. Set LLM_BASE_URL and LLM_MODEL in .env to point at your model. To add problems, drop JSON files in problems/. The tutor's teaching policy is plain text in prompts/tutor_system.md, and you can edit it while the app runs.

Status: untested with a real model. This is v0.1, an early experiment. The app, the graph guard and the math checker are covered by 80 passing tests, but so far the tutor has only been run against a fake model server. Nobody knows yet how well real local models follow the Socratic rules. The teacher view has no login, so the server binds to localhost only.

Help wanted

Contributions are welcome, especially:

Open an issue