Appearance
Cluster Preferences
Hive can store the app's local user preferences (theme mode, theme preset, custom CSS, and any other hive-* localStorage key) on the connected daemon and share them across every client that joins the cluster.
By default every client keeps preferences in its own localStorage - this feature is opt-in: nothing is uploaded until the user clicks Save to cluster, and the cluster blob is never auto-applied to a client until they click Pull from cluster.
Where to configure
Settings → Cluster Preferences. The card shows:
- Cluster value updated - the timestamp on the blob the connected daemon currently holds, refreshed automatically on (re)connect.
- Save to cluster - snapshots every
hive-*key in the running client'slocalStorageand pushes the blob to the daemon. The daemon persists it tocluster_preferences.jsonand, in cluster mode, broadcasts it to every peer. - Pull from cluster - fetches the latest blob from the daemon, replaces every
hive-*key inlocalStorage(keys not in the blob are removed), and reloads the window so module-level composables re-read their state. - Refresh - re-fetches the cluster timestamp without touching local state.
The buttons are disabled when no daemon is connected.
What gets synced
Everything the app writes under the hive- localStorage prefix, which today includes:
hive-theme- light/dark mode toggle.hive-theme-preset- selected appearance preset (orcustom).hive-theme-custom-css- the user's custom CSS overrides.
Anything else the app adds under that prefix is picked up automatically.
Keys outside the hive- prefix are intentionally not synced. The remote-update settings stored at hive.remoteUpdate.settings.v1 are a notable example: those have their own daemon-side persistence in config.toml and are replicated separately via PeerMessage::SyncRemoteUpdateConfig.
How it's stored and replicated
- The daemon keeps an in-memory
ClusterPreferences { values, updated_at }blob plus a JSON file at<config_dir>/cluster_preferences.json. The file is restored on daemon start, so a restart preserves the last-written value. updated_atis Unix milliseconds, stamped server-side atSettime so a client with a skewed clock cannot poison ordering.- In cluster mode, every
Setis broadcast asPeerMessage::SyncClusterPreferences. Receivers apply the incoming blob only when itsupdated_atis strictly newer than their local copy - last-writer-wins on the whole blob. - Every connected client receives the new blob as
ServerMessage::ClusterPreferences, but the desktop app does not auto-apply it; the user must click Pull from cluster to overwrite local state.
Conflict resolution
Whole-blob last-writer-wins. A second client clicking Save to cluster right after the first one wins because the daemon stamps a newer updated_at. There is no per-key merge; if you push, you push everything your client has under hive-*.
Wire protocol
ClientMessage::GetClusterPreferences→ServerMessage::ClusterPreferences.ClientMessage::SetClusterPreferences { preferences }→ daemon persists, broadcasts to peers, and replies/broadcastsServerMessage::ClusterPreferences.PeerMessage::SyncClusterPreferences { preferences }- peer-to-peer replication of the blob (LWW onupdated_at).