Support Chat
In-app chat for Omniscio users to contact support directly from the toolbar. User mode (default): A chat icon in the toolbar opens a floating panel (bottom-right). Users enter a display name on first use, then send messages that reach the operator's inbox.
What it is
In-app chat for Omniscio users to contact support directly from the toolbar.
Where to find it
The chat icon in the toolbar opens a floating panel at the bottom-right. Operator mode is a setting rather than a separate screen.
How it behaves
How It Works
- User mode (default): A chat icon in the toolbar opens a floating panel (bottom-right). Users enter a display name on first use, then send messages that reach the operator's inbox.
- Operator mode (
supportChatOperator: truein settings): The operator sees all conversations as inbox items and can reply from the same floating panel or the inbox.
Scope and limits
- Reachable from the localhost CLI — mark-read is the one exception. The control server (
127.0.0.1:19519) reaches Support Chat:GET /support-chat/install-id(this install's own conversation key),GET /support-chat/messages?conversationId=(a conversation's messages — a non-operator may read only its own and gets403otherwise; an operator reads any),GET /support-chat/conversations(operator only) andPOST /support-chat/send(applies immediately; a non-operator send is pinned to its own conversation). The family is gated onsupportChatEnabledand answers403when Support Chat is switched off. The one command that stays in-app isSUPPORT_CHAT_MARK_READ— it clears a conversation's unread cursor and is a deliberatefeature-scoped-surfaceexemption in the CLI-parity manifest (it is Support-Chat-specific, not the generic inbox mark-read route).
Key Files
src/shared/support-chat-types.ts— shared typessrc/main/services/support-chat-service.ts— user path (supportChatrelay: send / mark-read / poll) + operator path (operatorConsolerelay: list / getMessages / mark-read / send, plus a ~15s conversation poll); NO admin SDK;sendMessage/markRead/getMessagessplit bysender/readersrc/main/services/support-chat/support-chat-relay-client.ts— USER relay client (relaySendMessage/relayMarkRead/relayPoll)src/main/services/operator-console/operator-console-client.ts— OPERATOR relay client (callOperatorConsoleFn, admin-authed)firebase/functions/src/support-chat-relay.ts— thesupportChatrelay Cloud Function (send/markRead/poll)firebase/functions/src/operator-console.ts— theoperatorConsoleCloud Function (broadcast + support-chat operator actions);firebase/functions/src/operator-console-support-chat-validate.ts— support-chat action validatorssrc/main/ipc/support-chat-handlers.ts— IPC handlerssrc/renderer/src/stores/support-chat-store.ts— Zustand storesrc/renderer/src/features/support-chat/SupportChatPanel.tsx— floating panel UI
For agents
Architecture
- Backend: Firebase Firestore (the shares project),
support_conversations/{installId}/messages/{auto-id}layout. - Keying: Each install gets a stable
installId(auto-generated, persisted in config.json). No Firebase Auth required. - User path — no shipped admin key: a user's send, mark-read, AND message reads all go through the
supportChatrelay Cloud Function (ship-in-app deterrent token; the Firestore admin credential lives server-side). A packaged build's firebase-adminonSnapshotfails7 PERMISSION_DENIED(the share-mirror packaged-admin bug), so the user READ path polls the relay'spollop about every 15s (relayPoll) instead of a real-time listener; the panel also refreshes instantly on open. Delivery + notifications are unchanged (sameSUPPORT_CHAT_MESSAGE_RECEIVEDpush, notify only on a genuinely new reply). Locked by the user-write-relay contract. - Operator path — no shipped admin key: the operator's list / read / reply / mark-read run server-side through the admin-authed
operatorConsolerelay Cloud Function — gated by the operator's VERIFIED Firebase ID token + an admin role (authenticate+requireAdmin), strictly stronger than the old client-side check. The live console view POLLS the relay'ssupportChat.listConversationsaction about every 15s (replacing the oldonSnapshotover the wholesupport_conversationscollection). Delivery + notifications are unchanged (sameSUPPORT_CHAT_CONVERSATIONS_CHANGEDpush; one notify per genuinely-new unread reply). Locked by the operator-console-relay contract. - Inbox source: Operator-only. Unread conversations appear as
support-chatinbox items.
Settings
| Setting | Type | Default | Description |
|---|---|---|---|
supportChatEnabled |
boolean | true |
Master toggle — hides toolbar icon and panel when off |
supportChatOperator |
boolean | false |
Operator mode — see all conversations in inbox |
supportChatUserName |
string | '' |
Display name shown on messages (required before first send) |
IPC Channels
| Channel | Direction | Purpose |
|---|---|---|
SUPPORT_CHAT_LIST_CONVERSATIONS |
request-response | List all conversations (operator only) |
SUPPORT_CHAT_GET_MESSAGES |
request-response | Get messages for a conversation |
SUPPORT_CHAT_SEND |
request-response | Send a message |
SUPPORT_CHAT_GET_INSTALL_ID |
request-response | Get this install's unique ID |
SUPPORT_CHAT_MARK_READ |
request-response | Mark conversation as read |
SUPPORT_CHAT_MESSAGE_RECEIVED |
push (Main->Renderer) | New message notification |
SUPPORT_CHAT_CONVERSATIONS_CHANGED |
push (Main->Renderer) | Conversation list changed |
Related
- inbox-overview.md — where operator mode routes conversations.
- report-conversations.md — filing a bug or a feature request, a different route into the same team.
Last verified 2026-10-01