Stop repeating the same chess mistakes. Blunder Tutor pulls your games from Lichess and Chess.com, finds the positions where you went wrong, and turns them into puzzles you can practice — for free, on your own machine.
The blog post with the design and approaches architecture
- Import your games from Lichess, Chess.com, or both
- Find your blunders using Stockfish engine analysis
- Practice them as puzzles — the positions where you made mistakes, not random tactics
- See where you're weakest — dashboard shows your blunder patterns by opening, game phase, and difficulty
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
- Lichess analysis shows you the blunder but doesn't let you drill it repeatedly
- Chess.com Game Review is paywalled — one free review per day, then $50–150/year
- Generic puzzle sites train random positions, not your weaknesses
Blunder Tutor combines the parts that matter: finds your mistakes, turns them into drillable puzzles, and tracks which patterns you've fixed. All free, all local.
docker run -p 8000:8000 -v $(pwd)/data:/app/data ghcr.io/mrlokans/blunder-tutor:latestOpen http://localhost:8000 and enter your chess username. That's it.
For Docker Compose, environment variables, and advanced options see Docker Deployment Guide.
By default Blunder Tutor runs single-user with no login. To host multiple accounts on one instance, enable credentials mode:
docker run -p 8000:8000 -v $(pwd)/data:/app/data \
-e AUTH_MODE=credentials \
-e SECRET_KEY="$(openssl rand -hex 32)" \
-e MAX_USERS=5 \
ghcr.io/mrlokans/blunder-tutor:latestFirst signup uses a one-time invite code printed to the server log on boot. Each account gets an isolated SQLite database under data/users/. See Authentication for the full setup, CLI admin commands, and gotchas.
Off by default. Enable Sentry to get HTTP transactions, exception capture, custom metrics for engine / jobs / WebSockets, and a Sentry Crons monitor on the scheduler tick:
docker run -p 8000:8000 -v $(pwd)/data:/app/data \
-e SENTRY_ENABLED=true \
-e SENTRY_DSN="https://<key>@<org>.ingest.sentry.io/<project>" \
ghcr.io/mrlokans/blunder-tutor:latestFor tuning knobs, the Sentry-side Crons monitor setup, and data-handling notes see the Observability section of docs/environment.md.
All environment variables — auth, data, demo, engine, cache, analytics, observability, debugging — are documented in docs/environment.md.
- Multi-platform import — Lichess, Chess.com, or paste your own PGN
- Stockfish analysis — configurable depth, runs locally on your machine
- Puzzle trainer — practice your blunders with hints, best-move arrows, tactical patterns highlights and threat detector
- Smart filtering — narrow puzzles by game phase, tactical pattern, difficulty, time control, color, or date range
- Spaced repetition — recently solved puzzles are held back so you focus on fresh weaknesses
- Opening traps — see which traps you've fallen into and learn the refutations
- Starred puzzles — bookmark positions you want to revisit
- Dashboard — accuracy trends, activity heatmap, opening breakdown, phase/color/difficulty distribution, growth metrics, conversion & resilience rates, collapse-point analysis
- Board & theme customization — 16 piece sets, 6 board color presets, 7+ UI themes, or build your own
- Auto-sync — scheduled background fetch and analysis of new games
- Self-hosted — SQLite database, no external services, your data stays on your machine
- Docker-ready — single
docker runcommand to get started - Multilingual — English, Russian, Ukrainian, Spanish, Polish, Belarusian, and Chinese
- Demo mode — read-only hosted demo for trying the app without installing anything
make install-dev # Install dependencies
make test # Run tests
make lint # Check code style
make fix # Auto-fix formatting
make train-ui # Start on localhost:8000
# E2E tests (requires npm ci in e2e/)
cd e2e && npx playwright testRequires Python 3.13+, Node.js 22+, and Stockfish on your PATH (or set STOCKFISH_BINARY).
We use prek for pre-commit hooks (configured in prek.toml). To skip certain files or directories from hook processing, add an exclude pattern at the top level or per-hook:
# Global exclude — applies to all hooks
exclude = "node_modules|^\\.git"
# Per-hook exclude
[[repos.hooks]]
id = "ruff-check"
exclude = "migrations\\.py"See prek exclude docs for details.
Issues and pull requests are welcome. Run make install-dev and make test before submitting.
- Changelog
- Docker Deployment Guide
- Authentication — multi-user mode setup and admin
- Glossary — chess and engine terminology
- License (AGPL-3.0)







