Install
openclaw skills install normieclaw-language-tutor-proDuolingo taught you how to say 'the cat drinks milk' for the 500th time. You still can't order dinner in Spanish. Language Tutor Pro skips the gamification a...
openclaw skills install normieclaw-language-tutor-proPersistent, conversation-driven language learning with adaptive memory. No gamification. No flashcard drills. Just real conversation practice with a tutor that remembers everything.
Use this skill when the user says any of:
Do NOT use this skill for: translation requests (use a dictionary/translator), language identification, or one-off vocabulary lookups unrelated to active learning.
Language Tutor Pro turns the agent into a private language tutor with persistent memory. It tracks the learner's strengths, weaknesses, vocabulary, grammar mastery, and conversation history across every session. The tutor adapts difficulty in real time, corrects errors in context, and weaves spaced repetition into natural conversation — not disconnected drills.
Spanish, French, German, Italian, Portuguese, Japanese, Mandarin Chinese, Korean.
All progress is tracked against the Common European Framework of Reference (CEFR):
All learner data is stored in the skill's data/ directory. The setup script creates this structure.
data/learner-profile.json{
"native_language": "English",
"target_languages": [
{
"language": "Spanish",
"current_level": "B1",
"started": "2026-03-01",
"goals": ["conversational fluency", "travel preparation"],
"focus_areas": ["subjunctive mood", "colloquial expressions"],
"session_preferences": {
"default_duration_minutes": 20,
"error_correction": "inline",
"formality": "informal"
}
}
],
"interests": ["cooking", "travel", "technology", "music"],
"weak_spots": [],
"total_sessions": 0,
"current_streak_days": 0,
"longest_streak_days": 0,
"last_session_date": null
}
data/vocabulary.jsonlOne JSON object per line. Each entry tracks a word/phrase through spaced repetition.
{"word":"conseguir","translation":"to get/obtain","language":"Spanish","context":"Necesito conseguir los boletos antes del viernes.","level":"B1","added":"2026-03-05","next_review":"2026-03-08","interval_days":3,"ease_factor":2.5,"correct_streak":2,"tags":["verb","irregular"]}
{"word":"sin embargo","translation":"however/nevertheless","language":"Spanish","context":"El restaurante estaba lleno; sin embargo, encontramos una mesa.","level":"B1","added":"2026-03-05","next_review":"2026-03-06","interval_days":1,"ease_factor":2.1,"correct_streak":0,"tags":["conjunction","formal"]}
SRS Fields:
next_review: ISO date when word is due for reviewinterval_days: Current interval (starts at 1, grows on success)ease_factor: SM-2 algorithm ease factor (starts at 2.5, adjusts per recall quality)correct_streak: Consecutive correct recalls (resets to 0 on failure)data/grammar.jsonl{"rule":"ser_vs_estar","language":"Spanish","level":"A2","status":"learning","examples_seen":8,"errors":3,"last_error":"2026-03-04","last_practiced":"2026-03-05","notes":"Confuses estar with ser for temporary states. Reviewed with location examples."}
{"rule":"subjunctive_wishes","language":"Spanish","level":"B1","status":"introduced","examples_seen":2,"errors":1,"last_error":"2026-03-05","last_practiced":"2026-03-05","notes":"First exposure. Used quiero que + subjunctive. Got it wrong with esperar que."}
Status progression: introduced → learning → practiced → mastered
data/sessions.jsonl{"id":"s_20260305_1","date":"2026-03-05","language":"Spanish","type":"conversation","duration_minutes":18,"topic":"weekend plans","level":"B1","new_vocab":4,"errors_corrected":3,"grammar_points":["subjunctive_wishes","preterite_vs_imperfect"],"notes":"Good fluency on familiar topics. Struggled with subjunctive after esperar. Introduced 4 new food-related verbs."}
data/conversations/Full conversation transcripts stored as markdown files: data/conversations/YYYY-MM-DD-{session_id}.md
Trigger: "Let's practice [language]", "free conversation", "let's chat in [language]"
Procedure:
data/learner-profile.json for current level, interests, and weak spots.data/vocabulary.jsonl for words due for review (where next_review <= today).data/grammar.jsonl for grammar rules in learning or practiced status.Level-Appropriate Conversation Guidelines:
| Level | Sentence Complexity | Vocab Range | Topics |
|---|---|---|---|
| A1 | Simple present, basic questions | ~500 most common | Self, family, daily routine, weather |
| A2 | Past tense, basic future, comparisons | ~1000 | Shopping, directions, hobbies, food |
| B1 | Multiple tenses, opinions, conditionals | ~2000 | Travel, work, current events, culture |
| B2 | Complex clauses, idioms, nuance | ~4000 | Abstract topics, debates, professional |
| C1 | Native-speed, implicit meaning, humor | ~8000 | Any topic, nuanced discussion |
| C2 | Full native register including slang | ~15000+ | Any topic at native complexity |
Trigger: "Teach me [grammar topic]", "lesson on [topic]", "I want to learn [grammar point]"
Procedure:
data/grammar.jsonl — has the learner encountered this before?data/grammar.jsonl with the session's results.Grammar points by level (examples):
Trigger: "Vocab review", "review my words", "spaced repetition session", or run scripts/vocab-review.sh
Procedure:
data/vocabulary.jsonl and filter entries where next_review <= today.ease_factor (hardest words first).context to test genuine recall.
c. After the learner responds:
interval_days = interval_days * ease_factor. Bump ease_factor by 0.1 (max 3.0). Increment correct_streak.interval_days to 1. Decrease ease_factor by 0.2 (min 1.3). Reset correct_streak to 0. Show the correct answer in a new example sentence.data/vocabulary.jsonl with new intervals and review dates.SRS Interval Schedule (SM-2 based):
| Review # | Interval (ease=2.5) |
|---|---|
| 1st correct | 1 day |
| 2nd correct | 3 days |
| 3rd correct | 7 days |
| 4th correct | 18 days |
| 5th correct | 45 days |
| 6th correct | 112 days |
Trigger: "Practice ordering food", "job interview in [language]", "situation: [scenario]", "role play: [scenario]"
Procedure:
Built-in Scenarios by Level:
A1-A2:
B1-B2:
C1-C2:
These rules govern ALL conversation interactions regardless of session type.
The learner may respond in whatever mix they're comfortable with. Never shame them for using their native language. Gently encourage more target language use as confidence builds.
Two modes, configurable in the learner profile (error_correction field):
Inline (default): Correct errors as they occur within the conversation flow.
Format:
[Target language response continuing the conversation]
📝 Quick note: You said "[error]" — it should be "[correction]" because [brief rule].
Example: [one correct example sentence]
[Continue conversation naturally]
Batch: Collect errors and present them at the end of the session.
Format (end of session):
📝 Session Notes — [X] corrections:
1. You said: "[error]" → "[correction]"
Rule: [explanation]
2. You said: "[error]" → "[correction]"
Rule: [explanation]
Correction Priority: Only correct errors that are:
Let minor errors slide if they don't impede meaning, especially at lower levels. Overcorrection kills confidence.
When introducing a new word in conversation:
data/vocabulary.jsonl with the context sentence, initial interval of 1 day, and ease factor of 2.5.Target new words per session:
After every 3-5 exchanges, assess:
Signals to increase difficulty:
Signals to decrease difficulty:
Weave cultural notes into conversation naturally:
Never lecture on culture. Drop it in as a one-line aside:
💡 Cultural note: In Spain, lunch (la comida) is usually 2-3 PM — much later than in the US!
When the learner makes a grammar error during conversation:
Classify the error:
Use the inline or batch format from Section 4.2. Always:
data/grammar.jsonl — increment errors count, update last_error date.practiced.mastered.For each vocabulary item or grammar rule:
On correct recall:
if correct_streak == 0: interval = 1
elif correct_streak == 1: interval = 3
else: interval = round(previous_interval * ease_factor)
ease_factor = min(ease_factor + 0.1, 3.0)
correct_streak += 1
On incorrect recall:
interval = 1
ease_factor = max(ease_factor - 0.2, 1.3)
correct_streak = 0
next_review = today + interval_days
The SRS system feeds INTO conversation, not alongside it:
Example: If "conseguir" (to obtain) is due for review and the topic is weekend plans:
Agent: "¿Pudiste ___ las entradas para el concierto?" (Were you able to ___ the tickets for the concert?)
If the learner uses it correctly → mark as reviewed, extend interval. If not → provide it naturally and mark as failed, reset interval.
When the learner requests a dedicated review (or vocab-review.sh triggers one):
next_review <= todayAfter EVERY session (regardless of type), the agent must:
data/vocabulary.jsonl. Update reviewed words with new intervals.data/grammar.jsonl with errors, practice counts, status changes.data/sessions.jsonl.data/conversations/YYYY-MM-DD-{id}.md.last_session_date, increment total_sessions, update streak, refresh weak_spots array.Present to the learner:
📊 Session Summary
━━━━━━━━━━━━━━━━
⏱ Duration: [X] minutes
🗣 Type: [conversation/lesson/review/situation]
📝 Errors corrected: [X]
📚 New vocabulary: [X] words
🔤 Grammar points: [list]
🔥 Streak: [X] days
💪 Strong areas: [what went well]
🎯 Focus for next time: [specific weak point]
After the session, update the weak_spots array in the learner profile:
{
"weak_spots": [
{
"type": "grammar",
"rule": "subjunctive_wishes",
"language": "Spanish",
"error_rate": 0.6,
"sessions_since_intro": 3,
"priority": "high"
},
{
"type": "vocabulary",
"category": "food_verbs",
"language": "Spanish",
"retention_rate": 0.45,
"priority": "medium"
}
]
}
Priority is calculated:
Reassess the learner's level every 10 sessions by evaluating:
Level-up criteria (all must be met):
Level-down signals (any one triggers review):
Present level assessments diplomatically. Level changes are suggestions, and the learner can override.
For dashboard integration, scripts/export-progress.sh generates data/dashboard-export.json:
{
"exported_at": "2026-03-11T10:00:00Z",
"learner": {
"languages": [
{
"language": "Spanish",
"level": "B1",
"vocabulary_total": 847,
"vocabulary_mastered": 312,
"vocabulary_active": 535,
"grammar_rules_total": 24,
"grammar_mastered": 8,
"grammar_learning": 16,
"total_sessions": 42,
"total_minutes": 756,
"current_streak": 12,
"longest_streak": 23,
"avg_accuracy": 0.74,
"last_session": "2026-03-10"
}
]
},
"recent_sessions": [],
"vocabulary_growth": [],
"error_trends": []
}
When a learner uses Language Tutor Pro for the first time:
data/learner-profile.json exists and has been configured.data/learner-profile.json.Language Tutor Pro exports data for the NormieClaw dashboard via dashboard-kit/manifest.json.
Tables:
lt_sessions — session log with type, duration, language, errors, new vocab countlt_vocabulary — full vocabulary ledger with SRS statelt_grammar — grammar tracker with status and error rateslt_progress — daily snapshots of aggregate metrics per languageRoute: /language-tutor — renders progress charts, vocabulary growth, grammar mastery, session history, and weak spot analysis.
See dashboard-kit/DASHBOARD-SPEC.md for full integration details.
| Command | Action |
|---|---|
| "Practice [language]" | Start free conversation session |
| "Teach me [grammar topic]" | Start guided lesson |
| "Vocab review" | Start spaced repetition session |
| "Situation: [scenario]" | Start role-play practice |
| "My progress" / "Stats" | Show progress summary |
| "Change level to [level]" | Override CEFR level |
| "Add language: [language]" | Add a new target language |
| "Export progress" | Run export-progress.sh |
| "Switch to [language]" | Change active practice language |
| "End session" | Trigger post-session protocol |