# 11 — Desktop App (Kotlin + Compose Multiplatform) The desktop app is **the Android app, tweaked for a big screen**. It reuses the entire `app/shared` module (protocol, network, repositories, state, most UI) and only adds desktop platform services + a wider default layout. ## 11.1 What's shared vs desktop-specific | Layer | Shared (commonMain) | Desktop-specific (desktopMain) | |---|---|---| | Protocol / WS client | ✅ | — | | Repositories / state | ✅ | — | | Most Compose UI | ✅ | layout tweaks, keyboard shortcuts | | Push | — | **tray icon + OS notifications** (no FCM) | | Media playback | `MediaPlayer` interface | **desktop player** actual | | File picker | `MediaPicker` interface | **desktop file dialog** actual | | Window | — | resizable window, always-on-top, global hotkey | | Secure store | `SecureStore` interface | keyring / encrypted file actual | ## 11.2 `desktopMain` platform services - **Push → tray + OS notifications.** Desktop is assumed reachable (persistent WS), so no FCM. A **system tray icon** shows connection state + unread count; OS notifications (Java Desktop / `SystemTray` + a cross-platform notifier) fire for background chats / approvals / cron. Clicking focuses the window and deep-links to the chat. - **Media playback → `MediaPlayer` actual.** ExoPlayer is Android-only. Desktop uses a `libmpv`/`mpv`-backed Compose surface for video (and audio), with a WebView-based fallback if `mpv` isn't available. Same `MediaPlayer` interface the Android `ExoPlayer` actual implements, so UI code is identical. - **File picker → `MediaPicker` actual.** A native file dialog (Compose Desktop `FileChooser` / AWT `JFileChooser`) returning local file paths, then the same `media.upload` chunked path. - **Window.** Resizable, remembers size/position, optional always-on-top, a global hotkey to focus/show. Minimize-to-tray option. - **Secure store → `SecureStore` actual.** OS keychain (macOS Keychain, Linux Secret Service / encrypted file, Windows Credential Manager) or an encrypted file for the token + pinned cert. ## 11.3 Layout (big-screen tweaks) - **Two-pane is the default** (persistent left channel rail + chat), since there is width. Single-pane still available via the same toggle. - **Wider chat column** with comfortable max line length; optional **third pane** (inspector: session info, model, tokens, tool detail, channel settings). - **Larger type scale** and spacing for desktop; hover states; mouse + keyboard first. - **Keyboard shortcuts:** - `/` focus the composer and open the command menu. - `Ctrl/Cmd+K` command palette (all slash commands + actions). - `Ctrl/Cmd+N` new channel; `Ctrl/Cmd+T` new thread. - `Ctrl/Cmd+F` search (with the all/this-chat scope toggle). - `↑/↓` navigate channel list; `Enter` open. - `Esc` close sheet/dialog (one cancel gesture does exactly one thing). - **Multi-window (stretch):** open a channel in a separate window / pop-out. ## 11.4 Distribution - **Compose Desktop** → native binaries via **jpackage** (or a plain app image): Linux (.deb/.AppImage), macOS (.dmg), Windows (.msi/.exe). - Bundles the JRE. Auto-update is a stretch goal (v1: manual download). - The desktop app connects to the **same** gateway WS server as the phone (the user's home server / Tailscale). It does **not** spawn its own backend (unlike hermes's existing Electron desktop, which spawns `hermes serve`) — our desktop is a pure client of the messaging gateway, matching the Android app. ## 11.5 Parity checklist (same functionality as Android) - [ ] Streaming, reasoning block, tool cards (3-level verbosity), commentary. - [ ] Channels + threads + new channel + cron target. - [ ] Search (all / this-chat). - [ ] Media attach + live playback (via desktop player). - [ ] Slash command menu + autocomplete + interactive pickers. - [ ] Push (tray + OS notifications) + outbox/sync. - [ ] Pairing/Connect screen (URL + token, WSS cert pin).