Skip to content
BotServBotServ
MatrixBotOllamaAIDecentralizedE2EE

Matrix Bot with Ollama

Build a Matrix bot with Ollama. Decentralized chat with AI, room integration, E2EE and practical examples.

S

schutzgeist

6 min read
Matrix Bot with Ollama

Matrix Bot with Ollama

What This Article Covers

  • Building a Matrix bot with Ollama as your AI backend.
  • Integrating the bot into Matrix rooms.
  • Using RAG and tool integration with Matrix.
  • Real-world examples for support bots, moderation, and automation.
  • Best practices for E2EE, security, and privacy.

Introduction: Matrix Bot with Ollama Explained

Matrix is a decentralized chat protocol: self-hosted, encrypted, no central company. A Matrix bot with Ollama answers questions in your Matrix rooms using local AI. Your data never reaches third parties, there are no API costs, and you retain full control.

This article is for anyone wanting to build a Matrix bot with local AI. For foundational concepts, see Matrix Bots and Ollama.

Why Use a Matrix Bot with Ollama?

Discord bots run on Discord’s servers, which means your data lives with Discord. Matrix is self-hosted: your server, your data. A Matrix bot with Ollama represents the most thorough privacy approach: a decentralized protocol plus local AI means no one sees your conversations.

Matrix Bot with Ollama in a Nutshell

You create a Matrix bot (using matrix-nio or matrix-js-sdk) that listens for messages in rooms. When a message arrives, the bot calls Ollama and posts the response. With E2EE enabled, even those messages stay encrypted.

The core principle is simple: decentralized protocol plus local AI equals maximum control.

Who Should Read This?

  • Matrix users wanting an AI bot.
  • Privacy-conscious developers avoiding Discord.
  • Self-hosters running their own Matrix server.
  • Engineers building Matrix bots.

Some familiarity with Python and Ollama is helpful.

Key Terms

  • Matrix - Decentralized chat protocol. Use case: the protocol itself.
  • Synapse - Matrix homeserver. Use case: the server software.
  • Element - Matrix client. Use case: the frontend.
  • matrix-nio - Python library. Use case: bot development.
  • Ollama - Local model server. Use case: your AI backend.
  • E2EE - End-to-end encryption. Use case: private messages.
  • RAG - Knowledge database. Use case: FAQ systems.

Setup: Creating Your Matrix Bot

1. Bot Account on Your Homeserver

# On your Synapse server: create a bot user
register_new_matrix_user -c /etc/matrix-synapse/homeserver.yaml \
  -u ki-bot -p "sicheres-passwort" --no-admin

2. Bot Using matrix-nio

# bot.py
import asyncio
import aiohttp
from nio import AsyncClient, RoomMessageText

OLLAMA_URL = "http://ollama:11434"
HOMESERVER = "https://matrix.deine-domain.de"
BOT_USER = "@ki-bot:deine-domain.de"
BOT_PASSWORD = "sicheres-passwort"

async def call_ollama(prompt, system=None):
    """Call Ollama"""
    messages = []
    if system:
        messages.append({"role": "system", "content": system})
    messages.append({"role": "user", "content": prompt})

    async with aiohttp.ClientSession() as session:
        async with session.post(
            f"{OLLAMA_URL}/api/chat",
            json={
                "model": "llama3.1",
                "messages": messages,
                "stream": False
            },
            timeout=aiohttp.ClientTimeout(total=60)
        ) as response:
            data = await response.json()
            return data["message"]["content"]

async def main():
    client = AsyncClient(HOMESERVER, BOT_USER)

    # Login
    response = await client.login(BOT_PASSWORD)
    print(f"Bot logged in: {response.user_id}")

    # Auto-join on invites
    client.add_event_callback(on_invite, InviteEvent)

    async def on_message(room, event):
        """Handle new message"""
        if event.sender == BOT_USER:
            return

        # Respond to mentions or commands
        if f"{BOT_USER}" in event.body or event.body.startswith("!"):
            async with client.typing(room.room_id):
                # Extract question
                question = event.body.replace(f"@{BOT_USER.split(':')[0][1:]}", "").strip()
                if question.startswith("!"):
                    question = question[1:].strip()

                # Call Ollama
                answer = await call_ollama(
                    question,
                    system="You are a helpful assistant in a Matrix chat. Keep responses brief and useful."
                )

                # Send reply
                await client.room_send(
                    room_id=room.room_id,
                    message_type="m.room.message",
                    content={
                        "msgtype": "m.text",
                        "body": answer
                    }
                )

    client.add_event_callback(on_message, RoomMessageText)

    # Sync loop
    await client.sync_forever(timeout=30000)

asyncio.run(main())

3. Invite Bot to a Room

# In Element (your Matrix client):
1. Create or open a room
2. /invite @ki-bot:deine-domain.de
3. Bot auto-accepts via on_invite callback

Example 1: FAQ Bot with RAG

import chromadb

class MatrixFAQBot:
    def __init__(self):
        self.chroma = chromadb.HttpClient(host="chromadb", port=8000)
        self.collection = self.chroma.get_collection("faq")

    async def answer(self, question):
        """Answer question using RAG"""
        results = self.collection.query(
            query_texts=[question],
            n_results=3
        )

        context = "\n".join(results["documents"][0])

        answer = await call_ollama(
            f"Context:\n{context}\n\nQuestion: {question}",
            system="Answer the question based on the provided context. Include sources."
        )

        return {
            "answer": answer,
            "sources": [m["source"] for m in results["metadatas"][0]]
        }

# In on_message:
if event.body.startswith("!faq"):
    question = event.body[4:].strip()
    result = await faq_bot.answer(question)
    await client.room_send(
        room_id=room.room_id,
        message_type="m.room.message",
        content={
            "msgtype": "m.text",
            "body": f"{result['answer']}\n\nSources: {', '.join(result['sources'])}"
        }
    )

Example 2: Moderation

async def moderate_message(room, event, client):
    """Moderate a message"""
    analysis = await call_ollama(
        f"Analyze:\n{event.body}\n\n"
        "Categories: ok, spam, toxic, nsfw\n"
        "Respond: CATEGORY|REASON",
        system="You are a moderation assistant."
    )

    category, reason = analysis.split("|", 1)

    if category != "ok":
        # Delete message (bot needs moderator permissions)
        await client.room_redact(
            room_id=room.room_id,
            event_id=event.event_id,
            reason=reason
        )
        # Send warning
        await client.room_send(
            room_id=room.room_id,
            message_type="m.room.message",
            content={
                "msgtype": "m.text",
                "body": f"⚠️ Message removed: {reason}"
            }
        )

Practical Example 3: Workflow Trigger

if event.body.startswith("!workflow"):
    parts = event.body.split()
    workflow_name = parts[1] if len(parts) > 1 else "default"
    params = " ".join(parts[2:]) if len(parts) > 2 else ""

    # Call n8n webhook
    async with aiohttp.ClientSession() as session:
        async with session.post(
            f"http://n8n:5678/webhook/{workflow_name}",
            json={"params": params, "user": event.sender}
        ) as r:
            result = await r.text()

    await client.room_send(
        room_id=room.room_id,
        message_type="m.room.message",
        content={
            "msgtype": "m.text",
            "body": f"Workflow {workflow_name}: {result}"
        }
    )

Handling End-to-End Encryption

Matrix rooms can use end-to-end encryption. Your bot can only read unencrypted messages unless it has the decryption keys.

# E2EE bot with matrix-nio
from nio import AsyncClient, MatrixRoom, RoomMessageText
from nio.crypto import OlmMachine

# For E2EE, the bot needs:
# 1. Device keys
# 2. Trust establishment with other devices
# 3. Message decryption

# This is complex. To get started:
# - Use the bot only in unencrypted rooms
# - Or: Use an E2EE library like pantalaimon

Security Considerations

  • Bot Password: Use a strong password and store it securely. See Secrets.
  • Permissions: Grant the bot read and write access only, never admin privileges.
  • E2EE: In encrypted rooms, the bot can only read messages if it has the decryption keys.
  • Prompt Injection: Users can attempt injection attacks. See Prompt Injection.
  • Federation: Matrix is federated, which means messages can propagate to other servers.

Common Pitfalls

  • E2EE Complexity: Encrypted rooms require key management. Start with unencrypted rooms.
  • Access Token vs. Password: Use an access token instead of the password. Save it after login.
  • Rate Limiting: Matrix servers enforce rate limits. Implement throttling in your bot.
  • Message Size Limits: Matrix has a size cap per message (around 65KB). Split long responses.
  • Federation: Your bot only sees rooms it joins. Remote rooms accessed through federation behave differently.

Further Reading

Key Takeaways:

  • Matrix and Ollama: decentralized chat with local AI.
  • Use matrix-nio for Python bots, matrix-js-sdk for JavaScript.
  • Respond to mentions and commands.
  • RAG for FAQ, moderation for safety, workflows for automation.
  • E2EE is complex; start with unencrypted rooms.

FAQ

How do I create a Matrix bot?

Create a bot account on your Synapse server using register_new_matrix_user, then program it with matrix-nio (Python) or matrix-js-sdk (JavaScript).

Matrix or Discord for bots?

Choose Matrix for maximum control and privacy (self-hosted, decentralized). Choose Discord for larger communities and easier setup. Matrix is the privacy-first option.

Does the bot work in encrypted rooms?

Only if the bot has the decryption keys. E2EE bots are complex (key management, device trust). For now, stick to unencrypted rooms.

Which library should I use for Matrix bots?

matrix-nio for Python (async, well documented). matrix-js-sdk for JavaScript. matrix-bot-sdk for simpler abstraction.

Do I need my own homeserver?

No, you can register the bot on any homeserver (like matrix.org). However, running your own Synapse instance gives you maximum control and privacy.

Is the bot secure?

Yes, if you store the password securely, grant minimal permissions, and defend against prompt injection. Matrix is decentralized, so messages can be federated to other servers.

What does it cost?

Nothing. Synapse, matrix-nio, and Ollama are open source. You only pay for server and hardware costs.

What can I use the bot for?

FAQ bot, support bot, moderation, workflow triggers, document Q&A (RAG), notifications, translation, summarization.

Sources and Further Reading

Back to Blog
Share:

Related Posts