Skip to content
← back to writing

AI / LLM Ops

Building an AI Language Tutor That Actually Works: 5 Modes, Spaced Repetition, and Cron-Driven Practice

How I replaced Duolingo with a custom AI tutor that adapts to my level, remembers what I struggle with, and bugs me at random times throughout the day.

I've been learning Spanish for a while now. A2, creeping toward B1 — travel-ready, not yet conversation-fluent. Like many developers, I tried the usual apps: Duolingo, Anki, Memrise. They all had the same problem: rigidity. Fixed lesson paths, generic vocabulary, no real conversation practice, and zero awareness of what I specifically struggle with.

So I built my own.

It's a skill for Hermes Agent — an AI assistant that runs on my Raspberry Pi and talks to me through WhatsApp. The tutor combines CEFR-based adaptive learning, SM-2 spaced repetition, grammar mastery tracking, and a cron-driven scheduler that randomly delivers practice throughout the day. Here's how it works.

The architecture: 5 modes, one skill

The tutor operates in five distinct modes, each triggered by natural language:

Assess “Schätze mein Spanisch ein”
Adaptive placement test — 10–15 questions across vocabulary, grammar and comprehension.
Learn “Neue Lektion”
15–20 min session: warmup → 6–8 new words → grammar concept → mini-dialogue.
Review “Wiederholung”
SM-2 spaced repetition of due vocabulary, with AI-assigned quality scoring.
Converse “Lass uns Spanisch reden”
8–12 exchange roleplay across 8 travel scenarios (restaurant, hotel, doctor…).
Track “Wie steht's um mein Spanisch?”
Progress dashboard — stats, streaks, skill balance and data-driven recommendations.

All state is local — four JSON files under ~/.hermes/language-data/spanisch/:

spanisch/
├── profile.json      # CEFR level, grammar mastery matrix, learning goals
├── vocab.json        # All words with SM-2 intervals, error counts, mastery scores
├── sessions.json     # Full session log: mode, duration, topics, notes
└── progress.json     # Aggregated stats, streaks, skill balance

No cloud. No subscription. No lock-in. Just JSON.

SM-2: why flashcards alone don't cut it

The spaced-repetition system is SM-2 — the same algorithm behind Anki, but fully wired into the tutor's decision-making. Every word carries its schedule:

"sm2": {
  "interval": 6,
  "repetitions": 2,
  "easiness": 2.3,
  "next_review": "2026-07-13"
},
"mastery": 2

The key difference from Anki: the AI scores you, not you scoring yourself. When you translate a sentence in Review mode, the tutor evaluates your answer and assigns a quality of 0–5. That kills the “I kind of knew it, let's call it a 4” inflation that makes most self-scored SRS ineffective. Quality 1–2 triggers a reset (interval → 1 day); quality 3+ advances the interval. The easiness factor adapts per word, so your personal difficult words get more frequent review automatically.

Problem-word tracking: study smarter, not more

Not every new word counts as “learned.” The system tracks four states per word:

Problem words get mandatory repetition in every subsequent session until they reach learned status — capped at 3 per session to avoid frustration. Your study time focuses on exactly what you're getting wrong, not re-drilling words you already know.

Grammar mastery: tracking concepts, not just words

Vocabulary is easy to track. Grammar is messier. The tutor maintains a grammar mastery matrix in profile.json:

"grammar_mastery": {
  "ser_vs_estar":             {"mastery": 0.6,  "total_errors": 4, "last_error": "2026-07-03"},
  "por_vs_para":              {"mastery": 0.2,  "total_errors": 8, "last_error": "2026-07-06"},
  "indefinido_vs_imperfecto": {"mastery": 0.0,  "total_errors": 0, "last_error": null},
  "pronombres_objeto":        {"mastery": 0.35, "total_errors": 6, "last_error": "2026-07-05"}
}

Every grammar error is classified into one of these concepts. Mastery drops by 0.1 per error and rises by 0.05 per session with correct usage. The two weakest concepts get priority in every Learn and Review session — anything below 0.4 mastery even takes precedence over new grammar topics.

This creates a natural progression. The Spanish grammar hierarchy has 10 levels (presente → pretérito perfecto → indefinido → imperfecto → futuro → subjuntivo → condicional → imperativo → pronombres → por/para), and you don't advance until the current concept's mastery is solid.

The Korrektur-Protokoll: every error is a lesson

After every mistake — in any mode — the tutor follows a strict five-step protocol:

  1. 1 Show the correction — the complete, correct sentence.
  2. 2 Name the error — in one sentence: "You used ser instead of estar."
  3. 3 Explain the rule — 1–2 sentences in German, crisp and precise.
  4. 4 Track it — update grammar_mastery and/or vocab error_count.
  5. 5 Immediate re-practice — one similar sentence on the same concept before moving on.

Every error becomes a structured micro-lesson instead of a fleeting “oops, wrong.” The data persists, so the system actively hunts for your weak spots in future sessions.

Converse mode: actually speaking (without the pressure)

Converse mode is where it gets genuinely useful for travel prep. Eight scenarios — restaurant, hotel, directions, shopping, train station, doctor, making friends, phone calls. The AI plays the other role (waiter, receptionist, passerby) and adapts language complexity to your CEFR level.

This mirrors how real language acquisition works: you need to produce language under mild pressure, not just recognize it in a multiple-choice quiz.

The cron scheduler: practice finds you

This is my favorite part. A Python script runs every hour from 9:00 to 22:00 via cron. It randomly selects ~3 times per day and delivers practice straight to my WhatsApp.

The recent innovation is dual-mode randomization. Each delivery randomly picks between:

There's also a variety enforcement rule: if the first two deliveries of the day were the same mode, the third is forced to the other. No three translation-only days.

The scheduler tracks everything in daily_practice.json:

{
  "date": "2026-07-07",
  "deliveries": [
    {"hour": "10:00", "mode": "translation"},
    {"hour": "15:00", "mode": "conversation"}
  ],
  "total_deliveries": 87
}

The probability is needed / remaining_hours — so early in the day there's a low chance of delivery, but if it's 20:00 and you still need all three, they get forced through. Practice distributes naturally across the day without being predictable.

Why this works better than apps

  1. 1 Adaptive to you, not a cohort. The system knows your exact error history, weak grammar concepts and problem words. Every session is personalized.
  2. 2 Real conversation practice. Multiple-choice and fill-in-the-blank don't teach you to produce language. Roleplaying with corrective feedback does.
  3. 3 It comes to you. No app to open. Practice arrives on WhatsApp at random intervals — no decision fatigue, no “I'll do it later.”
  4. 4 Full data ownership. All progress, vocabulary and session history live in plain JSON on your own machine. Exportable, backup-able, never vendor-locked.
  5. 5 Extensible. Want a new language? Copy the template, run Assess mode, and you're set up in 10 minutes.

The stack

Agent
Hermes Agent on a Raspberry Pi 5
Model
DeepSeek V4 Pro via OpenRouter
Delivery
WhatsApp (native integration)
Scheduling
System cron + Python scheduler
Storage
Local JSON with SM-2 data
Cost
~$3–5/month in API credits

Open source

The language tutor skill and scheduler script are open source under the MIT license: github.com/d1gl3/hermes-skills (see skills/language-tutor/). The dual-mode conversation feature was just merged — the scheduler now randomly chooses between translation exercises and mini roleplays, with a variety guarantee so you never get three of the same in a row.

¿Quieres probarlo? Clone the repo, set up Hermes Agent, and run hermes cron create with the scheduler script. In 10 minutes you'll have an AI tutor that knows your weaknesses better than you do.