A personal AI tutor with a teacher-only brain and swappable subject roles. One brain, many masks.
Status: a working tutor, used daily on a phone. Phases 0–5, 7, 10, 11, 11b, 11c and 13 are done; Phase 6 (daily use) is the standing one. It is live at
https://mathos.amirj4m.comas an installable web app, and as an Android package you can download and side-load.It teaches, and it leads.
mathos chatholds a real conversation under the teacher constitution, authors a teacher from a plain sentence, and drives tools. Since Phase 13 it also plans: on a new teacher it asks what you are aiming at and how much time you have — at most two questions — then designs a syllabus, puts it up whole, and teaches it in order (D-084 to D-092). It knows what day it is in your timezone, so "that's enough for today" ends the sitting instead of delivering four weeks of material in one evening (D-096) — and if you ask for more it teaches you anyway.Review is real. FSRS decides when a concept comes back; the question is written fresh every time and graded by the brain, nothing is stored to be re-asked, and a concept you keep losing is taught again from another direction (D-040 to D-044). Every answer is graded exactly once (D-048). Nothing enters the rotation without your approval (D-032) — except an item of a plan you already approved by name (D-085). Say a second subject mid-lesson and you are offered a move, never answered inline (D-006, D-036).
Everything persists, in one SQLite file outside this repository (D-027). A teacher can be deleted with everything it remembers, explicitly and with a snapshot taken first (D-091). Reminders are opt-in, never sent on an evening with nothing due (D-077).
The constitution is measured, not just written — on 31 of its 39 cases. 0% leak, 0% false refusal, zero bare refusals, on the prompt alone, across every recorded run. The denominator is 31, not 39: the eight cases added for the plan layer and the intake ordering (E-31 to E-38) have never been graded, so no figure in this project says anything about them. See
docs/eval/BASELINE.md, which is honest about what a 0% on cases you wrote yourself does not prove. Two caveats belong here rather than in a footnote. The corpus now holds 39 cases and only 31 have ever been graded: the eight added for the plan layer and the intake ordering have never been run. And the CI gate reported success for two months without ever executing — the key was in the wrong kind of GitHub secret and the job skipped silently. It now fails rather than skipping (D-099, D-101), but it has still never completed a run that graded anything, and one400 invalid_request_errorseen during that work is unattributed (D-102). Neither is resolved.The instrument has been measured too. A cheaper eval judge was tried and rejected on evidence — it reported an 8.3% leak rate on a corpus the expensive one reports 0% on (
docs/eval/JUDGE-VALIDATION.md). What using Mathos costs is written down with the arithmetic shown:docs/COSTS.md.And the review engine has been driven, not just built.
docs/eval/REVIEW-DRIVE.mdis real sessions against the live model, written up with the weak parts left in.The brain is built headless (D-021) and has three clients it knows nothing about: a CLI harness, an HTTP API (Phase 7), and the web app (D-069). No streaks, no goals, no XP, no badges — a number you can protect becomes a thing to protect instead of a thing to learn. See
web/README.md.
Mathos is a private, personal AI tutor. Its brain has one fixed identity — a teacher — and nothing else. It teaches conversationally, remembers what you know and what you forget, and brings things back for review using spaced repetition so they actually stick.
Review is not flashcards. The scheduler decides when a concept comes back; the tutor writes a new question about it every time — a definition today, a counterexample tomorrow, "explain this to a beginner" the week after — reads your answer, and grades it. A stored card teaches you the card; a question you have not seen before makes you hold the concept.
It is not a general assistant. It will not look up a price, recommend a restaurant, or tell you who called you. When you ask for those, it declines and redirects to what it does do: teach you how to do them yourself. That refusal is the whole point — it is what makes Mathos different from plain ChatGPT or Claude.
Mathos supports any subject — Greek, Linux, English, Go, a driving-license exam, guitar — but you do not pick from a fixed menu. You describe the teacher you want in a sentence, and the brain becomes it, while always staying a teacher.
"Be a truck-driving-license teacher, my exam is tomorrow, let's review the test questions." The brain authors that role itself, spins up a fresh learning scope and review rotation for it, and enters it — still under the same teacher-only rules. No new code per subject, and no flag: the profile is written from what you actually said.
The author learns by using (heavy day-to-day SSH use is what made Linux commands stick), and forgets things he only read once (the Ebbinghaus forgetting curve). Asking an assistant "explain this word" one time doesn't make it stay — you just re-ask next week. Mathos is the persistent 1:1 tutor that fixes this: it tracks your weak spots, schedules reviews, and is always available and conversational.
- One brain — a single subject-agnostic engine (the teacher constitution + the learning store + the review scheduler + the LLM). It knows how to teach, not any one subject.
- Many masks — each subject is a lightweight role: a persona frame worn over the constant constitution, plus its own learning scope, its own review rotation, and its own chat thread. Masks are data, not code. Switching masks never mixes subjects: you are offered the move, and when you take it you arrive in that teacher's conversation rather than dragging the last one along.
- Layer 1 — Core engine (subject-agnostic). The "heart": teacher constitution, role manager, the learning store, an FSRS spaced-repetition scheduler, and the LLM brain with tool-use.
- Layer 3 — Roles / personas. Each teacher is a swappable frame on the constant constitution, with its own scope, its own review rotation, and its own thread. A "my teachers" list lets you switch between them.
- Layer 2 — The frame. An installable web app on the owner's own domain (D-069,
superseding D-012), chosen over a Telegram bot that was cheaper and brought voice, images
and push for free — and rejected because it is blocked in Iran, would route his learning
data through a third party, and would confine the interface to somebody else's frame. Four
screens in
web/, on the same origin as the API. Images work end to end; voice is the browser's dictation rather than the server-side speech D-013 specifies, and says so on screen; reminders are built and are off until you turn them on (D-077). What it stands on is the layer under it — the brain as a service behind an HTTP API (D-063 to D-067), because the API key may never ship to a device.
Build order: Layer 1 → Layer 3 → Layer 2 (D-015 as reordered by D-021). The substantive rule is unchanged — the subject-agnostic core comes before any one subject.
CLI harness HTTP API (/v1, streamed turns, shared secret)
│ ▲
│ └── web/ the app: four screens, same origin, static files
└──────┬───────────┘
▼
Session controller (commands, moves, transcript, usage — one for both)
│ text
▼
Teacher Constitution (data, loaded verbatim; refuses non-teaching)
│
Brain (Claude + tool-use)
│
Role Manager (sentence → role, roles as data)
├──────────────────────┬─────────────────────┐
▼ ▼ ▼
Mathos DB (SQLite) jamgate (later) Google Calendar
learning store durable learner (optional, later)
roles · threads profile only —
concepts · FSRS a few dozen facts
observations
All learning state lives in Mathos's own database; jamgate holds only the durable learner
profile (D-020). Full detail in docs/DESIGN.md.
Mathos is a thin layer over things the author already runs:
- Brain = Claude, via the Anthropic API, with tool-use.
- Scheduler = FSRS (
ts-fsrs, a proven open spaced-repetition engine). - Durable learner profile = jamgate, his
self-hosted memory at
memory.amirj4m.com, under the scopeamir/mathos. Only who he is, how he learns, and what he's working toward — a few dozen facts. Everything the tutor learns about the learning lives in Mathos's own DB instead, because jamgate's quality gate is built for durable facts, not for a tutor's high-volume granular writes. No tutor logic goes inside jamgate. - Calendar = his existing Google Calendar connector (optional, late).
mathos/
├── README.md ← you are here
├── CLAUDE.md ← how to work in this repo
├── LICENSE ← MIT
├── constitution/
│ ├── CONSTITUTION.md ← the teacher constitution — data, not code
│ └── cases.yaml ← machine-readable eval corpus
├── docs/
│ ├── DESIGN.md ← full architecture
│ ├── DECISIONS.md ← dated decision log (living document)
│ ├── ROADMAP.md ← phased plan with exit criteria
│ ├── BACKGROUND.md ← why it exists: the market scan and the learning science
│ ├── COSTS.md ← what a session, a month and an eval run actually cost
│ ├── API.md ← the HTTP surface: routes, streaming, auth
│ ├── DEPLOY.md ← how it runs on the droplet, and how to restore a backup
│ └── eval/ ← constitution eval results; BASELINE.md is the summary
├── src/ ← the brain (TypeScript); see src/README.md
├── web/ ← the app (D-069); see web/README.md
├── test/ ← the brain's tests; the app's are in web/test/
├── deploy/ ← systemd units and the nginx server block, as data
├── backend/ ← retired placeholder; see backend/README.md
└── pwa/ ← retired; the app is in web/ (D-069)
If you want to use Mathos rather than work on it, start at
docs/QUICKSTART.md — clone, npm install, npm link, put a key in
.env, then mathos chat and say what you want to learn. No programming needed, and the
learning store stays on your own machine, outside this repository.
Node is pinned in .nvmrc. npm install, then copy
.env.example to .env and set ANTHROPIC_API_KEY — needed for chat
and eval, and for nothing else.
| Command | What it does |
|---|---|
npm run chat |
a teaching conversation from this terminal |
npm run chat -- --resume |
pick the last conversation back up where it stopped |
npm run mathos -- review |
what is due across every teacher; add a name to work through it |
npm run mathos -- roles |
the teachers you have; roles resume <name> carries one on |
npm run eval |
run the constitution corpus against the live brain and score it |
npm run eval -- rejudge <report.json> |
re-grade a past run's replies with a different judge; no brain calls |
npm run mathos -- db |
inspect the learning store (-- db help for the actions) |
npm run mathos -- db backup |
a consistent snapshot of the store, rotated |
npm run mathos -- serve |
the same brain over HTTP, for a client that is not a terminal |
npm run mathos -- doctor |
check the constitution, credentials, store and paths are in place |
npm run check |
typecheck + lint + format check + tests — run this before committing |
npm run typecheck |
tsc --noEmit |
npm run lint |
ESLint |
npm run format |
Prettier, write |
npm test |
Vitest |
npm run build |
compile src/ to dist/ |
chat and eval cost real API tokens; check and the tests never touch the network.
docs/COSTS.md prices both with the arithmetic shown — roughly $0.79 for a
twenty-minute study session and $1.39 for a full 31-case eval run. A full eval is a
phase-boundary measurement rather than an iteration loop (D-055); use eval -- --only E-01,E-07
while working, and eval -- rejudge to compare judges without paying for the brain at all.
The learning store is a single SQLite file, kept outside this repository —
$XDG_DATA_HOME/mathos/mathos.db by default, or wherever MATHOS_DB_PATH points.
mathos db status says where it is.
Do not back it up by copying that file. The store runs in WAL mode, so the most recent
writes are in a -wal beside it and a cp produces a database that opens cleanly and is
quietly missing them. mathos db backup takes a real snapshot with VACUUM INTO, and
docs/DEPLOY.md §5 has the rotation and the restore.
Conventions, the constitution's central role, and the decision-log discipline are in
CLAUDE.md.
MIT © 2026 jam