A native desktop GUI for interacting with the Lemonade Server.
This app provides a native desktop experience for managing models and chatting with LLMs running on lemond. It connects to the server via HTTP API and offers a modern, resizable panel-based interface.
It is built with Tauri v2, which embeds the operating system’s native webview — WebView2 on Windows, WKWebView on macOS, and webkit2gtk on Linux — instead of bundling Chromium. The renderer is a standard React 19 + TypeScript application served by webpack and shared with the browser-only src/web-app/ build.
Key Features:
lemonade:// deep-link protocol handlerlemond server on the local machineThe Tauri desktop app is a thin client for a separately-running lemond server. A single lemond can be driven by multiple clients at once, including clients running on other machines.
Consequences that callers of this code need to know about:
~/.cache/lemonade/app_settings.json on the client, owned by the Rust host (src-tauri/src/settings.rs). It is never stored or proxied through lemond, because two clients against the same server must be able to hold different preferences.lemond’s lifecycle. The server is started independently — on Windows by LemonadeServer.exe (auto-started via the startup folder, tray icon always visible), on Linux/macOS by the user or a service. The Tauri app is opened on demand and must not add itself to autostart, spawn lemond as a subprocess, or assume lemond is on the same machine.beacon.rs listens for a UDP broadcast emitted by a local lemond to auto-populate the base URL. For remote-server use, the user sets baseURL + apiKey in settings and the client talks to that endpoint directly.src/app/
├── package.json # Webpack + Tauri CLI devDependencies
├── webpack.config.js # Bundler config (target: web)
├── tsconfig.json # TypeScript config
├── assets/ # Icons, logos
│
├── src/
│ ├── global.d.ts # window.api type declaration
│ └── renderer/ # React UI (TypeScript)
│ ├── index.tsx # Renderer entry (imports tauriShim first)
│ ├── tauriShim.ts # Installs window.api → Tauri invoke() bridge
│ ├── App.tsx # Root component, layout orchestration
│ ├── TitleBar.tsx # Custom window controls
│ ├── ModelManager.tsx # Model list and actions
│ ├── ChatWindow.tsx # LLM chat interface
│ ├── LogsWindow.tsx # Server log viewer
│ ├── SettingsPanel.tsx # Inference parameters
│ └── utils/ # API helpers and config
│
└── src-tauri/ # Rust host (Tauri backend)
├── Cargo.toml # Rust dependencies
├── tauri.conf.json # Window config, bundle settings, plugins
├── build.rs # tauri_build::build()
├── capabilities/default.json # Tauri permissions
├── icons/ # Generated app icons (32x32/128x128/ico/icns)
└── src/
├── main.rs # Entry point (binary)
├── lib.rs # Tauri builder, plugin wiring, deep-link routing
├── commands.rs # #[tauri::command] handlers (window, settings, port)
├── events.rs # Tauri event channel name constants
├── settings.rs # app_settings.json read/write + sanitize
├── beacon.rs # UDP beacon listener (single bound socket)
├── tray_launcher.rs # macOS-only tray auto-start helper
└── webview_shim.rs # Per-platform webview hooks (mic permission, link interception)
/health,/system-stats, and/system-infoare NOT proxied through Rust. The renderer fetches them directly viaserverConfig.fetch(...); seeStatusBar.tsxandAboutModal.tsx.
┌────────────────────────────────────────────────┐
│ Tauri Rust Host (src-tauri/) │
│ Window mgmt, IPC commands, background tasks │
│ UDP beacon listener, settings file I/O │
├────────────────────────────────────────────────┤
│ tauriShim.ts (installs window.api in webview) │
│ Maps window.api.* → invoke() / listen() │
├────────────────────────────────────────────────┤
│ React Renderer (TypeScript) │
│ Source lives in src/app/src/; the web-app │
│ build (src/web-app/) reuses it via webpack │
│ relative entry/template paths — no symlinks. │
├────────────────────────────────────────────────┤
│ HTTP API → lemond (C++ server) │
└────────────────────────────────────────────────┘
libwebkit2gtk-4.1-dev, libsoup-3.0-dev, libjavascriptcoregtk-4.1-dev, librsvg2-dev, libayatana-appindicator3-dev — the repo’s setup.sh script checks for these and prompts to install them.cd src/app
# Install webpack + Tauri CLI dependencies
npm ci
# Run in dev mode (opens a window, hot-reloads webpack)
npm run dev
# Production build (single binary, no OS bundles)
npm run build -- --no-bundle
# Production build with platform bundles (macOS .app, Linux .deb/.rpm, Windows MSI/NSIS)
npm run build
The preferred path for shipping is through CMake, which stages the Tauri output alongside the rest of the server:
cmake --build --preset default --target tauri-app # Linux / macOS
cmake --build --preset windows --target tauri-app # Windows
npm run dev # Tauri dev mode (window + hot-reload)
npm run build # Tauri production build
npm run tauri icon <path> # Regenerate icons from a source image
npm run build:renderer # Build just the renderer (webpack, dev mode)
npm run build:renderer:prod # Build just the renderer (webpack, production)
npm run watch:renderer # Webpack watch mode for the renderer only
Unit tests live alongside the Rust modules and cover settings sanitization, beacon parsing, and deep-link URL parsing:
cargo test --manifest-path src-tauri/Cargo.toml