Skip to content

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's localStorage and pushes the blob to the daemon. The daemon persists it to cluster_preferences.json and, in cluster mode, broadcasts it to every peer.
  • Pull from cluster - fetches the latest blob from the daemon, replaces every hive-* key in localStorage (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 (or custom).
  • 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_at is Unix milliseconds, stamped server-side at Set time so a client with a skewed clock cannot poison ordering.
  • In cluster mode, every Set is broadcast as PeerMessage::SyncClusterPreferences. Receivers apply the incoming blob only when its updated_at is 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::GetClusterPreferencesServerMessage::ClusterPreferences.
  • ClientMessage::SetClusterPreferences { preferences } → daemon persists, broadcasts to peers, and replies/broadcasts ServerMessage::ClusterPreferences.
  • PeerMessage::SyncClusterPreferences { preferences } - peer-to-peer replication of the blob (LWW on updated_at).

Hive - remote AI coding agents over WebSocket.