A voice-first AI teaching assistant for classroom big screens.
Say “Hi, Neo” — a liquid-glass lens wakes along the screen edges, refracting the live desktop beneath a band of flowing color. Speak, and Neo transcribes, reasons, answers in streaming Markdown / KaTeX, and operates the machine through a gated local tool chain. When the work is done, it fades back into the system tray and waits for the next call.
- Overview
- Feature Highlights
- Screenshots
- The Voice Loop
- Requirements
- Download & Install
- Build from Source
- Architecture
- Classroom Mode
- Memory
- Tool Chain
- Safety & Privacy
- Versioning & Releasing
- Design Principles
- Acknowledgments
- License
Neo is a Windows desktop AI assistant built for classroom big screens — touch all-in-ones running at 1080p or 4K, read from several meters away. It is designed around three observations about real classrooms:
- The teacher's hands are busy. The primary interface is voice: wake word → dictation → answer. Everything else is secondary.
- The screen belongs to the lesson. Neo must be absent until called — no taskbar icon competing for attention, no window chrome over the slides. When it does appear, it appears as light: a lens of flowing color along the edges, a small card in the corner, a question dialog in the center — then it leaves.
- Classroom machines are hostile environments. Spotty networks, aggressive antivirus, no admin rights, and an audience. Neo's audio pipeline is fully offline, its installer is per-user (no UAC), and every mutating tool call is gated behind an explicit on-screen confirmation.
The visual language is adapted from DeepSeek Harness (@deepseek-ai/dsh).
Big-screen and touch adaptation, the voice pipeline, the liquid-glass overlay, the
classroom monitor, and the tool chain are original work — independent implementations,
not upstream ports.
| 🎙️ On-device wake word | Re-implementation of the livekit-wakeword inference chain (mel → speaker embedding → wake classifier) on local ONNX models. 16 kHz input, 80 ms frames, 2 s sliding window. |
| 🗣️ Offline speech-to-text | Silero VAD endpointing + SenseVoice-Small (int8) via in-process sherpa-onnx. Zero network dependency. |
| 🌊 Liquid-glass marquee | Fullscreen transparent overlay on DX12 + DirectComposition: live desktop capture drives real-time refraction with chromatic dispersion, Fresnel rim light, and roughness blur, wrapped in a seven-color pastel band that hugs the screen edges — corners included. Breathes with the mic level. |
| 🪟 Unified render layer | Mini window, confirmation cards, class summaries and effect flashes are all cards on one persistent overlay — no auxiliary windows are ever created, so none of them can flash black. Cards hit-test precisely; clicks fall through everywhere else. |
| 💬 Streaming conversation | OpenAI-compatible /chat/completions client (DeepSeek by default) with CommonMark + KaTeX rendering (a Rust port of KaTeX's layout). Cancellable at any moment — even mid-tool-execution. |
| 🛠️ Gated local tools | 20 tools: files, documents, shell (PowerShell + bundled Git Bash), screenshots, UIA automation, web search, memory. Write/exec actions require on-screen confirmation first. |
| ❓ Ask-the-user tool | When the model is unsure, ask_user pops a question card with tappable options instead of guessing. |
| 🧠 Three-tier memory | Long-term profile (remember/forget, injected into every prompt) · daily notes with a gist index (note_day/recall_day, index-first lookup) · per-day class notes written by the classroom monitor. |
| 🖥️ Classroom mode | Detects when a presentation goes fullscreen → silently captures + transcribes the lesson → polishes a summary when the class ends → slides in a summary card. A tiny red dot in the corner marks summary start/finish. |
| 🪟 Mini window | While Neo works in the background: tool flow + reply body (Markdown/LaTeX) in a corner card that dodges the cursor, auto-sizes to the final paragraph, and fades out after a 5 s dwell. |
| 🔔 Native notifications | Windows toasts on startup and task completion; the release build never flashes a console window. |
| Conversation · dark · 1080p | Generating (stoppable) |
|---|---|
![]() |
![]() |
| Tool cards | Math rendering (KaTeX port) | Mini window (done state) |
|---|---|---|
![]() |
![]() |
![]() |
More snapshots — light theme, 4K far-view, confirmation dialogs, settings
The full gallery lives in docs/screens/, including:
- Light theme & 4K far-view states
- Tool confirmation dialogs (normal / long-content / scrolled)
- Settings panels (appearance, model, display)
- Attachment chips & CommonMark edge cases (tables, nested lists, reference links)
- Session action sheets & reasoning traces
All snapshots are produced by the offscreen render tests (cargo test), so they never
drift far from what the app actually draws.
sequenceDiagram
autonumber
participant Mic as 🎙️ Microphone
participant Wake as neo-wake
participant Overlay as neo-overlay
participant STT as neo-stt
participant LLM as neo-llm
participant Tools as neo-tools
participant User as 👩🏫 Teacher
Mic->>Wake: 16 kHz stream
Wake-->>Overlay: “Hi, Neo” detected
Overlay->>Overlay: marquee on · capture desktop @ 30 fps
Mic->>STT: dictation frames
STT-->>LLM: transcript (VAD endpoint)
LLM-->>User: streaming Markdown / KaTeX answer
loop tool rounds
LLM->>Tools: tool call
Tools-->>User: confirmation / question card (if needed)
Tools-->>LLM: structured result
end
LLM-->>User: toast + mini window lingers 5 s, fades out
Overlay->>Overlay: marquee off — back to tray
| Requirement | Notes |
|---|---|
| Windows 10 2004 (20H1) or later | Capture exclusion (WDA_EXCLUDEFROMCAPTURE) is available from 2004 onward. |
| DX12-capable GPU | Required by the overlay's wgpu backend. |
| Microphone | For wake word & dictation. Everything else works without one. |
| Rust 1.95+ | Only for building from source. |
Note
On pre-2004 builds, or in remote sessions where capture exclusion fails, Neo still runs — the overlay degrades to a halo-only mode (no desktop refraction), so the marquee can never feed back into its own capture.
Pre-built artifacts are published on the Releases page:
| Artifact | Shape | Pick it if… |
|---|---|---|
neo-<ver>-installer-x64.exe |
NSIS wizard (per-user, no admin rights needed) | You want Start Menu / Desktop shortcuts and an entry in Apps & Features |
neo-<ver>-portable-x64.zip |
Zip with everything inside | You want to unpack-and-run, or keep it on a USB stick |
Both bundles contain the same payload: neo.exe, wake-word models, STT models
(SenseVoice int8 + Silero VAD), and a portable Git Bash runtime for the Bash tool.
Tip
The installer is unsigned for now — SmartScreen will warn once. User data
(database, memories) lives in %APPDATA%\Neo and survives uninstalls.
cargo run --release # release is strongly recommended: 60 fps at 4K
cargo test # unit tests + offscreen render snapshots (output: docs/screens/)| Asset | Location | Source |
|---|---|---|
| Wake-word models (~3 MB) | crates/neo-wake/assets/ |
Vendored in the repo — nothing to do |
| STT models (~240 MB) | crates/neo-stt/assets/ (git-ignored) |
sense-voice/model.int8.onnx + tokens.txt, and vad/silero_vad.onnx from the official sherpa-onnx releases; or point NEO_STT_MODEL_DIR at any directory containing them |
| Portable Git Bash (~91 MB) | runtime/ (git-ignored) |
python tools/fetch_runtime.py |
Important
Missing STT models disable only voice transcription; a missing runtime disables only the Bash tool. Everything else works.
flowchart LR
subgraph Input
Mic[🎙️ mic]
Screen[🖥️ screen]
end
subgraph Voice["voice pipeline"]
Wake[neo-wake<br/>wake-word ONNX]
STT[neo-stt<br/>VAD + SenseVoice]
end
App[neo-app<br/>eframe UI · state machine · tray]
Overlay[neo-overlay<br/>unified render layer<br/>wgpu/DX12]
LLM[neo-llm<br/>streaming client]
Tools[neo-tools<br/>20 gated tools]
Store[(neo-store<br/>SQLite)]
FS[(memories.json<br/>daily/ · class/)]
Mic --> Wake -->|wake event| App
Mic --> STT -->|transcript| App
App -->|show / level| Overlay
Screen -->|30 fps capture| Overlay
App --> LLM --> Tools
Tools -->|confirmation / question cards| Overlay
App <--> Store
Tools <--> FS
| Crate | Responsibility |
|---|---|
neo-app |
Main binary: eframe UI, voice state machine, tray, per-turn orchestration |
neo-ui |
Custom-drawn component library (buttons, modals, lists, badges, fields, …) |
neo-theme |
Design system: semantic palette, metrics & scaling chain, fonts, squircle corners |
neo-llm |
OpenAI-compatible streaming client; function-calling protocol transport |
neo-tools |
Tool spec / confirmation policy / execution / result presentation |
neo-wake |
Wake-word engine (mic → mel → embedding → scoring) |
neo-stt |
Offline speech-to-text (Silero VAD + SenseVoice int8) |
neo-overlay |
The one always-on-top transparent window: marquee + all cards, shared GPU |
neo-store |
Session & message persistence (SQLite, WAL) |
When a teacher opens a slide deck fullscreen, Neo starts an eyes-and-ears session in the background — no interaction needed:
stateDiagram-v2
[*] --> Idle
Idle --> Recording: presentation maximized
Recording --> Polishing: fullscreen exits + 2 min idle
Recording --> Idle: cancelled
Polishing --> Presenting: summary ready
Polishing --> Recording: new class started<br/>(result kept)
Presenting --> Recording: new class started<br/>(popup stays up)
Presenting --> Idle: dismissed
- Recording — silent screenshots (no flash, no self-capture) are analyzed by the vision model while lesson audio is transcribed continuously. STT engines are reused across classes, not reloaded.
- Polishing — screen notes + transcript are condensed into a ≤ 1500-character summary. A small red dot in the top-left corner marks the start and finish of this phase (5 s each).
- Presenting — the summary slides in from the top as a Markdown card, and is filed
under per-day class notes (
class/YYYY-MM-DD.json) with a one-line pointer appended to long-term memory.
Neo keeps three deliberately separate kinds of memory:
| Tier | Where | Written by | Read by the model |
|---|---|---|---|
| Long-term | memories.json |
remember tool / settings UI |
Injected into every system prompt (≤ 50 entries, 3000 chars) |
| Daily notes | daily/YYYY-MM-DD.json + index.json |
note_day tool (silent observations, e.g. off-task screen content) |
recall_day — index first, then the day file |
| Class notes | class/YYYY-MM-DD.json |
classroom monitor | via recall_day (subject + summary) |
The daily index is double-capped (120 days / 4000 chars, oldest dropped first) so
lookup stays O(small) forever. All memory files are atomic-write JSON with .bad
quarantine on corruption, and live next to the database in %APPDATA%\Neo.
Every tool declares its parameters, preview line, and risk level once; the JSON schema, the confirmation policy, and the docs are derived from that single declaration.
| Risk | Tools | Policy |
|---|---|---|
read |
read_file · read_document · view_image · web_search · recall_day · screenshot · screen_elements · screen_element_search | run immediately |
open |
open_file · open_app · remember · forget · note_day | run immediately (machine state untouched) |
ask |
ask_user | the popup is the answer path — replies flow back as the tool result |
write |
write_file · edit_file | on-screen confirmation |
exec |
powershell · bash · click · drag | on-screen confirmation |
Warning
click / drag synthesize real mouse input. While Neo is driving the pointer,
clicking anywhere pops an interrupt confirmation — and Neo's own synthetic clicks
are excluded from that detection so it can never interrupt itself.
- Voice stays on the machine. Wake word and STT are fully offline ONNX models.
- The LLM is the only network dependency (plus
web_search, only when invoked). - The overlay excludes itself from capture (
WDA_EXCLUDEFROMCAPTURE), so lesson screenshots, recordings, and meeting shares never contain the marquee or the cards. - No admin rights, ever. Per-user install, per-user data, per-user registry hive.
- Classroom monitoring is local-first: screenshots are analyzed by the configured vision model; transcripts and notes never leave the machine except through that configured endpoint.
The single source of truth is [workspace.package].version in the root
Cargo.toml; every crate inherits it, and the UI reads it via
env!("CARGO_PKG_VERSION").
Pushing a v* tag triggers the release pipeline:
flowchart LR
Tag([git tag v*]) --> Build[ cargo build --release ]
Build --> Assets[STT models + MinGit runtime]
Assets --> Zip[[portable-x64.zip]]
Assets --> Art[make_installer_art.py<br/>whale icon · wizard bitmaps]
Art --> NSIS[[installer-x64.exe]]
Zip --> Release([GitHub Release<br/>auto changelog])
NSIS --> Release
- Visual fidelity first; adaptation through non-visual channels. The upstream shape language (corner radii, button sizes, type rhythm) is never re-invented. Big-screen adaptation is uniform proportional scaling plus a 48 pt touch floor.
- Scaling must be visible. The final scale-factor formula is printed in full in the settings panel, so on-site troubleshooting starts with the answer on screen.
- Keep egui for what it does best. Text editing and scroll clipping use native egui; everything else is custom-drawn.
- No window may ever flash black. Auxiliary UI is drawn as cards on the persistent overlay; offscreen test paths keep the old viewports so snapshots stay honest.
- If it can break in a classroom, it breaks loudly in a test. Dead streams, poisoned locks, panicking workers, 49-day uptime wraps — each has a regression test.
- DeepSeek Harness (
@deepseek-ai/dsh) — visual language - livekit-wakeword — wake-word inference chain design
- sherpa-onnx — in-process ONNX inference (SenseVoice, Silero VAD)
- ratex — KaTeX's layout, ported to Rust
- egui / wgpu — UI & rendering foundations




