Matrix AI Bot: Decentralized Chat Assistant
Build an AI bot for Matrix protocol. End-to-end encryption, federation, and bridging support for decentralized messaging.
Molted Team
molted.cloud
Build an AI bot for Matrix protocol. End-to-end encryption, federation, and bridging support for decentralized messaging.
Molted Team
molted.cloud
Matrix is the decentralized, open-source protocol for secure communication. Unlike Slack or Teams, no single company controls it. If you value federation, encryption, and open standards, Matrix is your messaging platform. This guide shows how to add AI to it.
Matrix uses these concepts:
Register a new account on your homeserver. For matrix.org:
mkdir matrix-ai-bot
cd matrix-ai-bot
npm init -y
npm install matrix-bot-sdk @anthropic-ai/sdk dotenvCreate .env:
MATRIX_HOMESERVER=https://matrix.org
MATRIX_ACCESS_TOKEN=your-access-token
MATRIX_BOT_USER_ID=@yourbot:matrix.org
ANTHROPIC_API_KEY=your-anthropic-keyrequire('dotenv').config();
const {
MatrixClient,
SimpleFsStorageProvider,
AutojoinRoomsMixin,
} = require('matrix-bot-sdk');
const Anthropic = require('@anthropic-ai/sdk');
const homeserverUrl = process.env.MATRIX_HOMESERVER;
const accessToken = process.env.MATRIX_ACCESS_TOKEN;
const botUserId = process.env.MATRIX_BOT_USER_ID;
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const conversations = new Map();
// Storage for sync state
const storage = new SimpleFsStorageProvider('bot-storage.json');
// Create client
const client = new MatrixClient(homeserverUrl, accessToken, storage);
// Auto-join rooms when invited
AutojoinRoomsMixin.setupOnClient(client);
// Handle messages
client.on('room.message', async (roomId, event) => {
// Ignore our own messages
if (event.sender === botUserId) return;
// Only handle text messages
if (event.content?.msgtype !== 'm.text') return;
const text = event.content.body;
// In rooms with multiple users, only respond when mentioned
const members = await client.getJoinedRoomMembers(roomId);
if (members.length > 2) {
// Check if bot is mentioned
const botDisplayName = 'AI'; // Or get from profile
if (!text.toLowerCase().includes(botDisplayName.toLowerCase()) &&
!text.includes(botUserId)) {
return;
}
}
// Clean text (remove mentions)
const cleanText = text
.replace(new RegExp(botUserId, 'g'), '')
.replace(/@\S+/g, '')
.trim();
if (!cleanText) return;
// Get or create conversation
if (!conversations.has(roomId)) {
conversations.set(roomId, []);
}
const history = conversations.get(roomId);
history.push({ role: 'user', content: cleanText });
if (history.length > 20) {
history.splice(0, history.length - 20);
}
try {
// Send typing indicator
await client.sendTyping(roomId, true, 30000);
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
system: 'You are a helpful AI assistant in a Matrix chat room. Keep responses concise.',
messages: history,
});
const reply = response.content[0].text;
history.push({ role: 'assistant', content: reply });
// Stop typing
await client.sendTyping(roomId, false);
// Send reply
await client.sendText(roomId, reply);
} catch (error) {
console.error('Error:', error);
await client.sendText(roomId, 'Sorry, I encountered an error.');
}
});
// Start the bot
client.start().then(() => {
console.log('Matrix bot started!');
});Matrix AI without the code
OpenClaw supports Matrix as a plugin. Configure and go.
Coming soonFor end-to-end encrypted rooms, you need additional setup:
const {
MatrixClient,
SimpleFsStorageProvider,
AutojoinRoomsMixin,
RustSdkCryptoStorageProvider,
} = require('matrix-bot-sdk');
// Crypto storage for E2EE
const cryptoStorage = new RustSdkCryptoStorageProvider('./crypto-store');
const client = new MatrixClient(
homeserverUrl,
accessToken,
storage,
cryptoStorage
);
// The rest is the same - the SDK handles encryption transparentlyNote: E2EE support in bots can be complex. The matrix-bot-sdk handles most of it, but key verification and cross-signing require additional work.
client.on('room.message', async (roomId, event) => {
if (event.sender === botUserId) return;
if (event.content?.msgtype !== 'm.text') return;
const text = event.content.body;
// Handle commands
if (text.startsWith('!')) {
const [command, ...args] = text.slice(1).split(' ');
switch (command) {
case 'help':
await client.sendText(roomId, `Available commands:
!help - Show this message
!clear - Clear conversation history
!model - Show current AI model
!ask <question> - Ask a one-off question`);
return;
case 'clear':
conversations.delete(roomId);
await client.sendText(roomId, 'Conversation cleared.');
return;
case 'ask':
const question = args.join(' ');
// One-off question without history
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: [{ role: 'user', content: question }],
});
await client.sendText(roomId, response.content[0].text);
return;
}
}
// Regular message handling...
});// Send formatted message (HTML)
await client.sendHtmlText(
roomId,
'<strong>Bold</strong> and <em>italic</em> text',
'**Bold** and *italic* text' // Fallback plain text
);
// Send code block
const code = `function hello() {
console.log('Hello!');
}`;
await client.sendHtmlText(
roomId,
`<pre><code>${code}</code></pre>`,
code
);client.on('room.message', async (roomId, event) => {
// Handle images
if (event.content?.msgtype === 'm.image') {
const mxcUrl = event.content.url; // mxc://server/media-id
const httpUrl = client.mxcToHttp(mxcUrl);
// Download and process
const response = await fetch(httpUrl);
const buffer = await response.arrayBuffer();
const base64 = Buffer.from(buffer).toString('base64');
const aiResponse = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: [{
role: 'user',
content: [
{
type: 'image',
source: {
type: 'base64',
media_type: event.content.info?.mimetype || 'image/jpeg',
data: base64,
},
},
{
type: 'text',
text: 'What is in this image?',
},
],
}],
});
await client.sendText(roomId, aiResponse.content[0].text);
}
});Decentralized AI, zero hassle
OpenClaw supports Matrix with E2EE. Plugin install on Molted or self-host.
For maximum control, run your own Matrix homeserver:
# Using Synapse (reference implementation)
docker run -d --name synapse \
-v synapse-data:/data \
-e SYNAPSE_SERVER_NAME=matrix.yourdomain.com \
-e SYNAPSE_REPORT_STATS=no \
-p 8008:8008 \
matrixdotorg/synapse:latest
# Or Conduit for lighter resource usage
# Or Dendrite for the newer Go implementationMatrix bridges let you connect to other platforms. Your AI bot can respond to messages bridged from Slack, Discord, or Telegram.
With bridges, one Matrix bot can effectively serve multiple platforms.
OpenClaw supports Matrix as a plugin:
OpenClaw on Matrix. Your server, your rules, your AI.
24-hour free trial · no credit card · cancel anytime
Run an AI assistant on Signal for encrypted conversations. Complete signal-cli setup with Claude integration.
Run ChatGPT or Claude on WhatsApp with Baileys. Complete self-hosted setup guide with code examples and deployment options.
Run your personal AI assistant 24/7 on a Mac Mini. Complete setup guide for OpenClaw, formerly known as Clawdbot and MoltBot.
STILL AWAKE?