A Rails-native Matrix SDK for building multi-agent bot systems and real-time communication features. This gem is a fork of the matrix-sdk gem, extensively enhanced with Rails integration, multi-agent architecture, and persistent state management.
- Ruby 3.4+
- Rails 8.0+
- PostgreSQL 18+ (required for UUIDv7 primary keys)
- Multi-Agent Architecture: Run multiple bots concurrently with async fiber-based lifecycle management
- Daemon Binary: Production-ready
activematrixdaemon with multi-process workers and health probes - Rails Integration: Deep integration with ActiveRecord, Rails.cache, and Rails.logger
- State Machines: state_machines-powered state management for bot lifecycle
- Memory System: Three-tier memory architecture (agent, conversation, global)
- Event Routing: Intelligent event distribution to appropriate agents
- Client Pooling: Efficient connection management with async semaphores
- Generators: Rails generators for quick bot creation
- Inter-Agent Communication: Built-in messaging between bots
- PostgreSQL 18 Features: UUIDv7 primary keys, JSONB with GIN indexes
Add this line to your application's Gemfile:
gem 'activematrix'And then execute:
$ bundle install
$ rails generate active_matrix:install
$ rails db:migrate$ rails generate active_matrix:bot captainThis creates a bot class in app/bots/captain_bot.rb:
class CaptainBot < ActiveMatrix::Bot::MultiInstanceBase
set :accept_invites, true
set :command_prefix, '!'
command :status,
desc: 'Get system status',
args: '[component]' do |component = nil|
if component
# Check specific component
status = memory.get("status_#{component}") || 'unknown'
room.send_notice("#{component}: #{status}")
else
# Overall status
room.send_notice("All systems operational!")
end
end
command :deploy,
desc: 'Deploy to production',
args: 'target' do |target|
# Use conversation memory to track deployments
deployments = conversation_memory.remember(:deployments) { [] }
deployments << { target: target, time: Time.current }
conversation_memory[:deployments] = deployments
# Notify other agents
broadcast_to_agents(:lieutenant, {
type: 'deployment',
target: target,
initiated_by: agent_name
})
room.send_notice("Deploying to #{target}...")
end
# Handle inter-agent messages
def receive_message(data, from:)
case data[:type]
when 'status_report'
memory.set("status_#{data[:component]}", data[:status])
logger.info "Received status update from #{from.agent_name}"
end
end
end# Create agent records in Rails console or seeds
captain = ActiveMatrix::Agent.create!(
name: 'captain',
homeserver: 'https://matrix.org',
username: 'captain_bot',
password: 'secure_password',
bot_class: 'CaptainBot',
settings: {
rooms_to_join: ['!warroom:matrix.org'],
command_prefix: '!'
}
)
lieutenant = ActiveMatrix::Agent.create!(
name: 'lieutenant',
homeserver: 'https://matrix.org',
username: 'lieutenant_bot',
password: 'secure_password',
bot_class: 'LieutenantBot'
)The activematrix binary manages your bots in production, similar to Sidekiq or GoodJob:
# Start in foreground
bundle exec activematrix start
# Start with multiple worker processes
bundle exec activematrix start --workers 3
# Start specific agents only
bundle exec activematrix start --agents captain,lieutenant
# Daemonize with PID file
bundle exec activematrix start --daemon --pidfile tmp/pids/activematrix.pid
# Check status (queries health probe)
bundle exec activematrix status
# Graceful shutdown
bundle exec activematrix stop
# Reload agent configuration
bundle exec activematrix reloadHealth Probes (for Kubernetes/Docker):
GET /health- Returns 200 if healthyGET /status- JSON with detailed agent statusGET /metrics- Prometheus-compatible metrics
curl http://localhost:3042/health
curl http://localhost:3042/status# Start all agents (blocks until shutdown)
ActiveMatrix::AgentManager.instance.start_all
# Start specific agent
ActiveMatrix::AgentManager.instance.start_agent(captain)
# Check status
ActiveMatrix::AgentManager.instance.status
# => { running: 2, agents: [...], monitor_active: true }
# Stop agent
ActiveMatrix::AgentManager.instance.stop_agent(captain)
# Restart agent
ActiveMatrix::AgentManager.instance.restart_agent(captain)# In your bot
memory.set('last_deployment', Time.current)
memory.get('last_deployment')
memory.increment('deployment_count')
memory.remember('config') { load_config_from_api }# Automatically available in commands
conversation_memory[:last_command] = 'deploy'
context = conversation_context # Hash of conversation data
# Track message history
conversation_memory.add_message(event)
recent = conversation_memory.recent_messages(5)# Set global data
global_memory.set('system_status', 'operational',
category: 'monitoring',
expires_in: 5.minutes,
public_read: true
)
# Broadcast to all agents
global_memory.broadcast('alert', {
level: 'warning',
message: 'High CPU usage detected'
})
# Share between specific agents
global_memory.share('secret_key', 'value', ['captain', 'lieutenant'])class MonitorBot < ActiveMatrix::Bot::MultiInstanceBase
# Route specific events to this bot
route event_type: 'm.room.message', priority: 100 do |bot, event|
# Custom processing
end
route room_id: '!monitoring:matrix.org' do |bot, event|
# Handle all events from monitoring room
end
endFor simple, single-bot applications:
# Traditional client usage still works
client = ActiveMatrix::Client.new 'https://matrix.org'
client.login 'username', 'password'
room = client.find_room '#matrix:matrix.org'
room.send_text "Hello from ActiveMatrix!"# config/initializers/active_matrix.rb
ActiveMatrix.configure do |config|
# Agent settings
config.agent_startup_delay = 2.seconds
config.max_agents_per_process = 10
config.agent_health_check_interval = 30.seconds
# Memory settings
config.conversation_history_limit = 20
config.conversation_stale_after = 1.day
config.memory_cleanup_interval = 1.hour
# Daemon settings
config.daemon_workers = 2
config.probe_port = 3042
config.probe_host = '0.0.0.0'
config.shutdown_timeout = 30
end# test/bots/captain_bot_test.rb
class CaptainBotTest < ActiveSupport::TestCase
def setup
@agent = ActiveMatrix::Agent.create!(
name: 'test_captain',
homeserver: 'https://matrix.org',
username: 'test_bot',
bot_class: 'CaptainBot'
)
end
test 'responds to status command' do
# Your test logic here
end
endActiveMatrix implements a sophisticated multi-agent architecture:
- AgentManager: Manages lifecycle of all bots using async fibers (start/stop/restart)
- AgentRegistry: Fiber-safe registry of running bot instances
- EventRouter: Routes Matrix events to appropriate bots via async queues
- ClientPool: Manages shared client connections with async semaphores
- Memory System: Hierarchical storage with caching
- State Machines: Track agent states (offline/connecting/online/busy/error)
All models are namespaced under ActiveMatrix:::
ActiveMatrix::Agent- Bot agent records with state machineActiveMatrix::AgentStore- Per-agent key-value storageActiveMatrix::ChatSession- Conversation context per user/roomActiveMatrix::KnowledgeBase- Global shared storage
Bug reports and pull requests are welcome on GitHub at https://github.com/seuros/activematrix
The gem is available as open source under the terms of the MIT License.