/sync API — it opens the connection outbound,
so nothing needs to be reachable from the internet. There is no inbound route to
register, no reverse proxy, and no port to open. This page walks you through
creating the bot account, configuring the connection, and turning on encryption.
You don’t need to understand the technical details to use this feature. The configuration examples below are copy-paste ready.
Prerequisites
- Comis installed and running (Quickstart)
- A Matrix account for the bot on a homeserver — you will use its full MXID,
for example
@bot:example.org - An access token for that account (or its password — see Authentication)
- If you self-host: the homeserver’s base URL (for example
https://matrix.example.org)
How Comis connects
Matrix delivers messages by letting a client pull them. Comis logs in to your homeserver and holds an outbound/sync long-poll, receiving room events as
they arrive. Because the daemon initiates the connection, nothing has to be
reachable from the internet — no inbound route, no reverse proxy, no open
port. This is the same pull model as Telegram and
Signal, and the inverse of channels that push activities to
a bot.
A three-gate watermark on the sync loop ensures the bot processes each event
once and does not replay the backlog after a restart, so a restart never
re-answers old messages.
Setup
1
Create a bot account on your homeserver
Register a dedicated account for the bot (for example
@bot:example.org)
through your homeserver’s registration flow or admin API. Give it its own
account — do not reuse a human’s login, so the bot has a stable, separate
identity.2
Get an access token
You need an access token so Comis can authenticate as the bot. Either log in
once with any Matrix client and copy the account’s access token, or let Comis
log in with the account password and mint (and persist) a token itself —
see Authentication. The token is the only secret Comis
stores.
3
Configure Comis
Add the Matrix channel to your Comis configuration file
(Set the secret in your Prefer the command line?
~/.comis/config.yaml):~/.comis/.env file:comis init can write the same block
non-interactively:4
Restart and verify
Restart the Comis daemon to pick up the new configuration:Check that the Matrix probes pass:Then invite the bot to a room from an allowlisted account (or send it a
direct message) and confirm it replies.
Authentication
Comis authenticates as the bot in one of two ways. Either way the identity is validated with awhoami call before the bot starts syncing, so a bad
credential fails loudly at startup rather than silently.
- Access token (recommended)
- Password login
Put a long-lived access token in Pair the token with a stable
accessToken. This is the simplest setup
and the token is the only secret.deviceId so the bot keeps the same device
identity — and therefore its encryption keys — across restarts.accessToken and password are secrets — keep them in ~/.comis/.env
(as MATRIX_ACCESS_TOKEN and MATRIX_PASSWORD) or as a SecretRef.
homeserverUrl, userId, and deviceId are plain configuration values.
End-to-end encryption
Encryption is on by default (e2ee: true). On first start Comis initializes
a crypto backend and persists it in the state directory (stateDir, default
~/.comis/matrix-state), so the bot can send and receive in encrypted rooms.
Set e2ee: false if you want the bot to operate in plaintext rooms only; for a
headless install, pass --matrix-e2ee false to comis init.
Keep a stable device. The bot’s encryption keys belong to its device, so a
stable deviceId is what lets those keys survive a restart. A password login
pins and persists the device automatically; with an access token, set deviceId
explicitly.
Device verification. An unverified bot device can still participate in
encrypted rooms, but some senders will withhold room keys from an unverified
device — a loud, supported posture: the bot runs, and it tells you when this
happens rather than failing. To verify the device, provide the account’s secure
backup key in recoveryKey; the bot restores cross-signing and the room-key
backup and verifies itself.
comis doctor encryption and device-verification probes
report the same posture (see Liveness).
Configuration
The full option table — every field, type, and default — lives in the Configuration reference. The environment variable is documented in Environment variables. This section covers the options that carry a security consequence worth spelling out.Which rooms the bot joins, and who it listens to
Three keys decide whether the bot auto-joins a room it is invited to:
The invite decision keys on the inviter’s full MXID (
@user:server), never
the display name — which anyone can set to impersonate another user.
Self-hosted homeservers
homeserverUrl is validated against server-side request forgery before any
connection is opened, which blocks private-range addresses by default. To point
the bot at a homeserver you run on a private address, set
allowPrivateHomeserver: true. The opt-in covers the sync connection and
mxc:// media downloads alike. Cloud-metadata endpoints stay blocked regardless.
Media
Inbound. Attachments — images, audio and voice messages, video, and files — arrive asmxc:// references. Comis downloads them through an authenticated,
DNS-pinned, SSRF-guarded fetcher scoped to your homeserver host. In an encrypted
room it decrypts the media before the bytes are MIME-sniffed and handed to
the media pipeline (transcription, vision, document extraction).
Outbound. The agent uploads attachments to the homeserver and sends them as
native Matrix media events (m.image, m.file, and the like). In an encrypted
room the uploaded bytes are encrypted before they leave.
Attachment size ceilings are set by your homeserver, not by Comis.
Liveness
comis doctor runs five Matrix probes so a mis-wired or silently broken
connection cannot report healthy forever:
- Credentials parse — the configured credentials are present and coherent.
If a secret reference such as
${MATRIX_ACCESS_TOKEN}is unresolved, the finding names the reference, never the value. - Reachability — the live adapter’s connection state, read over the daemon’s status channel.
- Encryption backend — when
e2eeis on, the crypto backend actually loaded; a warning here means encryption init failed. - Device verification — a warning (never a failure) when the bot’s device is unverified, since unverified operation is a supported posture.
- State directory — the state directory is writable.
Local emulator (self-drive testing)
For an offline round trip without a real homeserver — and for the self-driving live-test rig — an in-tree emulator plays the homeserver side (login,/sync,
media, and the encryption key-upload and key-query surface). It lives at
test/live/emulators/matrix/ and is launched from test/live/bin/.
Because Matrix is pull-based, wiring the emulator is just configuration:
point the channel at it. There are no signing-key or connector seams to set —
the daemon simply connects outbound to the emulator instead of a real
homeserver.
test/live/scenarios/channels/matrix-emulator.test.ts, which drives
a real adapter against the emulator, including an encrypted-startup and an
honest decrypt-degrade edge.
What your agent can do
Once connected to Matrix, your agent can:- Send, edit, and delete messages in direct messages and group rooms (edits replace the original event; deletes redact it)
- Reply inside a thread
- Send and receive reactions (remove one by redacting it)
- Stream a response by editing a message in place as it is generated
- Show a typing indicator while it works
- Send and receive media — images, audio and voice messages, video, and files — including in encrypted rooms
- Fetch recent room history for context
- Participate in end-to-end-encrypted rooms
- Mention users, and detect when it is mentioned
- Deliver messages from cron jobs and heartbeats to rooms it has joined
Platform limits
Troubleshooting
The bot won't join a room I invited it to
The bot won't join a room I invited it to
What happened: The invite gate declined the invite.How to fix it: Confirm
autoJoinOnInvite is true. In the default
allowlist mode the inviter’s full MXID must appear in allowFrom —
an exact match, so a bare localpart, a display name, or the same localpart on
a different homeserver will not match. Add the inviter’s MXID, or set
allowMode: "open" to accept any invite. comis doctor confirms the channel
is connected.The bot receives messages but can't read encrypted ones
The bot receives messages but can't read encrypted ones
What happened: The bot’s device cannot decrypt the room — usually an
unverified device, a missing room key, or encryption having been turned off.How to fix it: The bot posts a once-per-room note that names the exact
next step. Set
recoveryKey to verify the device, or have a room member
re-share the keys; if e2ee was disabled, set it back to true. Make sure
deviceId is stable so the device (and its keys) survive restarts. The
comis doctor encryption and device-verification probes report which half is
wrong.Authentication fails at startup
Authentication fails at startup
What happened: The access token was rejected, or the login could not
resolve the bot’s identity.How to fix it: Refresh
MATRIX_ACCESS_TOKEN, or configure a password
so Comis can re-log-in and mint a fresh token itself. Verify homeserverUrl
and that userId is the full MXID (@bot:example.org). The comis doctor
credentials and reachability probes tell you which check failed.The bot won't connect to my self-hosted homeserver
The bot won't connect to my self-hosted homeserver
What happened:
homeserverUrl points at a private-range address, which
is blocked by the SSRF guard by default.How to fix it: Set allowPrivateHomeserver: true for a homeserver you
control. Cloud-metadata endpoints stay blocked regardless.Later additions
The Matrix channel covers chat, threads, reactions, edit and delete, media, history, mentions, and encrypted rooms. These are documented as not-yet-shipped so you can plan around them:- Paginating room history in the older-than-a-cursor (
before) direction - Following a room upgrade (a tombstoned room to its replacement) automatically
- Interactive buttons (Matrix exposes no button surface; prompts render as text)
- Voice / TTS replies
Delivery Infrastructure
How streaming, typing indicators, and retry logic work under the hood.
Multiple users & teams
Run one install for a whole team - private per person, isolated per agent.
All Channels
Compare all 11 supported platforms side by side.
Agent Configuration
Set up your agent’s personality, tools, and behavior.
Secret Management
Learn how to manage API keys and tokens securely.
