Repository files navigation

Math Mate

An AI math-tutoring platform. Students work assignment problems through a Claude-powered tutor that checks prerequisite knowledge, resolves weak spots ("gaps") with a mini-lesson, then scaffolds the student through the problem itself — without ever handing over the answer.

Overview

Each tutoring session walks a fixed path:

  1. Intro — greet the student and set up the problem.
  2. Gap check — probe the topics the problem depends on. Any topic below the mastery threshold gets a short mini-lesson and a follow-up check before moving on.
  3. Solve — the problem is revealed and the tutor scaffolds the student toward a solution (hints and guiding questions, never the answer).
  4. Review — a wrap-up once the student answers correctly.

A judge model classifies each turn (attempted? correct?) before the tutor replies, so phase transitions are deterministic rather than inferred from prose. Wrong answers are meant to feed inferred misconceptions back into the student's knowledge profile — that write-back loop is a planned milestone and not implemented yet.

Objectives and goals

  • Never give away the answer. The tutor scaffolds and questions; it doesn't solve.
  • Fix prerequisites before the problem. A student missing foundational topics gets a mini-lesson first, so the main problem is tackled with the right footing.
  • Make mastery a derived, honest signal. Mastery is computed from attempt history (correct / attempted), never hand-set, and unassessed topics are treated as unknown rather than as gaps.
  • Keep the tutor brain testable in isolation. The core state machine and prompt logic have no direct DB or HTTP dependency, so tutoring behavior can be unit-tested with fakes.
  • Close the loop on mistakes (in progress). Wrong answers should eventually update an inferred-misconceptions profile that shapes future sessions.

Tech stack

  • Next.js 15 (App Router) + React 19
  • Supabase (Postgres + Auth, via @supabase/ssr)
  • @anthropic-ai/sdk — Claude Sonnet for tutoring, Claude Haiku for turn judging
  • shadcn/ui + Radix + Tailwind 4 + Recharts
  • Vitest for unit tests

Prerequisites

Installation

  1. Clone and install dependencies

    git clone <repo-url>cd math-mate
    npm install
  2. Configure environment variables

    Create a .env.local file in the project root:

    NEXT_PUBLIC_SUPABASE_URL=your-supabase-project-url
    NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
    ANTHROPIC_API_KEY=your-anthropic-api-key
  3. Set up the database

    Apply the SQL migrations in utils/supabase/migrations/ to your Supabase project, in numeric order (via the Supabase SQL editor or CLI). They set up the student/topic/mastery schema, the tutoring_sessions table, and row-level security (owner-scoped to student_id = auth.uid()).

  4. Run the dev server

    npm run dev

    Open http://localhost:3000.

Commands

npm run dev # Next.js dev server (localhost:3000)
npm run build # production build
npm run lint # next lint (eslint 9)
npm test# vitest run (all *.test.ts under app/ and lib/)
npm run test:watch # vitest watch mode

Run a single test file or filter by name:

npx vitest run app/tutor/stateMachine.test.ts
npx vitest run -t "resolves a gap on a correct answer"

Project structure

  • app/queries/ — typed Supabase query functions (masteries, weaknesses, sessions, problems).
  • app/tutor/ — the tutor brain: state machine, gap classification, system prompt builder, turn judge, and conversation orchestration. Pure logic with injected dependencies (no direct DB/HTTP), so it's unit-testable with fakes.
  • app/api/sessions/ — HTTP layer: session bootstrap/resume and the per-turn message endpoint (streamed as NDJSON).
  • utils/supabase/ — Supabase client setup and SQL migrations.
  • lib/historyCache.ts — ephemeral conversation-transcript cache, separate from the durable session row.
  • app/ (App Router pages) — dashboard, courses, login, and the tutoring UI.

See CLAUDE.md for a deeper architectural writeup.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Math Mate

An AI math-tutoring platform. Students work assignment problems through a Claude-powered tutor that checks prerequisite knowledge, resolves weak spots ("gaps") with a mini-lesson, then scaffolds the student through the problem itself — without ever handing over the answer.

Overview

Each tutoring session walks a fixed path:

  1. Intro — greet the student and set up the problem.
  2. Gap check — probe the topics the problem depends on. Any topic below the mastery threshold gets a short mini-lesson and a follow-up check before moving on.
  3. Solve — the problem is revealed and the tutor scaffolds the student toward a solution (hints and guiding questions, never the answer).
  4. Review — a wrap-up once the student answers correctly.

A judge model classifies each turn (attempted? correct?) before the tutor replies, so phase transitions are deterministic rather than inferred from prose. Wrong answers are meant to feed inferred misconceptions back into the student's knowledge profile — that write-back loop is a planned milestone and not implemented yet.

Objectives and goals

  • Never give away the answer. The tutor scaffolds and questions; it doesn't solve.
  • Fix prerequisites before the problem. A student missing foundational topics gets a mini-lesson first, so the main problem is tackled with the right footing.
  • Make mastery a derived, honest signal. Mastery is computed from attempt history (correct / attempted), never hand-set, and unassessed topics are treated as unknown rather than as gaps.
  • Keep the tutor brain testable in isolation. The core state machine and prompt logic have no direct DB or HTTP dependency, so tutoring behavior can be unit-tested with fakes.
  • Close the loop on mistakes (in progress). Wrong answers should eventually update an inferred-misconceptions profile that shapes future sessions.

Tech stack

  • Next.js 15 (App Router) + React 19
  • Supabase (Postgres + Auth, via @supabase/ssr)
  • @anthropic-ai/sdk — Claude Sonnet for tutoring, Claude Haiku for turn judging
  • shadcn/ui + Radix + Tailwind 4 + Recharts
  • Vitest for unit tests

Prerequisites

Installation

  1. Clone and install dependencies

    git clone <repo-url>cd math-mate
    npm install
  2. Configure environment variables

    Create a .env.local file in the project root:

    NEXT_PUBLIC_SUPABASE_URL=your-supabase-project-url
    NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
    ANTHROPIC_API_KEY=your-anthropic-api-key
  3. Set up the database

    Apply the SQL migrations in utils/supabase/migrations/ to your Supabase project, in numeric order (via the Supabase SQL editor or CLI). They set up the student/topic/mastery schema, the tutoring_sessions table, and row-level security (owner-scoped to student_id = auth.uid()).

  4. Run the dev server

    npm run dev

    Open http://localhost:3000.

Commands

npm run dev # Next.js dev server (localhost:3000)
npm run build # production build
npm run lint # next lint (eslint 9)
npm test# vitest run (all *.test.ts under app/ and lib/)
npm run test:watch # vitest watch mode

Run a single test file or filter by name:

npx vitest run app/tutor/stateMachine.test.ts
npx vitest run -t "resolves a gap on a correct answer"

Project structure

  • app/queries/ — typed Supabase query functions (masteries, weaknesses, sessions, problems).
  • app/tutor/ — the tutor brain: state machine, gap classification, system prompt builder, turn judge, and conversation orchestration. Pure logic with injected dependencies (no direct DB/HTTP), so it's unit-testable with fakes.
  • app/api/sessions/ — HTTP layer: session bootstrap/resume and the per-turn message endpoint (streamed as NDJSON).
  • utils/supabase/ — Supabase client setup and SQL migrations.
  • lib/historyCache.ts — ephemeral conversation-transcript cache, separate from the durable session row.
  • app/ (App Router pages) — dashboard, courses, login, and the tutoring UI.

See CLAUDE.md for a deeper architectural writeup.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Math Mate

An AI math-tutoring platform. Students work assignment problems through a Claude-powered tutor that checks prerequisite knowledge, resolves weak spots ("gaps") with a mini-lesson, then scaffolds the student through the problem itself — without ever handing over the answer.

Overview

Each tutoring session walks a fixed path:

  1. Intro — greet the student and set up the problem.
  2. Gap check — probe the topics the problem depends on. Any topic below the mastery threshold gets a short mini-lesson and a follow-up check before moving on.
  3. Solve — the problem is revealed and the tutor scaffolds the student toward a solution (hints and guiding questions, never the answer).
  4. Review — a wrap-up once the student answers correctly.

A judge model classifies each turn (attempted? correct?) before the tutor replies, so phase transitions are deterministic rather than inferred from prose. Wrong answers are meant to feed inferred misconceptions back into the student's knowledge profile — that write-back loop is a planned milestone and not implemented yet.

Objectives and goals

  • Never give away the answer. The tutor scaffolds and questions; it doesn't solve.
  • Fix prerequisites before the problem. A student missing foundational topics gets a mini-lesson first, so the main problem is tackled with the right footing.
  • Make mastery a derived, honest signal. Mastery is computed from attempt history (correct / attempted), never hand-set, and unassessed topics are treated as unknown rather than as gaps.
  • Keep the tutor brain testable in isolation. The core state machine and prompt logic have no direct DB or HTTP dependency, so tutoring behavior can be unit-tested with fakes.
  • Close the loop on mistakes (in progress). Wrong answers should eventually update an inferred-misconceptions profile that shapes future sessions.

Tech stack

  • Next.js 15 (App Router) + React 19
  • Supabase (Postgres + Auth, via @supabase/ssr)
  • @anthropic-ai/sdk — Claude Sonnet for tutoring, Claude Haiku for turn judging
  • shadcn/ui + Radix + Tailwind 4 + Recharts
  • Vitest for unit tests

Prerequisites

Installation

  1. Clone and install dependencies

    git clone <repo-url>cd math-mate
    npm install
  2. Configure environment variables

    Create a .env.local file in the project root:

    NEXT_PUBLIC_SUPABASE_URL=your-supabase-project-url
    NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
    ANTHROPIC_API_KEY=your-anthropic-api-key
  3. Set up the database

    Apply the SQL migrations in utils/supabase/migrations/ to your Supabase project, in numeric order (via the Supabase SQL editor or CLI). They set up the student/topic/mastery schema, the tutoring_sessions table, and row-level security (owner-scoped to student_id = auth.uid()).

  4. Run the dev server

    npm run dev

    Open http://localhost:3000.

Commands

npm run dev # Next.js dev server (localhost:3000)
npm run build # production build
npm run lint # next lint (eslint 9)
npm test# vitest run (all *.test.ts under app/ and lib/)
npm run test:watch # vitest watch mode

Run a single test file or filter by name:

npx vitest run app/tutor/stateMachine.test.ts
npx vitest run -t "resolves a gap on a correct answer"

Project structure

  • app/queries/ — typed Supabase query functions (masteries, weaknesses, sessions, problems).
  • app/tutor/ — the tutor brain: state machine, gap classification, system prompt builder, turn judge, and conversation orchestration. Pure logic with injected dependencies (no direct DB/HTTP), so it's unit-testable with fakes.
  • app/api/sessions/ — HTTP layer: session bootstrap/resume and the per-turn message endpoint (streamed as NDJSON).
  • utils/supabase/ — Supabase client setup and SQL migrations.
  • lib/historyCache.ts — ephemeral conversation-transcript cache, separate from the durable session row.
  • app/ (App Router pages) — dashboard, courses, login, and the tutoring UI.

See CLAUDE.md for a deeper architectural writeup.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Math Mate

An AI math-tutoring platform. Students work assignment problems through a Claude-powered tutor that checks prerequisite knowledge, resolves weak spots ("gaps") with a mini-lesson, then scaffolds the student through the problem itself — without ever handing over the answer.

Overview

Each tutoring session walks a fixed path:

  1. Intro — greet the student and set up the problem.
  2. Gap check — probe the topics the problem depends on. Any topic below the mastery threshold gets a short mini-lesson and a follow-up check before moving on.
  3. Solve — the problem is revealed and the tutor scaffolds the student toward a solution (hints and guiding questions, never the answer).
  4. Review — a wrap-up once the student answers correctly.

A judge model classifies each turn (attempted? correct?) before the tutor replies, so phase transitions are deterministic rather than inferred from prose. Wrong answers are meant to feed inferred misconceptions back into the student's knowledge profile — that write-back loop is a planned milestone and not implemented yet.

Objectives and goals

  • Never give away the answer. The tutor scaffolds and questions; it doesn't solve.
  • Fix prerequisites before the problem. A student missing foundational topics gets a mini-lesson first, so the main problem is tackled with the right footing.
  • Make mastery a derived, honest signal. Mastery is computed from attempt history (correct / attempted), never hand-set, and unassessed topics are treated as unknown rather than as gaps.
  • Keep the tutor brain testable in isolation. The core state machine and prompt logic have no direct DB or HTTP dependency, so tutoring behavior can be unit-tested with fakes.
  • Close the loop on mistakes (in progress). Wrong answers should eventually update an inferred-misconceptions profile that shapes future sessions.

Tech stack

  • Next.js 15 (App Router) + React 19
  • Supabase (Postgres + Auth, via @supabase/ssr)
  • @anthropic-ai/sdk — Claude Sonnet for tutoring, Claude Haiku for turn judging
  • shadcn/ui + Radix + Tailwind 4 + Recharts
  • Vitest for unit tests

Prerequisites

Installation

  1. Clone and install dependencies

    git clone <repo-url>cd math-mate
    npm install
  2. Configure environment variables

    Create a .env.local file in the project root:

    NEXT_PUBLIC_SUPABASE_URL=your-supabase-project-url
    NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
    ANTHROPIC_API_KEY=your-anthropic-api-key
  3. Set up the database

    Apply the SQL migrations in utils/supabase/migrations/ to your Supabase project, in numeric order (via the Supabase SQL editor or CLI). They set up the student/topic/mastery schema, the tutoring_sessions table, and row-level security (owner-scoped to student_id = auth.uid()).

  4. Run the dev server

    npm run dev

    Open http://localhost:3000.

Commands

npm run dev # Next.js dev server (localhost:3000)
npm run build # production build
npm run lint # next lint (eslint 9)
npm test# vitest run (all *.test.ts under app/ and lib/)
npm run test:watch # vitest watch mode

Run a single test file or filter by name:

npx vitest run app/tutor/stateMachine.test.ts
npx vitest run -t "resolves a gap on a correct answer"

Project structure

  • app/queries/ — typed Supabase query functions (masteries, weaknesses, sessions, problems).
  • app/tutor/ — the tutor brain: state machine, gap classification, system prompt builder, turn judge, and conversation orchestration. Pure logic with injected dependencies (no direct DB/HTTP), so it's unit-testable with fakes.
  • app/api/sessions/ — HTTP layer: session bootstrap/resume and the per-turn message endpoint (streamed as NDJSON).
  • utils/supabase/ — Supabase client setup and SQL migrations.
  • lib/historyCache.ts — ephemeral conversation-transcript cache, separate from the durable session row.
  • app/ (App Router pages) — dashboard, courses, login, and the tutoring UI.

See CLAUDE.md for a deeper architectural writeup.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Math Mate

An AI math-tutoring platform. Students work assignment problems through a Claude-powered tutor that checks prerequisite knowledge, resolves weak spots ("gaps") with a mini-lesson, then scaffolds the student through the problem itself — without ever handing over the answer.

Overview

Each tutoring session walks a fixed path:

  1. Intro — greet the student and set up the problem.
  2. Gap check — probe the topics the problem depends on. Any topic below the mastery threshold gets a short mini-lesson and a follow-up check before moving on.
  3. Solve — the problem is revealed and the tutor scaffolds the student toward a solution (hints and guiding questions, never the answer).
  4. Review — a wrap-up once the student answers correctly.

A judge model classifies each turn (attempted? correct?) before the tutor replies, so phase transitions are deterministic rather than inferred from prose. Wrong answers are meant to feed inferred misconceptions back into the student's knowledge profile — that write-back loop is a planned milestone and not implemented yet.

Objectives and goals

  • Never give away the answer. The tutor scaffolds and questions; it doesn't solve.
  • Fix prerequisites before the problem. A student missing foundational topics gets a mini-lesson first, so the main problem is tackled with the right footing.
  • Make mastery a derived, honest signal. Mastery is computed from attempt history (correct / attempted), never hand-set, and unassessed topics are treated as unknown rather than as gaps.
  • Keep the tutor brain testable in isolation. The core state machine and prompt logic have no direct DB or HTTP dependency, so tutoring behavior can be unit-tested with fakes.
  • Close the loop on mistakes (in progress). Wrong answers should eventually update an inferred-misconceptions profile that shapes future sessions.

Tech stack

  • Next.js 15 (App Router) + React 19
  • Supabase (Postgres + Auth, via @supabase/ssr)
  • @anthropic-ai/sdk — Claude Sonnet for tutoring, Claude Haiku for turn judging
  • shadcn/ui + Radix + Tailwind 4 + Recharts
  • Vitest for unit tests

Prerequisites

Installation

  1. Clone and install dependencies

    git clone <repo-url>cd math-mate
    npm install
  2. Configure environment variables

    Create a .env.local file in the project root:

    NEXT_PUBLIC_SUPABASE_URL=your-supabase-project-url
    NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
    ANTHROPIC_API_KEY=your-anthropic-api-key
  3. Set up the database

    Apply the SQL migrations in utils/supabase/migrations/ to your Supabase project, in numeric order (via the Supabase SQL editor or CLI). They set up the student/topic/mastery schema, the tutoring_sessions table, and row-level security (owner-scoped to student_id = auth.uid()).

  4. Run the dev server

    npm run dev

    Open http://localhost:3000.

Commands

npm run dev # Next.js dev server (localhost:3000)
npm run build # production build
npm run lint # next lint (eslint 9)
npm test# vitest run (all *.test.ts under app/ and lib/)
npm run test:watch # vitest watch mode

Run a single test file or filter by name:

npx vitest run app/tutor/stateMachine.test.ts
npx vitest run -t "resolves a gap on a correct answer"

Project structure

  • app/queries/ — typed Supabase query functions (masteries, weaknesses, sessions, problems).
  • app/tutor/ — the tutor brain: state machine, gap classification, system prompt builder, turn judge, and conversation orchestration. Pure logic with injected dependencies (no direct DB/HTTP), so it's unit-testable with fakes.
  • app/api/sessions/ — HTTP layer: session bootstrap/resume and the per-turn message endpoint (streamed as NDJSON).
  • utils/supabase/ — Supabase client setup and SQL migrations.
  • lib/historyCache.ts — ephemeral conversation-transcript cache, separate from the durable session row.
  • app/ (App Router pages) — dashboard, courses, login, and the tutoring UI.

See CLAUDE.md for a deeper architectural writeup.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Math Mate

An AI math-tutoring platform. Students work assignment problems through a Claude-powered tutor that checks prerequisite knowledge, resolves weak spots ("gaps") with a mini-lesson, then scaffolds the student through the problem itself — without ever handing over the answer.

Overview

Each tutoring session walks a fixed path:

  1. Intro — greet the student and set up the problem.
  2. Gap check — probe the topics the problem depends on. Any topic below the mastery threshold gets a short mini-lesson and a follow-up check before moving on.
  3. Solve — the problem is revealed and the tutor scaffolds the student toward a solution (hints and guiding questions, never the answer).
  4. Review — a wrap-up once the student answers correctly.

A judge model classifies each turn (attempted? correct?) before the tutor replies, so phase transitions are deterministic rather than inferred from prose. Wrong answers are meant to feed inferred misconceptions back into the student's knowledge profile — that write-back loop is a planned milestone and not implemented yet.

Objectives and goals

  • Never give away the answer. The tutor scaffolds and questions; it doesn't solve.
  • Fix prerequisites before the problem. A student missing foundational topics gets a mini-lesson first, so the main problem is tackled with the right footing.
  • Make mastery a derived, honest signal. Mastery is computed from attempt history (correct / attempted), never hand-set, and unassessed topics are treated as unknown rather than as gaps.
  • Keep the tutor brain testable in isolation. The core state machine and prompt logic have no direct DB or HTTP dependency, so tutoring behavior can be unit-tested with fakes.
  • Close the loop on mistakes (in progress). Wrong answers should eventually update an inferred-misconceptions profile that shapes future sessions.

Tech stack

  • Next.js 15 (App Router) + React 19
  • Supabase (Postgres + Auth, via @supabase/ssr)
  • @anthropic-ai/sdk — Claude Sonnet for tutoring, Claude Haiku for turn judging
  • shadcn/ui + Radix + Tailwind 4 + Recharts
  • Vitest for unit tests

Prerequisites

Installation

  1. Clone and install dependencies

    git clone <repo-url>cd math-mate
    npm install
  2. Configure environment variables

    Create a .env.local file in the project root:

    NEXT_PUBLIC_SUPABASE_URL=your-supabase-project-url
    NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
    ANTHROPIC_API_KEY=your-anthropic-api-key
  3. Set up the database

    Apply the SQL migrations in utils/supabase/migrations/ to your Supabase project, in numeric order (via the Supabase SQL editor or CLI). They set up the student/topic/mastery schema, the tutoring_sessions table, and row-level security (owner-scoped to student_id = auth.uid()).

  4. Run the dev server

    npm run dev

    Open http://localhost:3000.

Commands

npm run dev # Next.js dev server (localhost:3000)
npm run build # production build
npm run lint # next lint (eslint 9)
npm test# vitest run (all *.test.ts under app/ and lib/)
npm run test:watch # vitest watch mode

Run a single test file or filter by name:

npx vitest run app/tutor/stateMachine.test.ts
npx vitest run -t "resolves a gap on a correct answer"

Project structure

  • app/queries/ — typed Supabase query functions (masteries, weaknesses, sessions, problems).
  • app/tutor/ — the tutor brain: state machine, gap classification, system prompt builder, turn judge, and conversation orchestration. Pure logic with injected dependencies (no direct DB/HTTP), so it's unit-testable with fakes.
  • app/api/sessions/ — HTTP layer: session bootstrap/resume and the per-turn message endpoint (streamed as NDJSON).
  • utils/supabase/ — Supabase client setup and SQL migrations.
  • lib/historyCache.ts — ephemeral conversation-transcript cache, separate from the durable session row.
  • app/ (App Router pages) — dashboard, courses, login, and the tutoring UI.

See CLAUDE.md for a deeper architectural writeup.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Math Mate

An AI math-tutoring platform. Students work assignment problems through a Claude-powered tutor that checks prerequisite knowledge, resolves weak spots ("gaps") with a mini-lesson, then scaffolds the student through the problem itself — without ever handing over the answer.

Overview

Each tutoring session walks a fixed path:

  1. Intro — greet the student and set up the problem.
  2. Gap check — probe the topics the problem depends on. Any topic below the mastery threshold gets a short mini-lesson and a follow-up check before moving on.
  3. Solve — the problem is revealed and the tutor scaffolds the student toward a solution (hints and guiding questions, never the answer).
  4. Review — a wrap-up once the student answers correctly.

A judge model classifies each turn (attempted? correct?) before the tutor replies, so phase transitions are deterministic rather than inferred from prose. Wrong answers are meant to feed inferred misconceptions back into the student's knowledge profile — that write-back loop is a planned milestone and not implemented yet.

Objectives and goals

  • Never give away the answer. The tutor scaffolds and questions; it doesn't solve.
  • Fix prerequisites before the problem. A student missing foundational topics gets a mini-lesson first, so the main problem is tackled with the right footing.
  • Make mastery a derived, honest signal. Mastery is computed from attempt history (correct / attempted), never hand-set, and unassessed topics are treated as unknown rather than as gaps.
  • Keep the tutor brain testable in isolation. The core state machine and prompt logic have no direct DB or HTTP dependency, so tutoring behavior can be unit-tested with fakes.
  • Close the loop on mistakes (in progress). Wrong answers should eventually update an inferred-misconceptions profile that shapes future sessions.

Tech stack

  • Next.js 15 (App Router) + React 19
  • Supabase (Postgres + Auth, via @supabase/ssr)
  • @anthropic-ai/sdk — Claude Sonnet for tutoring, Claude Haiku for turn judging
  • shadcn/ui + Radix + Tailwind 4 + Recharts
  • Vitest for unit tests

Prerequisites

Installation

  1. Clone and install dependencies

    git clone <repo-url>cd math-mate
    npm install
  2. Configure environment variables

    Create a .env.local file in the project root:

    NEXT_PUBLIC_SUPABASE_URL=your-supabase-project-url
    NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
    ANTHROPIC_API_KEY=your-anthropic-api-key
  3. Set up the database

    Apply the SQL migrations in utils/supabase/migrations/ to your Supabase project, in numeric order (via the Supabase SQL editor or CLI). They set up the student/topic/mastery schema, the tutoring_sessions table, and row-level security (owner-scoped to student_id = auth.uid()).

  4. Run the dev server

    npm run dev

    Open http://localhost:3000.

Commands

npm run dev # Next.js dev server (localhost:3000)
npm run build # production build
npm run lint # next lint (eslint 9)
npm test# vitest run (all *.test.ts under app/ and lib/)
npm run test:watch # vitest watch mode

Run a single test file or filter by name:

npx vitest run app/tutor/stateMachine.test.ts
npx vitest run -t "resolves a gap on a correct answer"

Project structure

  • app/queries/ — typed Supabase query functions (masteries, weaknesses, sessions, problems).
  • app/tutor/ — the tutor brain: state machine, gap classification, system prompt builder, turn judge, and conversation orchestration. Pure logic with injected dependencies (no direct DB/HTTP), so it's unit-testable with fakes.
  • app/api/sessions/ — HTTP layer: session bootstrap/resume and the per-turn message endpoint (streamed as NDJSON).
  • utils/supabase/ — Supabase client setup and SQL migrations.
  • lib/historyCache.ts — ephemeral conversation-transcript cache, separate from the durable session row.
  • app/ (App Router pages) — dashboard, courses, login, and the tutoring UI.

See CLAUDE.md for a deeper architectural writeup.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Math Mate

An AI math-tutoring platform. Students work assignment problems through a Claude-powered tutor that checks prerequisite knowledge, resolves weak spots ("gaps") with a mini-lesson, then scaffolds the student through the problem itself — without ever handing over the answer.

Overview

Each tutoring session walks a fixed path:

  1. Intro — greet the student and set up the problem.
  2. Gap check — probe the topics the problem depends on. Any topic below the mastery threshold gets a short mini-lesson and a follow-up check before moving on.
  3. Solve — the problem is revealed and the tutor scaffolds the student toward a solution (hints and guiding questions, never the answer).
  4. Review — a wrap-up once the student answers correctly.

A judge model classifies each turn (attempted? correct?) before the tutor replies, so phase transitions are deterministic rather than inferred from prose. Wrong answers are meant to feed inferred misconceptions back into the student's knowledge profile — that write-back loop is a planned milestone and not implemented yet.

Objectives and goals

  • Never give away the answer. The tutor scaffolds and questions; it doesn't solve.
  • Fix prerequisites before the problem. A student missing foundational topics gets a mini-lesson first, so the main problem is tackled with the right footing.
  • Make mastery a derived, honest signal. Mastery is computed from attempt history (correct / attempted), never hand-set, and unassessed topics are treated as unknown rather than as gaps.
  • Keep the tutor brain testable in isolation. The core state machine and prompt logic have no direct DB or HTTP dependency, so tutoring behavior can be unit-tested with fakes.
  • Close the loop on mistakes (in progress). Wrong answers should eventually update an inferred-misconceptions profile that shapes future sessions.

Tech stack

  • Next.js 15 (App Router) + React 19
  • Supabase (Postgres + Auth, via @supabase/ssr)
  • @anthropic-ai/sdk — Claude Sonnet for tutoring, Claude Haiku for turn judging
  • shadcn/ui + Radix + Tailwind 4 + Recharts
  • Vitest for unit tests

Prerequisites

Installation

  1. Clone and install dependencies

    git clone <repo-url>cd math-mate
    npm install
  2. Configure environment variables

    Create a .env.local file in the project root:

    NEXT_PUBLIC_SUPABASE_URL=your-supabase-project-url
    NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
    ANTHROPIC_API_KEY=your-anthropic-api-key
  3. Set up the database

    Apply the SQL migrations in utils/supabase/migrations/ to your Supabase project, in numeric order (via the Supabase SQL editor or CLI). They set up the student/topic/mastery schema, the tutoring_sessions table, and row-level security (owner-scoped to student_id = auth.uid()).

  4. Run the dev server

    npm run dev

    Open http://localhost:3000.

Commands

npm run dev # Next.js dev server (localhost:3000)
npm run build # production build
npm run lint # next lint (eslint 9)
npm test# vitest run (all *.test.ts under app/ and lib/)
npm run test:watch # vitest watch mode

Run a single test file or filter by name:

npx vitest run app/tutor/stateMachine.test.ts
npx vitest run -t "resolves a gap on a correct answer"

Project structure

  • app/queries/ — typed Supabase query functions (masteries, weaknesses, sessions, problems).
  • app/tutor/ — the tutor brain: state machine, gap classification, system prompt builder, turn judge, and conversation orchestration. Pure logic with injected dependencies (no direct DB/HTTP), so it's unit-testable with fakes.
  • app/api/sessions/ — HTTP layer: session bootstrap/resume and the per-turn message endpoint (streamed as NDJSON).
  • utils/supabase/ — Supabase client setup and SQL migrations.
  • lib/historyCache.ts — ephemeral conversation-transcript cache, separate from the durable session row.
  • app/ (App Router pages) — dashboard, courses, login, and the tutoring UI.

See CLAUDE.md for a deeper architectural writeup.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages