Appearance
Appearance & Theming
The Hive desktop and Android apps support full theming of the UI chrome, embedded terminals, and both CodeMirror-based editors via CSS custom properties.
Navigation profiles and density
Open Customize navigation from the sidebar footer or press F1 and run Customize navigation. The dialog controls the feature destinations shown in both the desktop sidebar and mobile menu:
- Full shows every feature destination.
- Simple shows only Chats and Notes.
- Custom lets you show or hide each feature destination and move visible items up or down. Changing an item while Full or Simple is selected switches the profile to Custom.
- Comfortable and Compact change the vertical spacing between feature destinations without changing which ones are visible.
The selected profile, custom order, visibility, and density are stored on the current device. Reset restores Full navigation, the default item order, and Comfortable density.
Connection, Settings, Documentation, and Customize navigation remain available as permanent footer escape hatches even when feature destinations are hidden. The footer also keeps Cluster, Logs, and Sessions available. On mobile, the same configured feature list scrolls above a touch-sized footer, so Simple and Custom profiles never hide the controls needed to restore Full navigation.
The F1 command palette also provides Use Simple navigation, Use Full navigation, Customize navigation, and Open Hive documentation. The documentation action opens the public Hive docs and is also available directly from the desktop and mobile menus.
Where to configure
Open Settings → Appearance. The card contains:
- Preset picker - pick a built-in theme. Each theme is a complete light or dark look; selecting one also sets the app's light/dark mode, so there is no separate light/dark toggle. Built-ins: Default Dark/Light, Solarized Dark/Light, Dracula Dark/Light, Catppuccin Mocha (dark), Catppuccin Latte (light), Nord (dark), Tokyo Night (dark), and Custom.
- Mode selector - shown only for the Custom theme; chooses whether your custom CSS renders as a light or dark theme.
- CSS Variables editor - a CodeMirror editor showing the active theme. Read-only while a built-in preset is selected; pick Edit as Custom to fork the active CSS into the Custom slot and start editing.
- Reset - drops back to the Default theme (matching your OS light/dark preference) and clears any custom CSS.
Edits in Custom mode apply live to the running app and are persisted in the device's localStorage. Each theme is a single :root { ... } block; the Custom theme's Mode selector decides whether it renders light or dark.
OpenRouter API key
The Appearance tab also contains OpenRouter API for the connected node. You can jump directly to it with F1 > Configure OpenRouter API key. The card shows whether a key is configured and whether its source is the node's private config or daemon environment, but never displays or returns the saved key.
Saving a key creates or replaces [openrouter].api_key. Clear stored key removes that config value. An OPENROUTER_API_KEY supplied by the daemon environment remains effective and cannot be cleared from the app. Key changes apply to the next native OpenRouter turn without restarting the daemon. See Native OpenRouter API for setup and runtime details.
Available variables
UI chrome:
| Variable | Purpose |
|---|---|
--background / --foreground | App body |
--card / --card-foreground | Card surfaces |
--popover / --popover-foreground | Popovers, dropdowns |
--primary / --primary-foreground | Primary action buttons |
--secondary / --secondary-foreground | Secondary surfaces |
--muted / --muted-foreground | Muted text and surfaces |
--accent / --accent-foreground | Hover / selected states |
--destructive | Destructive actions |
--border / --input / --ring | Borders, inputs, focus rings |
--sidebar* | Sidebar surface, foreground, primary, accent, border, ring |
Terminal:
| Variable | Purpose |
|---|---|
--terminal-bg / --terminal-fg | Terminal background / default text |
--terminal-cursor | Cursor color |
--terminal-selection-bg | Mouse selection background |
--terminal-black / --terminal-bright-black | ANSI 0 / 8 |
--terminal-white / --terminal-bright-white | ANSI 7 / 15 |
--terminal-font-family | Terminal font stack |
ANSI colors 1-6 (red, green, yellow, blue, magenta, cyan) are not driven by CSS variables; they come from a fixed light/dark palette in useTerminalManager.ts.
Editor:
| Variable | Purpose |
|---|---|
--editor-bg / --editor-foreground | Editor canvas and default text |
--editor-gutter-bg / --editor-gutter-fg | Line-number gutter colors |
--editor-gutter-active-fg | Active line number |
--editor-border | Gutter / panel borders |
--editor-selection-bg | Text selection |
--editor-active-line-bg / --editor-active-line-gutter-bg | Active line highlight |
--editor-cursor | Caret color |
--editor-search-match-* | Search result highlight fill / border / selected match |
--editor-bracket-match-* | Matching bracket highlight fill / border |
Example: minimal custom theme
A custom theme is a single :root block. Set the Mode selector to light or dark to tell the app which ANSI palette and dark: utilities to use.
css
:root {
--background: #1c1b18;
--foreground: #e6e1d6;
--primary: #d98a52;
--editor-bg: #24221f;
--terminal-bg: #1c1b18;
--terminal-fg: #e6e1d6;
}Notes
- Themes are device-local by default. Use Settings → Sync preferences with cluster → Save to cluster to push the current theme (and every other
hive-*localStorage preference) to the connected daemon; any client that later connects to that cluster can pull the same blob with Pull from cluster. Sync is opt-in per action: editing locally never touches the cluster value. - The base styles in
crates/clusto-app/src/style.cssdefine the defaults; your overrides cascade on top of those, so you only need to declare the variables you want to change. - Already-open terminals and editors refresh their colors live when the theme changes; no reopen / reattach needed.
Resizable panels
Every side panel can be resized by dragging the thin handle on its border, the same gesture used between terminal panes. On desktop (md+) only - on phone widths these panels are full-width swappable panes or sheets, so the handle is hidden. Each panel remembers its width across restarts in localStorage:
| Panel | Page | Range | Key |
|---|---|---|---|
| Main navigation (left) | all pages | 180-420 px | hive-nav-width |
| Right sidebar (Files/Git/Run/Commands) | Workspace | 220-560 px | hive-right-sidebar-width |
| Notes file tree (left) | Notes | 180-480 px | hive-notes-tree-width |
| Notes editor split divider | Notes (split mode) | 20-80% | hive-notes-editor-split |
The shared drag logic lives in src/composables/useResizablePanel.ts; the handle visual is src/components/common/ResizeHandle.vue. The collapsed main nav keeps its fixed w-12 rail and is not resizable until re-expanded.
Cluster-shared preferences
The daemon persists the synced blob in cluster_preferences.json next to its config.toml and broadcasts updates to its cluster peers via PeerMessage::SyncClusterPreferences. Conflict resolution is last-writer-wins on the whole blob, ordered by a server-side updated_at timestamp - so a slow peer broadcast can never clobber a fresher local write. Wire protocol: ClientMessage::GetClusterPreferences / SetClusterPreferences → ServerMessage::ClusterPreferences { preferences }.