A personal learning app that replaces Reddit scrolling with something that teaches. Scroll cards on agentic AI and LLM fundamentals, close it. No schedule, no streaks.
A Claude-powered educator agent decides what to teach from a knowledge graph, spaced repetition, and your engagement signals — what you read, skip, and how you score on challenges.
- How it works
- Architecture — the Vercel / Turso / Mac split
- The knowledge graph — storage, and what graph structure drives
- The educator agent & steering
- The evaluation engine — LLM judge + deterministic SM-2 state machine
- Adaptive learning
- Card types · Content
- Setup · Commands · Testing · Tech stack
- You scroll. A Reddit-style flat feed. Concept cards teach, connection cards link ideas, challenge cards test you. Answers are evaluated and your mastery updates.
- An agent curates. Claude (via the
claudeCLI + MCP tools) runs curation cycles against the graph and your patterns, with persistent memory across runs. - Spaced repetition is invisible. Concepts move
NEW → SEEN → CONNECTED → CHALLENGED → SOLID/GAPSon an SM-2 schedule. No review queue — the right things just show up.
Three locations, one database, no app-to-app coupling.
flowchart LR
subgraph Vercel["Vercel — always on"]
SPA["React SPA<br/>(static)"]
API["FastAPI<br/>(serverless)"]
end
subgraph Mac["Mac — intermittent"]
CUR["Curation agent"]
EVAL["Evaluation agent"]
MCP["MCP server<br/>(25 tools)"]
CUR --> MCP
EVAL --> MCP
end
subgraph Cloud["Turso — cloud SQLite"]
DB[("concepts · concept_edges<br/>cards · memory<br/>pending_evaluations")]
end
SPA --> API
API --> DB
MCP --> DB
- Frontend — React + TypeScript + Tailwind. Pure reader.
- Backend — Python FastAPI on Vercel serverless. Stateless over the database.
- Database — Turso (cloud SQLite), single source of truth; every side connects directly.
- Curation brain — the
claudeCLI on a Mac (when it's on), reaching the database through an MCP server of 25 tools.
Card generation is the only model-dependent step, so it runs in bursts while the reader stays instant. Offline, challenge answers queue in pending_evaluations and evaluate on the next run. In prod the database syncs to git after each run, versioning the learning state.
The curriculum is a directed graph of concepts, not a list — so the educator can reason about structure: dependencies, connections, centrality, thin spots.
Storage. Turso (SQLite) is the source of truth: concept rows (each with mastery state + SM-2 params) and edge rows (relationship, strength, test count, success rate). A NetworkX DiGraph is rebuilt from the rows each run as the in-memory analytical layer.
flowchart LR
A["tokenization"] -->|prerequisite| B["attention"]
B -->|prerequisite| C["KV cache"]
C -->|related| D["context windows"]
B -->|related| E["decoding"]
classDef solid fill:#bfe3c8,stroke:#5b8a72,color:#143;
classDef seen fill:#e7dcf2,stroke:#7c6f9b,color:#314;
class A,B solid;
class C,D,E seen;
What the graph drives — structure maps to concrete curation decisions:
| Graph query | Finds | Drives |
|---|---|---|
| unconnected pairs | two seen concepts with no/weak edge | a connection card linking them |
| prerequisite gaps | a seen concept whose prerequisite isn't mastered | teach the prerequisite first |
| weak subgraphs | a cluster with all-low-strength edges | reinforce that cluster |
| hub nodes | highest-degree concepts (central to many) | prioritize to SOLID — unlocks the most |
| shortest path | how two concepts connect | frame a connection card on the real bridge |
Edge strength isn't static: a challenge testing two linked concepts feeds back into that edge's strength and success rate, so the graph learns how well you understand relationships, not just nodes.
The educator is an autonomous agent — Claude as a claude -p subprocess, strict MCP toolset, long system prompt. Each run it inspects state through tools, decides what you need, and acts. The code launches it and reloads the graph after; what to teach is the agent's call.
Steering — the levers it pulls each run:
- Graph queries — unconnected pairs, prerequisite gaps, weak subgraphs, hubs.
- Learner analytics — difficulty calibration (70–80% target band), track engagement, metacognitive flags (skip-but-fail = overconfident; read-but-ace = underconfident), concepts-by-state, queue depth.
- Persistent memory —
curation-notesandlearner-journey, read first and written last, so runs compound instead of starting cold. - Vocabulary safety check — every term must map to a concept you've already reached; otherwise it's inline-defined in one sentence, or the card is deferred.
sequenceDiagram
participant Sched as Scheduler / CLI
participant Agent as Educator (Claude + MCP)
participant DB as Turso
Sched->>Agent: run curation cycle
Agent->>DB: read_memory(curation-notes, learner-journey)
Agent->>DB: get_pending_evaluations()
Note over Agent,DB: evaluate queued answers first
Agent->>DB: explore state — profile, concepts-by-state,<br/>difficulty calibration, engagement, flags
Agent->>DB: graph queries — unconnected pairs,<br/>prerequisite gaps, weak subgraphs, hubs
Agent->>Agent: vocabulary safety check per card
Agent->>DB: create_card() × N (interleaved across tracks)
Agent->>DB: write_memory(curation-notes)
Agent->>Sched: done → graph reloaded
Pedagogy lives in the system prompt, grounded in learning science (Mayer, Sweller, Bjork): interleave tracks every batch, hold 70–80% challenge success, escalate question depth what → why → how would you redesign, and grant progressive trust as SOLID concepts accumulate (early cards define everything; later cards reference freely).
Two halves: a non-deterministic judge scores understanding, a deterministic state machine sets the schedule. The model never touches the spaced-rep math.
Judge — LLM + tools. On a free-form answer, the agent looks up each tested concept's state, your challenge history, and its own notes, then returns a rubric:
score · correct_points · missed_points · misconceptions · per-concept concept_scores · gaps · reasoning.
Feedback is required to be specific, e.g. "correctly identified KV-cache growth causes attention dilution; missed that Flash Attention mitigates it by computing attention in blocks." No vague praise.
State machine — SM-2 variant. Scores feed pure transitions:
stateDiagram-v2
[*] --> NEW
NEW --> SEEN: concept shown
SEEN --> CONNECTED: linked via a connection card
CONNECTED --> CHALLENGED: challenge attempted
CHALLENGED --> SOLID: score ≥ 0.7
CHALLENGED --> GAPS: score < 0.7
GAPS --> CHALLENGED: re-challenged
SOLID --> SOLID: passes review (interval × ease)
SOLID --> GAPS: fails a review
SOLID --> CONNECTED: 6+ weeks overdue (decay)
- SEEN → 2-day interval; CONNECTED → 5-day.
- Challenge
≥ 0.7→ SOLID (14-day, ease +0.1);< 0.7→ GAPS (3-day, ease −0.15). - SOLID pass → interval × ease (cap 90d), extra ease bump if
≥ 0.8; SOLID fail → GAPS. - Ease clamped to
[1.3, 3.0]. SOLID left 6+ weeks overdue decays to CONNECTED. A new connection stretches the interval ×1.15.
flowchart TD
S["Learner submits answer"] --> Q{Mac online?}
Q -- "no" --> P["queue in pending_evaluations"]
P --> R["next curation run picks it up"]
Q -- "yes" --> E
R --> E["Evaluation agent (Claude + MCP)"]
E --> L["look up concept context + history"]
L --> J["judge → rubric + scores"]
J --> M["SM-2 state machine updates mastery"]
M --> W["write_memory(learner-journey)"]
W --> F["feedback to learner"]
- Difficulty calibration — holds challenge success at 70–80%.
- Track engagement — bridges skipped tracks to engaged ones via connection cards.
- Metacognitive calibration — corrects overconfidence (skip but fail) and underconfidence (read but ace).
- Elaborative interrogation — question depth per concept:
what → why → redesign. - Skip analysis — reclassifies a skip once a later challenge reveals whether it was justified.
| Type | What it does |
|---|---|
| Concept | Teaches a new idea. Whiteboard-style, technical depth. |
| Connection | Links two seen concepts — why A changes how you think about B. |
| Challenge | Realistic scenario, free-form answer, evaluated by Claude. |
| Micro-challenge | A code snippet and a short question. |
| Build | A hands-on project tied to recent learning. |
5 tracks, ~140 concepts:
| Track | Topics |
|---|---|
| LLM Internals | Tokenization, attention, decoding, context windows, training |
| RAG & Retrieval | Embeddings, vector search, chunking, reranking, advanced RAG |
| Agent Frameworks | Agent loops, tool use, LangGraph, multi-agent orchestration |
| Infra & Ecosystem | Observability, durable execution, inference providers, dev tools |
| Evaluation & Research | Benchmarks, evals, prompt engineering, agent testing, research methods |
Track 5 is cross-cutting — its concepts often have prerequisites in other tracks, which the prerequisite-gap check respects.
Prerequisites: Python 3.12+, Node 20+, the claude CLI (authenticated), a Turso account.
git clone https://github.com/tirthajyoti-ghosh/the-feed.git
cd the-feed
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
pip install libsql-experimental # local Turso embedded replica
cd frontend && pnpm install && cd ..
cp .env.example .env # add Turso URL + auth token
make devTurso:
turso auth login
turso db create the-feed
turso db show the-feed --url # → TURSO_DB_URL
turso db tokens create the-feed # → TURSO_AUTH_TOKENVercel: vercel --prod, then set TURSO_DB_URL, TURSO_AUTH_TOKEN, CLOUD_MODE=true, FEED_ENV=prod.
| Command | What |
|---|---|
make dev |
Backend (dev db, reload) + frontend dev server |
make prod |
Build frontend + run backend (prod) |
make curate |
Trigger a curation run |
make test-unit |
Unit tests (~106, ~3s) |
make test-integration |
Integration tests (real Claude, ~3min) |
make feed / make progress / make status |
Fetch cards / check progress / check curation |
| Tier | Command | Tests | Covers |
|---|---|---|---|
| Unit | make test-unit |
106 | Database, graph, SM-2, tools, API |
| E2e core | ./scripts/e2e.sh |
23 | Full API flow against test db |
| E2e scenarios | ./scripts/e2e_scenarios.sh |
20 | Lifecycle, mastery transitions, memory, queue |
| Integration | make test-integration |
2 | Real Claude curation + evaluation |
| E2e + Claude | ./scripts/e2e.sh --with-claude |
28 | Core flow + live challenge submit |
Backend — Python, FastAPI, SQLite (Turso), NetworkX, APScheduler
Frontend — React 18, TypeScript, Vite, Tailwind, framer-motion, react-markdown
AI — Claude via the claude CLI with a strict MCP toolset; SM-2 spaced repetition
Infra — Vercel (frontend + serverless API), Turso (cloud SQLite)
MIT