Why this exists
I'm proprietor of a school in Jos, Plateau State. The connectivity is intermittent at best. Every "AI in the classroom" tool I evaluated assumed broadband and centralized inference. None of them would deploy. So I built one — under Foniolabs, my personal lab, in my own time.
SkoolBox serves teachers and students in a single application — teachers plan lessons, assess, and monitor; students learn topics with an embedded AI tutor and take adaptive quizzes — and the whole thing runs on a laptop with no internet.
Why Tauri + Rust
Electron was off the table — a 200MB binary is unshippable on the connections this app deploys over. Tauri ships a WebView pointed at the OS's native renderer (~12MB), with Rust handling the heavy lifting: SQLite, file system, LLM inference, encryption.
The frontend is a normal React + Tailwind app. The backend is a Rust crate invoked via Tauri's command system. Everything that can run on-device does; the network is opportunistic.
Architecture
┌──────────────────────────────┐
│ React 18 + Tailwind │
│ (WebView, ~3MB) │
└────────────┬─────────────────┘
│ Tauri IPC (typed)
┌────────────▼─────────────────┐
│ Rust backend │
│ - reqwest (sync when online)│
│ - SQLite (sqlx) │
│ - bcrypt (account auth) │
│ - DOCX parser (mammoth) │
│ - Local LLM runtime │
└──────────────────────────────┘
Key decisions
Local LLM, not cloud. A small quantized model runs locally for tutoring conversations. Quality is below GPT-4 but it's there when there's no internet. When connectivity returns, the app upgrades to a cloud model transparently.
SQLite everywhere. All user data, all course material, all conversation history lives in a local SQLite file. Sync is a separate concern that runs in the background when network is available; the foreground app never blocks on it.
KaTeX, not MathJax. KaTeX renders math 10x faster and ships as static CSS — no runtime font loading, no network requests, predictable performance on low-end hardware.
Why this matters to me personally
I run the school that this tool deploys into. That changes how I build it. Every decision I make in code shows up in a classroom I'm responsible for. Constraint becomes feature; context becomes accountability.