Cloud support operator guide¶
The optional plugins.cloud_support service backs the OSS console Help entry and
lazy Lit widget on the public Cloud home, pricing and signup pages. It is disabled
until instance configuration and operator validation succeed. Self-hosted public
pages do not load the widget by default. This change does not install a provider
app, send a real operator notification, merge, or deploy anything.
Configure the service¶
Apply core database migrations and use the standard EE plugin installation, which
discovers cloud_support under preloop.plugins.proprietary. Proprietary plugin
loading and RBAC must be enabled. Background outbox and operator listener tasks
run with the plugin; database leases coordinate API replicas. Set these instance
variables, never tenant chat-connection credentials:
| Variable | Purpose |
|---|---|
CLOUD_SUPPORT_ORIGIN |
Mattermost HTTPS origin |
CLOUD_SUPPORT_BOT_TOKEN |
Dedicated bot access token secret |
CLOUD_SUPPORT_BOT_USER_ID |
Instance operator bot identity |
CLOUD_SUPPORT_TEAM_ID |
Private operator team's ID |
CLOUD_SUPPORT_CHANNEL_ID |
Private channel's ID |
CLOUD_SUPPORT_OPERATOR_ID |
Authorized human Mattermost user ID |
CLOUD_SUPPORT_CONSOLE_USER_ID |
Authorized active Preloop console user UUID |
CLOUD_SUPPORT_PUBLIC_ORIGIN |
Canonical Cloud HTTPS origin for operator links |
CLOUD_SUPPORT_OPERATOR_NAME |
Visitor-facing human name, for example Support |
Startup verifies bot identity, the active console operator, the Mattermost human,
private channel/team boundaries, and both users' team/channel membership. Changes
require restarting the service. Mattermost traffic uses the core HTTPS/DNS-pinning
policy; allow a self-hosted private subnet with MODEL_ENDPOINT_ALLOWED_CIDRS only
when needed. System trust/SSL_CERT_FILE supports a private CA. Secrets are not
included in feature flags, provider errors, analytics, or browser responses.
Documentation and independent support budget¶
Retrieval uses only a committed build snapshot, with source paths and SHA-256 checksums. Rebuild it from the pinned OSS checkout and public plan/brand sources:
The index reads public docs/overview/installation plus current build pricing and self-hosted terms. It never fetches visitor URLs or indexes tenant audit data. Answers return real documentation/pricing citations; unsupported questions offer human help. With no explicit support model configuration, answers are cited excerpts. Pricing snapshots describe the build and direct users to current terms.
For model-written documentation answers, configure a dedicated Preloop-funded service account/model/key, separate from customers' defaults, BYOK and credits:
CLOUD_SUPPORT_FUNDING_ACCOUNT_ID,CLOUD_SUPPORT_MODEL_ID, andCLOUD_SUPPORT_GATEWAY_KEYexplicitly select the service account/model/key.CLOUD_SUPPORT_DAILY_MICROUSDdefaults to 2,000,000 ($2/day).CLOUD_SUPPORT_REQUEST_MICROUSDdefaults to 20,000 ($0.02/request).
Known pricing is required. A conservative maximum-input/output tariff reservation is atomic across replicas; unknown pricing, caps, or unavailable funding fall back to excerpts without a model call. There is one model round, no MCP tools, at most three bounded source excerpts, and at most 700 output tokens. Reservations remain charged after uncertain calls; the existing gateway meters actual usage against the support service account. In-flight model HTTP requests are cancelled promptly when ownership changes; generation checks still fence staged responses and sends. Configure the dedicated service account's gateway budgets as an additional spend control. Human replies and handoff work without model credit.
Inspect my setup is an explicit signed-in action. It calls existing authorized read APIs and forwards only bounded chat setup/worker/link statuses and visible model/default-configuration counts. It never authorizes by contact email and never returns tokens, external identity IDs, raw audit history, or unrestricted tools.
Mattermost operation¶
Every choice or user message creates/updates a durable conversation and ordered private operator thread. Impressions and dismissals create aggregate counters only. The first post contains source-page context, the user's verbatim question, and an authenticated console link. Follow-ups stay in that thread; assistant output is included after delivery to the visitor. Visitor-controlled mentions are neutralized.
In the thread, the configured human can send:
| Command | Effect |
|---|---|
!takeover |
Claim human ownership and fence pending/in-flight assistant output |
| Any normal thread reply after takeover | Deliver that human reply to the visitor |
!resume |
Explicitly return to the assistant |
!close |
Close the conversation |
!reopen |
Explicitly reopen a closed conversation with human ownership |
The console link also offers Take over, Return to assistant, Close and
Reopen using authenticated endpoints restricted to the configured console user.
No unsigned Mattermost callback's user_id is trusted. Socket events are hints:
canonical posts and current operator/team/channel membership establish authority.
Wrong users/channels/threads, bot/system echoes and duplicate posts are ignored.
Replies before takeover are not relayed. An explicit visitor human request is
highlighted and immediately fences assistant work, but does not promise an
immediate human response. Optional reply contact is used only for requested
offline follow-up, separately from account authorization.
The browser shows the owner/status and reconnects using persisted history. A scoped, unguessable session credential grants access to one anonymous conversation. Account conversations additionally require the original active account/user. The browser keeps this scoped credential in session storage, clears it on identity changes, and does not persist provider credentials.
Delivery and recovery¶
Notification claims serialize each conversation's messages, preserving one root. Definitive provider rate-limit rejections retry with bounded backoff; other explicit rejections fail visibly. The authenticated operator console can retry a definitively failed delivery after its cause is corrected; later notifications remain ordered behind it. A timeout, interrupted send or ambiguous provider failure becomes uncertain. The worker reconciles the bounded latest channel history using a server-owned delivery marker, author and channel before marking it delivered. It never blindly reposts an ambiguous send. Inspect the console conversation's delivery jobs and the Mattermost channel if a marker is outside that bounded history; do not manually retry until the prior outcome is established.
The operator socket uses a leased durable checkpoint and up to 300 posts for reconnect recovery. An oversized gap stops automatic recovery and leaves operator connectivity unavailable for inspection; it is not silently skipped. Browser history remains durable and available during operator-socket outages; connectivity is reported separately from the configured service availability. The assistant cannot publish an answer for a prior ownership generation after takeover. Transactions cover ownership and claims, never inference or provider network calls.
Public create/message/inspection/aggregate/history routes have bounded per-peer quotas
(history allows 3,600 polls per hour per peer),
conversation histories are capped, and retries use stable client event IDs. Behind
a reverse proxy, configure the ASGI trusted proxy handling so its peer address
reflects your intended quota boundary; arbitrary forwarded headers are not trusted.
Conversations/messages/contact/outbox are deleted after
CLOUD_SUPPORT_RETENTION_DAYS (default 30, allowed 1–90). Aggregate counters expire
separately and contain no conversation/contact/chat content.
Optional prompt experiment¶
CLOUD_SUPPORT_PROACTIVE=true enables a session-level quiet-launcher versus choice
experiment. The small prompt requires at least 30 seconds of active-page dwell and
12 seconds idle (CLOUD_SUPPORT_DWELL_MS, CLOUD_SUPPORT_IDLE_MS can increase
these thresholds). Those values are configurable starting points, not measured
optima. Hidden tabs, focused forms/typing, prior dismissal, conversion and a prior
prompt suppress it. No full chat auto-opens; free text is always available and
there is no email gate. Initial choices are single-select and page-specific.
Only finite impression/engagement/dismissal/activation dimensions are aggregated. Use them with activation/completed-integration outcomes and answer-quality, latency/cost/support-delivery measures. No chat content, credentials, IPs or contact information belong in experiment analytics.
Verification limits¶
Local synthetic PostgreSQL, TLS HTTP/WebSocket provider and browser fixtures cover
authorization, deduplication, reconnection, leases, takeover/resume and delivery
races. Live Mattermost/Slack/Discord installation and production load acceptance
require a separate authorized environment; they are not claimed as verified here.
Slack's native agent_view behavior and Mattermost Agents model/MCP integration
are optional surfaces and are not implemented or required by this service.