Skip to content

hivaze/adaptive_lang_study_bot

Repository files navigation

Adaptive Language Study Bot

A personalized AI language tutor that runs on Telegram. The bot adapts exercises to each user's level, tracks vocabulary with spaced repetition (FSRS), and sends proactive study reminders on user-configured schedules.

Powered by Claude (via claude-agent-sdk), PostgreSQL, Redis, and aiogram. Most of the codebase was developed with Claude Code (Opus 4.6).

Try the live bot: @personal_lang_study_bot

Features

  • Adaptive exercises — the AI generates exercises tailored to the user's level (A1-C2), interests, weak areas, and preferred difficulty. No static exercise bank.
  • Three session stylesStructured (theory/grammar first, then practice; plans ordered by grammar concepts), Intensive (goal-driven, weakness-focused, vocabulary-heavy; aggressive pace), Casual (free conversation on topics the student enjoys; exercises emerge organically). Style affects session flow, exercise selection, plan construction, and minimum coverage requirements.
  • Learning plans — structured multi-week study plans with phases, topics, and vocabulary targets. Plans are constructed according to the student's session style. Progress is derived from exercise results. The agent adapts plans when the student is ahead or behind schedule.
  • Vocabulary tracking — words are stored per-user with FSRS spaced repetition. The bot schedules reviews at optimal intervals.
  • Web search-powered discussions — the agent can search the web (via Tavily) for news, articles, and cultural content in the target language. Users can ask for news-based lessons, current event discussions, or topic exploration. Available in both interactive sessions and proactive notifications.
  • Proactive notifications — schedule-based reminders that the user signs up for: practice reminders, vocabulary review (when cards are due), weekly progress summaries, and agent-created quiz/custom schedules. Notifications include action + dismiss buttons. The bot remembers what it sent — when a user replies to a notification, the session automatically continues from that context. Users control schedules via natural language or /settings.
  • Auto session management — sessions end automatically when the lesson reaches a natural conclusion. The agent calls an end_session tool, delivers a farewell, and the user receives a formatted summary with achievements and recommendations. An internal AI summary is generated in the background and injected into the next session's system prompt for continuity.
  • Two-tier system — Free (Haiku 4.5) and Premium (Sonnet 4.6) with different limits. No billing — admin grants premium via the Gradio panel.
  • 17 target languages — English, French, Spanish, Italian, German, Portuguese, Russian, Chinese, Japanese, Korean, Arabic, Turkish, Dutch, Polish, Swedish, Ukrainian, Hindi. Users can learn any of these.
  • 7 UI languages — English, Russian, Spanish, French, German, Portuguese, Italian. All bot UI, notifications, and session messages are rendered in the user's native language via an i18n system with JSON locale files.
  • Gradio admin panel — monitor users, sessions, costs, alerts, and system health. Gradio auth required (ADMIN_API_TOKEN).
  • Health alerts — automated Telegram alerts to admins for cost spikes, pool saturation, pipeline failures, and connectivity issues.

Requirements

  • Python 3.12+
  • PostgreSQL 16
  • Redis 7
  • Claude CLI (installed on the host or in Docker)
  • Poetry (for local development)

Quick Start (Docker)

  1. Clone the repository and create the .env file with the required variables:
# Required
TELEGRAM_BOT_TOKEN=your-telegram-bot-token
ANTHROPIC_API_KEY=your-anthropic-api-key
POSTGRES_PASSWORD=your-secure-password
ADMIN_API_TOKEN=your-admin-token  # Gradio admin panel refuses to start without it

# Optional (defaults shown)
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USER=langbot
POSTGRES_DB=langbot
REDIS_URL=redis://localhost:6379/0
MAX_CONCURRENT_INTERACTIVE_SESSIONS=500
MAX_CONCURRENT_PROACTIVE_SESSIONS=50
PROACTIVE_TICK_INTERVAL_SECONDS=60
ADMIN_HOST=0.0.0.0
ADMIN_PORT=7860
ADMIN_TELEGRAM_IDS=[]         # JSON array of admin user IDs, e.g. [123456,789012]
LOG_LEVEL=INFO
METRICS_PORT=9090
DB_POOL_SIZE=150
DB_MAX_OVERFLOW=100
DB_POOL_RECYCLE=3600          # seconds
DB_POOL_TIMEOUT=10            # seconds to wait for a connection before raising
REDIS_MAX_CONNECTIONS=200
  1. Start all services:
docker compose up -d

This starts 4 containers:

  • bot — Telegram bot + APScheduler proactive engine (single process)
  • admin — Gradio admin panel on port 7860
  • postgres — PostgreSQL 16
  • redis — Redis 7 (256MB, noeviction — used for locks/coordination, not caching)
  1. Run database migrations:
docker compose exec bot python -m alembic upgrade head
  1. Open the admin panel at http://localhost:7860.

Quick Start (Local Development)

# Install dependencies
poetry install

# Set up .env with your keys (see above)

# Start PostgreSQL and Redis (or use Docker for just these)
docker compose up -d postgres redis

# Run database migrations
poetry run alembic upgrade head

# Start the bot
poetry run python -m adaptive_lang_study_bot.entrypoints.run_bot

# Start the admin panel (separate terminal)
poetry run python -m adaptive_lang_study_bot.entrypoints.run_admin

Configuration

All configuration is via environment variables (loaded by pydantic-settings from .env). See src/adaptive_lang_study_bot/config.py for all options.

Tier Limits

Parameter Free Premium
Model claude-haiku-4-5 claude-sonnet-4-6
Max turns/session 20 35
Max sessions/day 3 5
Session idle timeout 6 min 10 min
Thinking mode adaptive adaptive
Effort low low
LLM notifications/day 2 8
Rate limit 5 msg/min 20 msg/min
Max cost/session $0.75 $2.81
Max cost/day $2.00 $8.00

To grant a user premium access, use the admin panel or update the tier column in the users table directly.

Telegram Commands

Command Description
/start Onboarding: select native language, target language, timezone
/review Start a vocabulary review session (FSRS due cards)
/stats View progress: level, streak, vocabulary count, recent scores
/settings Manage preferences, schedules, quiet hours, timezone, target language
/end End the current study session explicitly
/deleteme Delete account and all associated data (with confirmation)
/help Command reference
/debug Toggle per-message debug output (admin-only)

Any other text message starts or continues an interactive study session with the AI tutor.

Architecture

System Design

                          ┌────────────┐
                          │  Telegram  │
                          └──────┬─────┘
                                 │ polling
                                 ▼
┌────────────────────────────────────────────────────────────────┐
│ Bot Process                                                    │
│                                                                │
│ INTERACTIVE PATH                                               │
│ aiogram --> DBSession --> Auth --> RateLimit                   │
│                           │                                    │
│     start  chat  settings  review  stats                       │
│              │                                                 │
│              ▼                                                 │
│ SessionManager ─────────────────────> Redis (session lock)     │
│              │                                                 │
│              ▼                                                 │
│ Agent Session (per user)                                       │
│   ClaudeSDKClient ──────────────────> Anthropic API            │
│    ├── System Prompt (15 sections)     (Haiku / Sonnet)        │
│    ├── MCP Server (8-14 tools) ──────> PostgreSQL              │
│    └── Hooks (PostToolUse, UserPromptSubmit, Stop)             │
│              │ on close                                        │
│              ▼                                                 │
│ Post-Session Pipeline ──────────────> PostgreSQL               │
│ (streak, difficulty, milestones)                               │
│                                                                │
│ PROACTIVE ENGINE                                               │
│ APScheduler 60s --> Schedules --> Dispatcher                    │
│                                   ├── template --> Telegram    │
│                                   └── LLM (+ web tools) ──> Anthropic│
│                                                                │
│ Health Alerts + Stats Reports ──────> Telegram (admins)        │
│ Prometheus metrics :9090                                       │
└──────────┬─────────────────┬───────────────────────────────────┘
           │                 │
           ▼                 ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│  PostgreSQL 16   │ │    Redis 7       │ │  Anthropic API   │
│  9 tables        │ │  session locks   │ │  Haiku 4.5       │
│                  │ │  rate limits     │ │  Sonnet 4.6      │
│  users           │ │  notif dedup     │ │                  │
│  vocabulary      │ │  tick lock       │ │  via Claude      │
│  sessions        │ │  alert dedup     │ │  Agent SDK       │
│  schedules       │ │                  │ │                  │
│  exercises       │ │                  │ │                  │
│  notifications   │ │                  │ │                  │
│  learning_plans  │ │                  │ │                  │
│  review_log      │ │                  │ │                  │
│  access_requests │ │                  │ │                  │
└────────▲─────────┘ └──────────────────┘ └──────────────────┘
         │
┌────────┴─────────┐
│  Gradio Admin    │
│  Panel :7860     │
│                  │
│  Users  Sessions │
│  Costs Analytics │
│  Alerts  System  │
│  Broadcast       │
│  Whitelist       │
└──────────────────┘

Directory Structure

src/adaptive_lang_study_bot/
├── config.py              # Settings, tier limits
├── enums.py               # StrEnum constants (UserTier, SessionType, NotificationTier, CloseReason, etc.)
├── utils.py               # Shared helpers (language names, streak, tool summaries)
├── i18n.py                # Internationalization: t(key, lang) with locale JSON fallback
├── locales/               # JSON locale files (en, ru, es, fr, de, pt, it)
├── agent/                 # Claude SDK: tools, hooks, prompt, session manager
├── bot/                   # aiogram: middlewares, routers, app setup
│   └── routers/           # start, chat, settings, review, stats, debug
├── db/                    # SQLAlchemy models, repositories, migrations
├── cache/                 # Redis: session lock, rate limits, key patterns, distributed locks
├── proactive/             # APScheduler tick, triggers, dispatcher, admin reports
├── fsrs_engine/           # FSRS spaced repetition wrapper
├── pipeline/              # Post-session validation (pure Python)
├── admin/                 # Gradio admin panel
└── entrypoints/           # run_bot.py, run_admin.py

Key design decisions

  • Per-session closures — each agent session creates its own tool and hook functions. Tools capture a session factory and user ID (each tool call gets its own short-lived DB session). This ensures complete data isolation between concurrent users.
  • Long-lived sessions — each user gets one ClaudeSDKClient that persists across messages until closed (by turn/cost limit, idle timeout, agent-initiated end_session, or /end). A new session builds a fresh system prompt from the user's current DB profile snapshot. A 120-second cooldown prevents new sessions immediately after close (skipped for onboarding).
  • Session continuity via AI summaries — after each session, a background LLM call generates a structured internal summary (topics, performance, vocabulary, continuation points). These summaries are stored in the sessions.ai_summary column and injected into the next session's system prompt, giving the agent rich context about recent sessions without duplicating raw exercise data.
  • Hybrid personalization — the system prompt carries the user profile snapshot (read-only context), while MCP tools handle all DB writes (exercises, vocabulary, preferences). Session style (structured/intensive/casual) modulates prompt generation across multiple sections: session flow, exercise preferences, plan construction guidelines, and minimum coverage rules.
  • Learning plans — structured multi-week plans (2-8 weeks) with phases, focus topics, and vocabulary targets. Progress is derived on-the-fly from exercise results (compute_plan_progress) — no stored per-topic state. The agent adapts plans when the student is ahead or behind schedule. Level progression is plan-anchored: the agent assesses readiness and calls adjust_level after plan completion, rather than automatic score thresholds. When all topics are completed but the user hasn't reached the target CEFR level, a consolidation phase is auto-added targeting the weakest topics at a higher mastery bar. Mastery plans (where current and target levels are the same) auto-complete and delete at 100%.
  • Three-tier notifications — template ($0 cost, random variant from locale files), LLM (short-lived proactive session with optional web search generates personalized message), or hybrid (try LLM, fall back to template). Free users get 2 LLM notifications/day, premium get 8. All notifications include CTA keyboards with action + dismiss buttons. A post-session cooldown prevents notifications from firing immediately after a session ends.
  • Notification reply context — when a user replies to a proactive notification, the system prompt includes the notification text as context, so the agent naturally continues from that topic rather than starting fresh.
  • Localized UI — all user-facing messages (bot UI, notifications, session summaries, warnings) rendered via i18n.t() in the user's native language.
  • Post-session pipeline — after each session, a pure-Python pipeline validates data integrity, updates streaks, auto-adjusts difficulty, and detects milestones.

Database

PostgreSQL with 9 tables:

Table Purpose
users User profiles, preferences, notification settings, tier
vocabulary Per-user words with FSRS spaced repetition state
sessions Session records with cost/token tracking
schedules RRULE-based recurring schedules (daily review, weekly summary, etc.)
exercise_results Individual exercise scores for analytics
notifications Audit log of all sent/skipped notifications
vocabulary_review_log Individual FSRS review events
learning_plans Structured multi-week study plans with JSONB phases/topics (one per user)
access_requests Whitelist access requests with approval status and reviewer info

Redis

Used for locking, rate limiting, and deduplication:

Key pattern TTL Purpose
session:active:{id} 7-12 min Track active sessions, enforce one-per-user
session:cooldown:{id} 120s Post-session cooldown before new session (skipped for onboarding)
ratelimit:user:{id}:* 60s Per-user rate limiting
notif:dedup:{user_id}:{type}:{date} 24h Prevent duplicate notifications
notif:llm_count:{user_id}:{date} 24h Track daily LLM notification count per user
notif:cooldown:{user_id} 5 min Per-user cooldown between any notifications
lock:proactive_tick 5 min Distributed lock for tick scheduler
lock:admin_stats_report 5 min Distributed lock for stats report
lock:admin_health 2 min Distributed lock for health alerts
admin:alert:{type}:{hour} 1h Dedup health alerts per type per hour

Database Migrations

# Create a new migration
poetry run alembic revision --autogenerate -m "description"

# Apply migrations
poetry run alembic upgrade head

# Rollback one step
poetry run alembic downgrade -1

Testing

# Run all tests
poetry run pytest

# Run only unit tests
poetry run pytest tests/unit/

# Run only integration tests (requires Docker for testcontainers)
poetry run pytest tests/integration/

# Run specific file
poetry run pytest tests/unit/agent/test_tools.py

# Stop on first failure
poetry run pytest -x

Unit tests (tests/unit/)

No database, Redis, or SDK required. They verify:

  • Tool constants and session-type permissions
  • Security invariants (mutable field whitelists)
  • Pure functions (message splitting, timezone conversion, language detection, utils helpers)
  • Prompt builder output structure and sanitization
  • Notification template rendering via i18n
  • Dispatcher gate logic (should_send conditions)
  • Score normalization consistency (0-10 scale thresholds)
  • Post-session pipeline steps and post-session logic
  • FSRS engine operations
  • Config validation
  • Learning plan progress computation
  • Hook behavior (adaptive hints, wrap-up injection)
  • Auth middleware logic
  • Admin role checks
  • Quiet hours edge cases
  • Difficulty adjustment
  • i18n translation and fallback chains
  • Proactive LLM session lifecycle

Integration tests (tests/integration/)

Require Docker. Use testcontainers to spin up real PostgreSQL 16 and Redis 7 containers. Tests cover:

  • CASCADE and FK constraints
  • Repository operations (user, vocabulary, session, schedule, exercise, notification)
  • Redis session lock and cache behavior
  • Atomic operations and concurrent access
  • Learning plan CRUD and constraints
  • Notification dispatch integration

LLM tests (tests/llm/)

Require ANTHROPIC_API_KEY. Make real Claude API calls via claude-agent-sdk to test:

  • System prompt compliance (native language, off-topic refusal)
  • Security boundaries (tool permissions, field whitelists)
  • Tool calling compliance
  • Session type behavior (onboarding vs interactive)
  • Learning plan tool calling (create, get, session-type restrictions)
  • Adaptive behavior (score-based hints)
  • Multi-turn conversations

Monitoring

Prometheus Metrics

The bot exposes a Prometheus metrics HTTP endpoint on port METRICS_PORT (default 9090). 16 metrics are tracked across 3 types:

  • Gauges — active session pool size (interactive/proactive)
  • Counters — sessions created/closed, messages processed, errors, notifications sent/skipped, proactive ticks, pipeline completions
  • Histograms — session cost, session duration, message cost, tick duration, pipeline duration, notification LLM cost

APScheduler Jobs

The bot process runs 3 background jobs:

Job Interval Purpose
proactive_tick 60s Schedule-based notifications and follow-up reminders
health_alerts 60s Evaluate 7 health conditions, alert admins via Telegram
admin_stats_report 12h Send usage/cost summary to admins via Telegram

Health Alerts

Automated alerts sent to admin Telegram IDs (deduped per hour per type):

Alert Condition
Cost spike Today's cost > 2x 7-day daily average
Interactive pool high > 80% capacity
Proactive pool high > 80% capacity
Pipeline failures > 3 failures in last hour
Redis unhealthy Connection failed
DB unhealthy Connection failed
Notification failures > 30% failure rate (min 5 total in last hour)

Admin Panel (Gradio)

Available at http://localhost:7860 (requires ADMIN_API_TOKEN, login as admin). Eight tabs:

  • Users — search by name/username/ID, view full profile, toggle tier (free/premium), toggle active status, toggle admin role
  • Sessions — recent 100 sessions: user, type, cost, turns, tools used, pipeline status, duration
  • Costs — summary (today/7d/30d), daily breakdown (14 days), per-user cost ranking (7 days)
  • Analytics — user activity trends, session metrics, retention data
  • Alerts — pipeline failures, notification delivery stats (7-day status breakdown + recent 20)
  • System — active session pool, Redis memory, DB status, configuration snapshot, health alert status (7 checks)
  • Broadcast — send messages to all users or filtered groups
  • Whitelist — manage access requests: view pending, approve/reject, track approvals

Logs

The bot uses loguru for structured logging. All significant events are logged:

  • User registration and profile updates
  • Session creation, tool calls, and completion
  • Proactive tick execution and notification dispatch
  • Post-session pipeline results
  • Health alerts and admin reports

Cost Estimates

Estimates assume prompt caching is active (system prompt + tool definitions cached across turns). Pricing: Haiku 4.5 — $1/$5 per MTok (input/output), Sonnet 4.6 — $3/$15 per MTok. Proactive notifications use Haiku regardless of tier.

Tier Avg session cost Daily (1-2 sessions) Monthly (1 user)
Free (Haiku 4.5) $0.03-0.08 ~$0.10 ~$3
Premium (Sonnet 4.6) $0.20-0.50 ~$0.80 ~$25

Scale estimates assume 60% daily active rate and 1.5 sessions per active user per day:

Scale All Free Mixed (90/10) All Premium
100 users ~$180/mo ~$320/mo ~$1,500/mo
1,000 users ~$1,800/mo ~$3,200/mo ~$15,000/mo

Capacity & Max Load

The primary bottleneck is the interactive session pool — each concurrent user holds one Claude CLI subprocess (~50-80 MB RAM) for the duration of their session (until idle timeout or /end). Defaults are tuned for ~50,000 registered users.

Default resource limits

Resource Default Env var / Config
Interactive session pool 500 concurrent MAX_CONCURRENT_INTERACTIVE_SESSIONS
Proactive session pool 50 concurrent MAX_CONCURRENT_PROACTIVE_SESSIONS
Bot container memory 40 GB docker-compose.yml deploy limit
DB connection pool 150 + 100 overflow DB_POOL_SIZE, DB_MAX_OVERFLOW
PostgreSQL max connections 500 docker-compose.yml command args
Redis max connections 200 REDIS_MAX_CONNECTIONS
Redis memory 512 MB docker-compose.yml command args

User capacity estimates

Assumptions: 60% daily active rate, 1.5 sessions per active user per day, average session occupies a slot for ~5 minutes, activity spread over ~16 waking hours, peak load ~3x average.

Registered users Avg concurrent sessions Peak concurrent (est.) Fits in 500 slots?
1,000 ~5 ~15 Yes (comfortable)
10,000 ~47 ~140 Yes
50,000 ~234 ~700 Yes (some rejection at extreme peaks)
100,000 ~469 ~1,400 No (pool exhaustion at peak)

Memory bound: 500 concurrent sessions x ~65 MB avg = ~32.5 GB. Fits within the 40 GB container limit with headroom for the Python process and overhead.

Proactive notification throughput

Each 60-second tick dispatches up to 50 concurrent notifications. Template notifications ($0) resolve in milliseconds; LLM notifications take ~5-30 seconds each. At 50 concurrent LLM slots, the system can dispatch ~100-600 LLM notifications per tick (depending on generation time). Daily LLM limits (2 free / 8 premium per user) bound demand to ~54 avg / ~160 peak per tick at 30k DAU — well within capacity. Excess LLM demand auto-downgrades to free template notifications.

Scaling beyond defaults

Bottleneck How to scale
Session pool exhausted Increase MAX_CONCURRENT_INTERACTIVE_SESSIONS (requires proportional RAM)
Bot out of memory Increase Docker memory limit (~65 MB per additional concurrent session)
DB connections saturated Increase DB_POOL_SIZE and PostgreSQL max_connections
Proactive notifications slow Increase MAX_CONCURRENT_PROACTIVE_SESSIONS
Single-process CPU bound Not horizontally scalable — the bot runs as a single process with in-memory session state. Scaling beyond one instance requires architectural changes (external session store, distributed session management).

Docker Compose Operations

The stack runs 4 services:

Service Image Purpose Port
bot custom (Dockerfile) Telegram bot + APScheduler proactive engine 9090 (Prometheus metrics)
admin custom (Dockerfile) Gradio admin panel 7860
postgres postgres:16-alpine Database (max_connections=500, tuned shared_buffers/work_mem) 5432 (internal)
redis redis:7-alpine Locks, rate limits, dedup (512MB, noeviction) 6379 (internal)

Lifecycle

# Start all services (detached)
docker compose up -d

# Stop all services (preserves data volumes)
docker compose down

# Stop and remove all data (fresh start)
docker compose down -v

# Rebuild after code changes and restart
docker compose up -d --build

# Rebuild only one service
docker compose up -d --build bot

# Restart a single service (no rebuild)
docker compose restart bot

# Check status
docker compose ps

Logs

# Follow all logs (Ctrl+C to stop)
docker compose logs -f

# Follow a single service
docker compose logs -f bot
docker compose logs -f admin
docker compose logs -f postgres
docker compose logs -f redis

# Last N lines
docker compose logs --tail 50 bot

# Last N lines + follow
docker compose logs -f --tail 100 bot

# Logs since a timestamp
docker compose logs --since "2025-01-15T10:00:00" bot

# Logs from the last hour
docker compose logs --since 1h bot

# Show timestamps
docker compose logs -t bot

# Multiple services at once
docker compose logs -f bot admin

# Grep for specific patterns (combine with standard tools)
docker compose logs bot 2>&1 | grep "ERROR"
docker compose logs bot 2>&1 | grep "user 123456"

Database (PostgreSQL)

# Open psql shell
docker compose exec postgres psql -U langbot

# Run a single SQL query
docker compose exec postgres psql -U langbot -c "SELECT count(*) FROM users;"

# Run migrations (after code update)
docker compose exec bot python -m alembic upgrade head

# Check current migration version
docker compose exec bot python -m alembic current

# Create a new migration
docker compose exec bot python -m alembic revision --autogenerate -m "description"

# Rollback one migration
docker compose exec bot python -m alembic downgrade -1

# Dump the database (backup)
docker compose exec postgres pg_dump -U langbot langbot > backup_$(date +%Y%m%d_%H%M%S).sql

# Restore from backup (stop bot/admin first)
docker compose stop bot admin
docker compose exec -T postgres psql -U langbot langbot < backup_20250115_120000.sql
docker compose start bot admin

Redis

# Open redis-cli
docker compose exec redis redis-cli

# Check connectivity
docker compose exec redis redis-cli ping

# View memory usage
docker compose exec redis redis-cli info memory

# List active session locks
docker compose exec redis redis-cli KEYS "session:active:*"

# List all keys (use cautiously in production)
docker compose exec redis redis-cli KEYS "*"

# Check a specific key's TTL
docker compose exec redis redis-cli TTL "session:active:123456"

# Flush all Redis data (resets locks, rate limits, dedup)
docker compose exec redis redis-cli FLUSHALL

# Monitor commands in real time (Ctrl+C to stop)
docker compose exec redis redis-cli MONITOR

Shell access

# Shell into the bot container
docker compose exec bot bash

# Shell into postgres container
docker compose exec postgres sh

# Run a Python one-liner inside the bot container
docker compose exec bot python -c "from adaptive_lang_study_bot.config import settings; print(settings.model_dump_json(indent=2))"

Update workflow

After pulling new code or making changes:

# 1. Rebuild and restart (zero-downtime for DB/Redis)
docker compose up -d --build

# 2. Run any new migrations
docker compose exec bot python -m alembic upgrade head

# 3. Verify services are healthy
docker compose ps
docker compose logs --tail 20 bot

For changes that require a fresh database:

# 1. Stop everything and remove volumes
docker compose down -v

# 2. Rebuild and start
docker compose up -d --build

# 3. Run all migrations on the empty database
docker compose exec bot python -m alembic upgrade head

Resource monitoring

# CPU and memory usage per container
docker compose stats

# Disk usage (images, containers, volumes)
docker system df

Maintenance

Granting premium tier

Via admin panel or directly:

UPDATE users SET tier = 'premium' WHERE telegram_id = 123456789;

Granting admin role

Via admin panel (auto-upgrades to premium) or directly:

UPDATE users SET is_admin = true, tier = 'premium' WHERE telegram_id = 123456789;

Resetting a user's streak

UPDATE users SET streak_days = 0, streak_updated_at = NULL WHERE telegram_id = 123456789;

Pausing all notifications for a user

UPDATE users SET notifications_paused = true WHERE telegram_id = 123456789;

Viewing active sessions

Check Redis:

redis-cli KEYS "session:active:*"

Or via the admin panel's System tab.

Docker resource requirements

The bot container is allocated 40GB memory to support up to 500 concurrent interactive agent sessions (~50-80MB each for the Claude CLI subprocess). PostgreSQL is tuned with shared_buffers=1GB, work_mem=4MB, and SSD-optimized settings. Redis is capped at 512MB with noeviction policy (Redis stores locks and coordination data, not cache — eviction would cause correctness bugs).

Troubleshooting

Issue Solution
Bot not responding Check docker compose logs bot for errors. Verify TELEGRAM_BOT_TOKEN is correct.
"Claude Code cannot be launched inside another session" Unset CLAUDECODE env var. Only happens when running inside VS Code with Claude Code extension.
High costs Check the admin panel Costs tab. Consider lowering max_sessions_per_day or max_cost_per_day_usd in config.py.
Notifications not sending Check user's notifications_paused, quiet_hours_start/end, and max_notifications_per_day. Check notifications table for skipped_* statuses.
Migrations fail Ensure PostgreSQL is running and POSTGRES_* env vars are correct. Check docker compose logs postgres.
Redis connection refused Verify REDIS_URL matches the Redis container hostname. Inside Docker, use redis://redis:6379/0.
Health alerts not arriving Ensure ADMIN_TELEGRAM_IDS is set and the listed users have is_admin = true in the database.

About

A personalized AI language tutor that runs on Telegram with proactive behaviour (cron-like). Agentic powers by claude-agent-sdk.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages