Full Next.js App Router application with: - AI-graded lesson checkpoints (BKT/Elo mastery tracking) - Auth.js v5: credentials, Google, GitHub, generic OIDC - Anonymous-session-first with migrate-on-signin - Admin panel: users, blueprints, reports, site settings - Password reset + email verification (nodemailer/SMTP) - Site config: require_auth + signups_enabled flags - server-only guards on all DB/generation/verification modules - PostgreSQL 16 + pgvector, Redis cache, Drizzle ORM - 271 unit tests (Vitest), golden-eval harness, Playwright e2e stubs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Curio
A curiosity-led mastery tutor. Learner states intent → gets a bounded ~10-minute Lesson → AI diagnoses free-text responses against pre-verified rubrics and a per-concept misconception library → gates advancement on demonstrated mastery.
The moat is diagnosis: inferring what a learner misunderstands and why, not content generation.
Prerequisites
- Node.js 20+, pnpm 9+
- Docker (for Postgres + Redis)
- API keys: Anthropic (generator) + OpenAI (grader) at minimum
Quick start
# 1. Clone and install
pnpm install
# 2. Copy env and fill in API keys
cp .env.example .env.local
# Required: ANTHROPIC_API_KEY, OPENAI_API_KEY
# Optional: LANGFUSE_* for tracing, UPSTASH_* for rate limiting
# 3. Start Postgres (port 5433) + Redis (port 6379)
docker compose up -d
# 4. Run migrations
pnpm drizzle-kit generate && pnpm drizzle-kit migrate
# 5. Seed the JS Closures demo topic
pnpm seed
# 6. Start dev server
pnpm dev
# → http://localhost:3000
Environment variables
All vars documented in .env.example. Key ones:
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
✓ | postgresql://curio:curio@localhost:5433/curio (docker default) |
REDIS_URL |
✓ | redis://localhost:6379 (docker default) |
ANTHROPIC_API_KEY |
✓ | Generator model (default: claude-sonnet-4-6) |
OPENAI_API_KEY |
✓ | Grader + embeddings (default: gpt-4o-mini, text-embedding-3-small) |
LANGFUSE_SECRET_KEY |
— | LLM call tracing; logs to console when absent |
SESSION_TOKEN_BUDGET |
— | Per-session output token cap (default: 50000) |
CONTENT_SAFETY_MODE |
— | open / controlled (default) / enterprise-safe |
Provider-agnostic: generator, grader, and embeddings are each independently configurable. Supported: Anthropic, OpenAI, Google Gemini, Mistral, Cohere, Groq, xAI, AWS Bedrock, Azure OpenAI, OpenRouter, Ollama (fully local, no API keys). See .env.example for all options.
Commands
pnpm dev # Next.js dev server
pnpm build # Production build
pnpm test # Vitest unit tests (LLM mocked — no API keys needed)
pnpm test:watch # Watch mode
pnpm test:e2e # Playwright end-to-end
pnpm test:golden # Real-model grading eval (CI-gated, needs API keys)
pnpm test:golden:misconceptions # Misconception quality eval
pnpm test:golden:content # Content verification eval
pnpm workers # BullMQ background workers (lesson generation, blueprint promotion)
pnpm seed # Seed JS Closures demo corpus (idempotent)
pnpm seed -- --force # Drop and re-seed
pnpm lint # ESLint
pnpm format # Prettier
pnpm drizzle-kit generate # Generate migration from schema changes
pnpm drizzle-kit migrate # Apply pending migrations
pnpm drizzle-kit studio # Drizzle Studio (DB browser)
Architecture
Request path (fast, no generation):
GET /api/lessons → Redis cache → Postgres → LessonResponse
Generation path (background, async):
POST /api/lessons cold-start → enqueue BullMQ job → generate-lesson-job
Blueprint promotion (T2 verify + variants) → promote-blueprint-job
Grading (per response):
POST /api/grade → cheapGrader (rubric match) → escalate to strong grader if uncertain/novel
→ persist response + grade → update mastery (BKT) → auto-flag collective failures
LLM:
All calls via src/lib/llm/client.ts — never call providers directly
Prompts in src/lib/llm/prompts/ (versioned registry)
Contracts are Zod schemas in src/schemas/ (shared API ↔ LLM ↔ UI)
See docs/curio-specification.md for full product + architecture reference.
Repo structure
src/
app/ # Next.js App Router: pages + api/ route handlers
components/ # UI components (LessonReader, GradeDisplay, …)
lib/
llm/ # LLM client + versioned prompt registry
generation/ # RAG-grounded content generation
verification/ # Content cascade (T0–T2) + response grader
memory/ # Mastery (BKT/Elo) + spaced repetition
intent/ # Intent normalization + blueprint lookup
db/ # Drizzle schema, queries, migrations, seed data
cache/ # Redis lesson buffer
jobs/ # BullMQ queue helpers
observability/ # Langfuse / OpenTelemetry tracing
schemas/ # Zod contracts (shared)
styles/ # Design tokens (CSS custom properties)
jobs/ # BullMQ workers (generation, promotion)
tests/golden/ # Frozen eval sets: grading accuracy + content verification
e2e/ # Playwright
docs/
curio-specification.md
Running workers
Background jobs handle lesson generation and blueprint promotion (T2 verification + difficulty variant generation). Run separately from the web server:
pnpm workers
Workers require Postgres, Redis, and API keys. In production, run as a separate process or container.
Tech stack
Next.js 15 (App Router) · TypeScript · Vercel AI SDK · Zod · PostgreSQL 16 + pgvector · Drizzle ORM · Redis · BullMQ · Tailwind · Vitest · Playwright