Skip to main content
Connect your Comis agent to Matrix — the open, federated messaging protocol — on any homeserver, whether that is matrix.org or a self-hosted Synapse, Dendrite, or Conduit. Your agent works in direct messages and group rooms, with threaded replies, reactions, edit and delete, media, and end-to-end-encrypted rooms out of the box. Matrix is a pull channel. Comis logs in to your homeserver and streams events over the Client-Server /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

  • 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 (~/.comis/config.yaml):
Set the secret in your ~/.comis/.env file:
Never store API keys, tokens, or passwords directly in config.yaml. Use the .env file or Secret Manager for credential management.
Prefer the command line? 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 a whoami call before the bot starts syncing, so a bad credential fails loudly at startup rather than silently. Only 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.
Honest degrade. When the bot receives an encrypted event it cannot decrypt, it never silently drops it. It posts a once-per-room system note carrying an operator hint that names the exact next step — verify the device, re-share the keys, or (if encryption was turned off) turn it back on — and it never exposes the ciphertext. The 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.
The single allowFrom list does two different jobs, with opposite defaults:
  • As the invite gate it is default-closed: an empty allowFrom auto-joins no room, so a stranger cannot pull the bot into an arbitrary room.
  • As the per-message speaker gate it is default-open: once the bot is in a room, an empty allowFrom lets every current and future member of that room talk to the agent.
So an allowlisted inviter gates the room join — it does not, by itself, restrict who may speak. If you want only specific people to drive the agent, list every MXID you trust to speak in allowFrom (that same list then also governs who may invite the bot). Do not assume “the bot only joined because I invited it, so only I can use it.” Set allowMode: "open" only if you genuinely want the bot to answer anyone in any room it has joined.

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 as mxc:// 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 e2ee is 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.
Probes that need the running daemon skip — rather than report OK — when it is down, so a stopped daemon never looks healthy.

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.
allowPrivateHomeserver: true is required here only because the emulator listens on a loopback address, which the SSRF guard blocks by default. Set it for the emulator or a homeserver you control — never to reach an arbitrary private address.
The whole wire stack is also proven offline (no daemon) by the round-trip scenario at 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
Matrix does not support the agent sending interactive buttons (Matrix exposes no button surface, so approval and action prompts render as text) or voice / TTS replies.

Platform limits

Troubleshooting

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.
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.
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.
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.