Hivemind ↔ Chatalot integration
This is the operator runbook for letting Hivemind agents post messages
into your chatalot channels. It uses chatalot's existing webhook
system — no chatalot code changes, no admin tokens, no E2E client
crypto. The webhook posts a single plaintext system message
(MessageType::Webhook) into one specific channel that you create the
webhook for.
This is the right pattern for:
- Daily ops summaries — a hivemind agent posts a thread digest each
morning into #ops.
- Alert relays — when something pages, a hivemind agent posts the
raw alert + its own commentary into #alerts.
- Scheduled announcements — release notes, status updates,
customer-facing messages.
- Chatbot answers in a designated channel — the support agent
echoes its answers into #support-log for transparency.
It is not the right pattern for: - Two-way conversations (the bot posting and reading replies). Webhooks are output-only. Inbound message subscription is a separate feature on the roadmap (CHAT bot-API + event-stream tickets). - Posting into E2E-encrypted private DMs. Webhooks live in regular channels only.
What you'll wire up
Hivemind agent
→ Hivemind's chatalot connector
→ POST https://chat.example.com/api/webhooks/execute/<token>
→ chatalot stores message_type=Webhook, broadcasts to channel
The token is created once per channel in chatalot's admin UI and
stored in Vaultwarden. Hivemind looks it up by name when an agent calls
chatalot post_message.
Step 1 — Create a webhook in chatalot
As an admin, in the chatalot web UI:
- Open the channel you want hivemind to post into (say
#ops). - Channel settings → Webhooks → Create webhook.
- Name it something the operator will recognize (e.g.
hivemind-ops-relay). - Save. Chatalot generates a 64-char token; the full URL looks like
https://chat.example.com/api/webhooks/execute/<token>. - Copy the URL.
You'll get one webhook URL per channel. Repeat this for every channel you want hivemind to post into.
Step 2 — Store the URL in Vaultwarden
Hivemind looks up webhook URLs by a predictable item name:
Where <instance> is a short slug for the chatalot instance (for
example, separate slugs for your own dev and production instances, or a
slug per customer) and <channel> is whatever you call the channel
(loose convention — match the channel name in chatalot for clarity).
Examples of valid item names:
Chatalot Webhook - dev - test
Chatalot Webhook - prod - ops
Chatalot Webhook - prod - announcements
Chatalot Webhook - support - support-log
In Vaultwarden:
- Create a new login item with that exact name.
- Paste the full webhook URL into the password field.
- Save into the Infrastructure collection (or wherever the rest of your chatalot creds live).
Hivemind fetches the URL from your secret manager by that name when an agent posts, so no new credentials are embedded in the agent config.
Step 3 — Use it from Hivemind
Once an item exists, an operator (or an authorized hivemind agent) can post via the Hivemind:
chatalot action=post_message instance=prod channel=ops content="Daily ops summary: 3 alerts cleared, 2 customers ingested, 0 outages."
Optional flags on the same call:
username="Hivemind Ops Bot"— overrides the webhook's display name per message.avatar_url=https://…— overrides the webhook avatar.
Returned JSON looks like:
{
"ok": true,
"instance": "prod",
"http_status": 200,
"url": "https://chat.seglamater.app/api/webhooks/execute/<token>"
}
For ad-hoc testing without Vaultwarden setup, pass the URL directly:
chatalot action=post_message webhook_url=https://chat.example.com/api/webhooks/execute/<token> content="hello"
Step 4 — Wire a hivemind agent to call it
Hivemind agent profiles (admin-tier) can invoke MCP tools when the operator has granted that permission. To let an agent post into chatalot:
- In Hivemind admin, edit the agent profile (e.g.
ops-summary). - Grant MCP access to
chatalot.post_message. (Tier-1 public agents should NOT have this — webhook posts are operator-side automation, not customer-facing chat.) - The agent's system prompt should specify which
instanceandchannelto use, and any defaultusername/avatar_urlfor branding.
When the agent runs (cron-driven directive, manual trigger, or
reaction to another agent's output), it calls
chatalot action=post_message ... and the message lands in
chatalot in real-time, broadcast to all connected clients in that
channel.
Rate limits + character limits
- 1 message per second per webhook. Bursting beyond that returns HTTP 400 from chatalot ("webhook rate limited"). Hivemind doesn't retry; the agent should pace itself or batch into one message.
- 1 to 4000 characters per message. Empty content and >4000 chars both fail validation.
- 64-char username cap. Anything longer is rejected.
Operational notes
- Tokens are sensitive. Anyone who has the URL can post into the channel. Treat them like deploy tokens. If a webhook leaks, delete it in chatalot's admin UI and create a fresh one.
- Messages are plaintext on the server. This is intentional — bot output isn't end-to-end encrypted. Don't post anything in webhook messages that you wouldn't be comfortable having in chatalot's database in cleartext.
- No inbound path. The bot can't read messages or react to user replies via this mechanism. That's tracked separately as the bot-API
- event-subscription work.
- Per-instance trust. A dev instance with a self-signed certificate can run with TLS verification disabled; production instances should verify normally. Configure each instance (name, base URL, and TLS verification) in your Hivemind connector settings.
Appendix — request shape
Hivemind wraps the underlying HTTP call so agents don't need to think about it, but for completeness:
POST /api/webhooks/execute/<token> HTTP/1.1
Host: chat.example.com
Content-Type: application/json
{
"content": "your message body, 1-4000 characters",
"username": "optional display-name override",
"avatar_url": "optional avatar URL override"
}
Successful execution returns 201 with a JSON body —
{message_id, channel_id, created_at, status} — so the caller can confirm
delivery (prior to v0.25.23 this was an empty 200). Validation errors return
422/400 with a plaintext error reason.