Chat connections¶
Ask Preloop about agents and spend, receive private approval notices, and send explicit notes or commands using your existing Preloop permissions. A team administrator connects the bot; each person links their own account. Shared bot credentials never grant another person's permissions.
Before starting¶
Run database migrations and the separate durable chat worker:
For Helm deployments, enable the optional worker in your deployment values:
This creates a separate -chat-worker Deployment running the command above.
The sync worker pools do not process chat jobs. The chat worker shares the API's
image, database, signing/encryption secrets, NATS connection, and operator
extraEnv, extraEnvFrom, extraVolumes, and extraVolumeMounts. If you supply
an encryption key or provider CA through those hooks, apply the same settings to
both processes. Run migrations before starting the worker. See the
Helm chart guide.
Set PRELOOP_URL to your externally reachable HTTPS origin before setting up
Slack or Discord. Provider callbacks cannot use a localhost or placeholder URL.
Configure encryption for stored credentials. Setup secrets live in encrypted,
actor/account-bound drafts for 30 minutes and are never stored in the browser.
The connection ID reserves its final callback before installation. Expired drafts
must be restarted. Management permissions are checked again when finishing.
Open Settings → Chat connections → Add connection, choose the service, and enter its bot credentials. Preloop discovers identity and named workspaces; there are no bot user IDs in the normal form. One workspace selects automatically; choose a name when there are several. A custom connection name is optional under Advanced settings. After saving, distinguish Configured, Worker ready, Provider event received, and Your account linked. Configuration alone does not mean a worker or provider callback has connected.
Mattermost setup¶
- Create a Mattermost bot account and copy its bot access token secret. A Token ID is not a credential. Do not use a human or system-admin token.
- Add the bot to the team whose members may use Preloop. In Mattermost, open that team's menu → Invite People → Invite Member, find the bot in Add or Invite People, and select Invite Members. Bot accounts can be invited using this flow; see Mattermost's bot account instructions. If invitations are restricted, ask an administrator to open System Console → User Management → Teams, select the team, then Members → Add Members, select the bot, and Add → Save. See the official team membership administration guide.
- Enter the server's HTTPS origin (for example
https://chat.example.com) and the token. Preloop verifies/api/v4/users/meand lists that bot's teams by display name. A verified bot with no team memberships is a valid incomplete setup: Finish stays disabled and the wizard shows its@usernameand invitation instructions. Add that bot to a team, return to the same wizard, and select Refresh installation. Refresh reuses the encrypted draft and token, including after a temporary provider error; it does not extend the 30-minute expiry. Once one team appears it selects automatically; choose explicitly if several appear. Do not create a new token or give the bot administrator privileges to solve missing membership. - Select the team and finish. The default is a bot WebSocket listener for direct
messages: no
/preloopcommand or slash-command token is required. - Select Link my account, then privately message the bot with
link CODE. Keep the code private. Refresh the connection to see the linked state.
Advanced team lookup accepts the team name or normal team URL, such as
https://chat.example.com/engineering. It resolves the name through the API and
checks bot membership. Invite links, channel URLs, and guessed IDs are rejected.
Saving the connection does not start a worker. Check Worker ready and Provider event received in the connection, then link your account and send a fresh DM to verify delivery. A running Kubernetes pod alone does not verify provider connectivity. The worker has no HTTP health endpoint; inspect connection health and worker logs for credentials, outbound policy, TLS, or WebSocket errors. The Cloud documentation support service below has a separate lifecycle; enabling it does not start this chat worker.
The initial WebSocket transport accepts one-to-one DMs only. Public mentions and group DMs are not supported. Both the bot and human must still be members of the selected team, even though a DM channel has no team ID. Canonical posts, channel membership, user identity, and team membership are fetched from the authenticated API. Bot/system messages and old posts are ignored. Stable post IDs deduplicate repeated frames. Replica leases prevent multiple active listeners for a connection. Disabling a connection or revoking its credentials stops delivery.
After an outage the listener reconnects with bounded backoff. It does not replay commands posted while disconnected: send those again deliberately after the worker is ready. Accepted queue jobs remain durable. A delivery interrupted during an external write is marked uncertain and is not blindly replayed.
Mattermost HTTPS destinations reuse the instance outbound network policy. Public
addresses work by default. For self-hosted intranet servers, the instance operator
can allow the necessary private subnet with MODEL_ENDPOINT_ALLOWED_CIDRS.
Link-local metadata addresses remain blocked. HTTP and WebSocket connections pin
the validated DNS address while preserving TLS verification and the Host header;
credential-bearing redirects are refused. The process must trust your server's CA
through the system trust store or SSL_CERT_FILE.
Existing slash-command connections¶
Existing connections retain token verification and team checks. The legacy
connection API remains available for advanced setups. To create /preloop
manually in Mattermost Integrations → Slash Commands, use:
- Trigger:
preloop; method: POST. - Request URL: the exact connection callback displayed by Preloop.
- Response username/icon: your bot's presentation, as desired.
- Verification token: copy the per-command token into the legacy connection API's
verification_secret, separately from itsbot_token.
Run /preloop /link CODE for linking and /preloop /note SESSION_ID TEXT for a
note. Existing connections can continue operating as configured. The wizard does
not create slash commands or grant manage_slash_commands permissions.
Slack setup¶
Ordinary direct messages and app_mention Events API events are the portable
baseline. No /preloop slash command or paid Slack agent surface is needed.
For your own Slack app:
- Create an app at Slack apps, enable its bot, and
install it to your workspace. Copy the Bot User OAuth Token (
xoxb-…). - Enter the token in Preloop.
auth.testdiscovers the workspace and bot user. - Use the generated minimal manifest and reserved callback. Its scopes are
chat:write,im:write,im:history, andapp_mentions:read; its bot events aremessage.imandapp_mention. Enable the Messages tab and allow messages. - Copy Basic Information → App Credentials → Signing Secret into Preloop. Slack's bot token cannot reveal this secret. The draft accepts only signed provider verification challenges before completion, not chat commands.
- Configure Event Subscriptions → Request URL with the displayed callback,
verify it, and finish installation. DM
link CODEto link your own identity.
The manifest is also useful when recreating an app: replace its callback with the reserved URL from your draft and reinstall when Slack requests updated scopes. Do not paste tokens into app names, workspace IDs, source code, or logs.
Add to Slack appears only when the deployment has all four settings:
CHAT_SLACK_CLIENT_ID, CHAT_SLACK_CLIENT_SECRET,
CHAT_SLACK_SIGNING_SECRET, and CHAT_SLACK_REDIRECT_URI. Register that fixed
redirect URI with Slack; never derive it from a request's Host header. The OAuth
state is random, expiring, single-use, and bound to the initiating account/actor.
Return to Preloop, refresh, confirm the discovered workspace, then finish while
signed in as that actor. Slack OAuth v2 does not advertise PKCE for this flow;
client-secret exchange and server-side state are used. The own-app path works
without centrally provisioned credentials. Reinstall through a new setup to rotate
credentials, then disable the old connection after relinking and checking delivery.
If Slack returns expiring credentials and a refresh token for the centrally configured OAuth app, the leased worker rotates both encrypted tokens before expiry. Failed/revoked refresh is visible as reconnecting and expired credentials are not used. Own-app manual tokens can be replaced by completing a new setup and disabling the old connection.
Slack agent_view/assistant events are not implemented. Standard DMs work without
those optional plan-specific capabilities. This integration does not claim native
agent thread context/status behavior.
Discord setup¶
- Create a bot application in the Discord Developer Portal and copy its bot token. Enter that token in Preloop.
- Preloop reads
GET /applications/@meand/users/@me, including the application ID, name, andverify_key. It lists installed servers from/users/@me/guilds; an application's support-serverguild_idis not treated as an installation. - If no server appears, use Install in Discord, then refresh. The link uses
only
bot+applications.commands, with Send Messages permission. A user with server installation rights must approve it. - Select a server and explicitly choose Finish and install /preloop. Preloop
configures the interactions callback using
PATCH /applications/@me, then creates or updates only its own guild/preloopcommand with a requiredmessagestring option. Other commands are preserved. An existing unrelated callback requires explicit confirmation before replacement. - Run
/preloop message:/link CODEusing the private linking code shown in Preloop. Replies arrive by DM; the interaction acknowledgement is ephemeral. Allow DMs from the bot/server so delivery can succeed.
A callback must be externally reachable and pass Discord's signed PING validation. If Discord rejects it, check the displayed URL, TLS, and ingress routing, then retry finishing the same setup. No public key, application ID, bot user ID, or raw server ID is required in the wizard. Discovery is bounded to 200 installed servers.
Commands and authorization¶
After linking, use ordinary text for read-only questions. Explicit commands are:
| Action | Slack / Mattermost direct message | Discord |
|---|---|---|
| Link account | link CODE |
/preloop message:/link CODE |
| Session note | note SESSION_ID TEXT |
/preloop message:/note SESSION_ID TEXT |
| Agent message | message AGENT_ID SESSION_ID TEXT |
/preloop message:/message AGENT_ID SESSION_ID TEXT |
| Approve request | approve REQUEST_ID |
/preloop message:/approve REQUEST_ID |
| Deny request | deny REQUEST_ID |
/preloop message:/deny REQUEST_ID |
The bot rechecks identity, account status, resource visibility and permission before actions and before delivering stored responses. Approval quorum and existing policy checks still apply. Linking codes expire after ten minutes and are single use. Use Unlink my account to revoke an identity. Account administrators can disable the connection; delivery history makes failures and uncertain sends visible.
Mattermost Agents is complementary: it provides its own model/MCP agent layer and is not required for this transport. No unverified gateway integration or actor-specific permissions through a shared Agents credential are promised.
Cloud documentation support¶
When the optional Cloud support service is configured, Help → Ask Preloop support and the public Cloud home/pricing/signup launcher open a separate support conversation. It uses public, versioned documentation sources with citations and an independent Preloop support budget. Inspect my setup explicitly reads only setup statuses allowed by your signed-in account permissions. It does not expose raw audit logs or run arbitrary MCP tools.
Messages may be reviewed by a human. Each message or choice creates an ordered private operator-thread entry; merely viewing or dismissing a prompt sends no operator notification. Human takeover blocks pending assistant responses, and operator thread replies return to the browser. Anonymous credentials authorize one conversation, and supplying contact information never authorizes account inspection. Self-hosted public sites do not load the Cloud widget by default. See your Cloud operator guide for service configuration, retention, budgets and delivery recovery.
Discord installation persists its callback target before remote changes. If installation fails, retry Finish with the same workspace; the saved connection supports that retry. A command-installation failure restores the prior callback when it still points to this attempt. An interrupted rollback retains a durable callback target. Slack OAuth must complete in the browser that initiated setup; its short-lived secure HttpOnly SameSite=Lax proof is never returned in the authorization URL.