The companion who actually lives with you.
A local-first desktop companion built on Tauri 2 + React 19 + Rust. SAKURA sits on the side of your screen, pays attention to what you're doing, remembers, and grows with you — without sending a single byte to a server you don't control.
src-tauri/ 20k lines of Rust (AI, memory, voice, perception, IPC)
src/ 15k lines of TypeScript + JSX (UI, stores, hooks)
docs/ Spec, slash commands, contribution notes
binaries/ whisper.cpp + Kokoro ONNX (optional voice)
public/ Live2D mao_pro + Cubism Core runtime
- 8-block dynamic prompt built per turn from mood, relationship, memory,
perception, and live personality sliders. See
src-tauri/src/ai/prompt.rs. - 12-tier relationship arc with level-gated voice, mascot, and unlock
messages. See
src-tauri/src/ai/relationship.rs. - 10-table SQLite memory with
sqlite-vecsemantic recall over user preferences. Seesrc-tauri/src/memory/. - Live2D mao_pro with 8 expressions and a 28-mood mapping
(
expressionForMoodinsrc/components/Live2D/Live2DCanvas.tsx). - 9-sense perception: foreground app, music metadata, mic input, idle timer, system battery, behavioral stress, screen vision opt-in, webcam opt-in, time-of-day. Background refresh every 30s.
- CPAL/WASAPI mic capture + whisper.cpp STT. No Python at runtime.
- Pure-Rust DXGI screen capture (single-frame primary monitor) +
vision captioning via
llama3.2-vision:11bthrough Ollama. - Open-Meteo weather in the status pill (no API key, free tier).
- Auto-updater wired to a GitHub release endpoint with a Tauri
pubkey check and
tauri signartifacts. - i18n for English / Japanese / French / Arabic (RTL aware). Live
langslash command. - 21 slash commands for diagnostics (
/sysinfo,/personality,/persona-test,/describe, …) and power-user actions (/export,/import,/reset,/quiet,/update, …). Seedocs/SLASH_COMMANDS.md. - CI + signed release workflow via GitHub Actions. See
.github/workflows/.
# Dev (hot reload, debug binary)
cd "sakura-app"
npm install
npm run tauri dev
# Production installer (NSIS + MSI in src-tauri\target\release\bundle\)
npm run tauri buildFor a signed release:
# One-time: generate a Tauri signing key
npx @tauri-apps/cli signer generate -w src-tauri/signing.key --ci
# Then either:
# - push a v* tag and let .github/workflows/release.yml sign + publish
# - or run locally:
pwsh scripts/release.ps1 -Version 0.6.0 -Notes "Kokoro port + auto-updater"Set the GitHub secrets:
TAURI_SIGNING_PRIVATE_KEY(contents ofsigning.key)TAURI_SIGNING_PRIVATE_KEY_PASSWORD
cd src-tauri
cargo test --lib # 23 unit tests
cargo test --test pure_logic # 15 integration tests
cargo test --test e2e_chat # 1 live-Ollama e2e (needs server)23 unit tests cover: prompt envelope extraction, level voice block,
personality block mapping, quiet-hours windowing, memory CRUD, store_fact
regression (the NOT NULL created_at bug), and 8 perception::apps::classify
categories + 5 weather WMO codes.
src-tauri/src/
├── lib.rs Tauri builder, plugin registration, command registry
├── app_state.rs AppState struct + Settings struct (BOM-safe JSON)
├── crash.rs Panic hook → data_dir/logs/crash.log
├── tray.rs System tray + right-click menu
├── window.rs Tauri window configuration
├── commands.rs 35+ #[tauri::command] IPC handlers + slash dispatcher
├── ollama/ Ollama HTTP client (chat streaming + vision caption)
├── voice/ STT/TTS subsystem (CPAL capture + whisper + SAPI TTS)
├── perception/ 9-sense perception engine
│ ├── screen.rs Foreground app probe (Win32)
│ ├── screen_capture.rs DXGI Desktop Duplication single-frame capture
│ ├── mic_capture.rs cpal/WASAPI mic capture + WAV writer
│ ├── audio.rs Music metadata probe
│ ├── apps.rs App classifier (game / ide / browser / chat / cinema)
│ ├── idle.rs Idle timer
│ ├── music.rs Music metadata (SMTC)
│ ├── webcam.rs Webcam presence (opt-in)
│ ├── system.rs System refresh (battery, time-of-day)
│ └── behavioral.rs Stress heuristic
├── memory/ SQLite memory store (10 tables + sqlite-vec)
├── ai/ 8-block prompt + brain
│ ├── prompt.rs The 8-block system prompt builder
│ ├── relationship.rs 12-level relationship arc
│ ├── mood.rs 28-emotion Mood state machine
│ ├── modes.rs 6 companion modes (gaming, cinema, focus, …)
│ ├── proactive.rs Proactive message engine (gated by quiet hours)
│ ├── killer_moment.rs "I kept thinking about you" boot greeting
│ └── traits.rs Trait deltas
└── settings (in app_state.rs) settings.json persistence
src/
├── App.tsx Root layout
├── i18n/translations.ts en/ja/fr/ar copy
├── components/
│ ├── OnboardingFlow.tsx 4-step onboarding with SVG illustrations
│ ├── OnboardingArt.tsx Inline SVG art (4 scenes)
│ ├── Icons.tsx 16 inline SVG icons
│ ├── Chat/ Chat input, history, bubble, message list
│ ├── Live2D/ mao_pro renderer + mouth param driver
│ ├── MoodPanel.tsx 28-emotion grid
│ ├── MemoryViewer.tsx Stored fact list with filter
│ ├── ProactiveToast.tsx Proactive message toast
│ ├── Settings/ Full settings panel
│ └── Overlays/ StatusPill, ModeIndicator, LevelChip,
│ LevelXPBar, PrivacyRing, UpdateBanner
├── stores/ zustand stores
│ ├── chatStore.ts Chat state + slash push
│ ├── settingsStore.ts Settings + hydrate/patch
│ ├── moodStore.ts 28-emotion Mood + delta
│ └── relationshipStore.ts Level/XP state
├── hooks/
│ ├── useTtsAudio.ts TTS auto-speak + body class hooks
│ ├── usePoke.ts Click-to-react reaction pool
│ └── useCharacterDrag.ts Drag-the-character with edge-snap
└── styles/globals.css 18KB CielChan-style overlay styles
Type any of these in the chat input. Full reference in
docs/SLASH_COMMANDS.md.
| Command | What it does |
|---|---|
/help |
List all commands. |
/graphify [args] |
Run the graphify CLI; falls back to graphify-out/graph.json. |
/capture |
Single-frame primary monitor via DXGI. |
/describe |
Capture + vision captioning via llama3.2-vision:11b. |
/export [path] / /import <path> / /reset |
Settings lifecycle. |
/version / /sysinfo / /personality / /persona-test |
Diagnostics. |
/mood <name> / /preset [name] / /level <n> |
Force states. |
/memory / /crash |
Memory + diagnostics. |
/quiet [on|off|22-7] / /city <name> / /lang <code> |
Environment. |
/update / /kill |
Lifecycle. |
See RUN.md for the operator's quick-reference. See
docs/SLASH_COMMANDS.md for the full slash
command reference.