From fluent
Atomically updates all 6 Fluent learner databases at session end via a single JSON payload. Called by practice skills (fluent-writing, fluent-vocab, etc.) to persist errors, review results, new vocabulary, and session metadata.
How this skill is triggered — by the user, by Claude, or both
Slash command
/fluent:fluent-db-updaterThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Every practice skill ends with a DB update. Instead of hand-editing 6 JSON files (error-prone, racy, easy to desync), pipe one JSON report to `update-db.py`. The script runs pre-write backups, validates the payload, applies all changes atomically via `.tmp + fsync + rename`, and rebuilds the spaced-repetition queue.
Every practice skill ends with a DB update. Instead of hand-editing 6 JSON files (error-prone, racy, easy to desync), pipe one JSON report to update-db.py. The script runs pre-write backups, validates the payload, applies all changes atomically via .tmp + fsync + rename, and rebuilds the spaced-repetition queue.
Load this skill whenever the tutor:
total_sessions, current_streak_days, or total_study_minutes.Skip this skill for read-only operations (use the fluent-progress skill or read-db.py directly) and during session setup (use fluent-setup skill instead — update-db.py is for session deltas, not bootstrap).
Run from the repo root:
python3 "${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR:-.}}/.claude/hooks/update-db.py" <<'EOF'
{ ...payload... }
EOF
Exit codes: 0 success, 1 validation error, 2 I/O error.
Required fields
session_id — string, convention session-NNN. Use computed.next_session_id from read-db.py.date — YYYY-MM-DD.Optional fields — omit to skip. Full canonical example (copy-paste this and fill in):
${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR:-.}}/.claude/references/db-updater-payload.example.json
Key blocks the example covers: skill_scores, errors[], new_vocabulary[], review_results[], topics_covered, breakthroughs, focus_next_session, session_notes, achievements_earned, milestones.
errors[] — one entry per distinct mistake this session. Collapse duplicates (same pattern_id) before sending; frequency is bumped by the script.new_vocabulary[] — items the learner met for the first time. Fill every field; incomplete entries yield incomplete spaced-repetition records.review_results[] — items already in the queue that were reviewed. The script runs SM-2 on each. See the fluent-sm2-calculator skill. Mapping: quality = floor(score / 2).skill_scores[].correct counts correct exercises, not a percentage. Accuracy is derived.confidence in learner-profile.skills is 0–100 integer; accuracy in progress-db is 0.0–1.0 float. The script handles the conversion.milestones[] — each entry is a bare string OR an object { "milestone": <required non-empty string>, "date": <optional YYYY-MM-DD, defaults to the session date> }. Don't set a nested session_id; the script stamps the authoritative top-level one. A malformed entry (neither string nor object, or an object missing/empty milestone) exits 1 with no files written. Each milestone becomes both a session-log.milestones[] record and a learner-profile.achievements[] entry.Always call read-db.py at session start to get current state + next_session_id. Don't read each JSON file separately:
python3 "${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR:-.}}/.claude/hooks/read-db.py"
Returns all 6 databases plus computed fields (due_reviews_count, next_session_id, streak_active, days_since_last_session).
python3 "${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR:-.}}/.claude/hooks/update-db.py" <<'EOF'
{
"session_id": "session-012",
"date": "2026-04-24",
"duration_minutes": 12,
"command_used": "/fluent-review",
"skills_practiced": ["vocabulary", "grammar"],
"skill_scores": {
"vocabulary": { "exercises": 3, "correct": 3, "time_minutes": 7 },
"grammar": { "exercises": 2, "correct": 1, "time_minutes": 5 }
},
"review_results": [
{ "item_id": "vocab_huis", "quality": 5 },
{ "item_id": "vocab_deur", "quality": 4 },
{ "item_id": "vocab_raam", "quality": 5 },
{ "item_id": "grammar_omdat_word_order", "quality": 2 },
{ "item_id": "grammar_past_tense", "quality": 4 }
],
"errors": [
{
"pattern_id": "grammar_omdat_word_order",
"category": "grammar",
"your_answer": "omdat ik ben moe",
"correct_answer": "omdat ik moe ben",
"context": "subordinate clause word order",
"severity": "critical"
}
],
"focus_next_session": ["Drill 'omdat' word order"]
}
EOF
python3 "${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR:-.}}/.claude/hooks/update-db.py" <<'EOF'
{
"session_id": "session-013",
"date": "2026-04-25",
"command_used": "/fluent-vocab",
"skills_practiced": ["vocabulary"],
"new_vocabulary": [
{
"item_id": "vocab_keuken",
"item_type": "vocabulary",
"content": "de keuken",
"answer": "the kitchen",
"category": "household_rooms",
"difficulty": "A1",
"initial_quality": 4,
"priority": "medium"
}
]
}
EOF
spaced-repetition.review_queue. It's regenerated from scratch on every run.session_id replaces. Sending the same ID twice overwrites the first call. Useful for corrections, dangerous if unintentional..backups/pre-update-<session_id>/ before any change. Check there to roll back.Six interdependent JSON files must agree: a new session-log entry, a bumped total_sessions, updated SM-2 params, new mistake patterns, recalculated accuracy, refreshed streak. Hand-editing causes silent desync — streak says 7 days but session-log has 6 entries, mastery says 4 stars but accuracy says 45%. The script is the single source of truth.
npx claudepluginhub m98/fluent --plugin fluentAdaptive language-learning session interleaving writing, speaking, vocabulary, and reading exercises based on learner level and weak patterns. Triggered by /fluent-learn.
Facilitates structured speaking practice for language learners, using ACTFL OPI and CEFR-aligned techniques to develop fluency, accuracy, and pragmatic competence through guided conversation.
Extracts session patterns into reusable learnings. Three modes: analyze (extract from history), review (edit/manage), and list (display active learnings). Requires persistence enabled in session config.