Compare commits
3 Commits
claude/iss
...
burn/274-1
| Author | SHA1 | Date | |
|---|---|---|---|
| 3c9a1d9010 | |||
| 56f5df8ade | |||
| b68d6c7259 |
36
.env.example
36
.env.example
@@ -257,6 +257,42 @@ BROWSER_INACTIVITY_TIMEOUT=120
|
||||
# TELEGRAM_WEBHOOK_PORT=8443
|
||||
# TELEGRAM_WEBHOOK_SECRET= # Recommended for production
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# MATRIX INTEGRATION
|
||||
# =============================================================================
|
||||
# Matrix is the sovereign messaging protocol: federated, E2EE, no corporation.
|
||||
#
|
||||
# For fleet ops notifications (replacing Telegram), configure these variables.
|
||||
# See docs/matrix-setup.md for full setup guide.
|
||||
|
||||
# Required: Your homeserver URL
|
||||
# MATRIX_HOMESERVER=https://matrix-client.matrix.org # Public homeserver for testing
|
||||
# MATRIX_HOMESERVER=https://matrix.your.domain.com # Self-hosted (recommended)
|
||||
|
||||
# Required: Bot access token (get from Element: Settings -> Help & About -> Advanced)
|
||||
# MATRIX_ACCESS_TOKEN=***
|
||||
|
||||
# Required: Bot user ID
|
||||
# MATRIX_USER_ID=@hermes-bot:matrix.org
|
||||
|
||||
# Required: Device ID (from login response)
|
||||
# MATRIX_DEVICE_ID=HERMES_BOT
|
||||
|
||||
# Fleet ops channel: Where system notifications, cron results, and alerts go
|
||||
# Create a room in Element, invite the bot, then get the room ID from Room Settings
|
||||
# MATRIX_HOME_CHANNEL=!room-id:matrix.org
|
||||
# MATRIX_HOME_CHANNEL_NAME=Fleet Ops
|
||||
|
||||
# Crisis channel: For SOUL.md protocol and urgent alerts
|
||||
# MATRIX_CRISIS_CHANNEL=!crisis-room-id:matrix.org
|
||||
# MATRIX_CRISIS_CHANNEL_NAME=Crisis Room
|
||||
|
||||
# E2EE Support: Install matrix-nio with encryption support
|
||||
# pip install "matrix-nio[e2e]"
|
||||
# Requires libolm C library: brew install libolm (macOS) or apt install libolm-dev (Linux)
|
||||
|
||||
# =============================================================================
|
||||
# WhatsApp (built-in Baileys bridge — run `hermes whatsapp` to pair)
|
||||
# WHATSAPP_ENABLED=false
|
||||
# WHATSAPP_ALLOWED_USERS=15551234567
|
||||
|
||||
@@ -214,58 +214,98 @@ matrix:
|
||||
- "!room1:matrix.org"
|
||||
```
|
||||
|
||||
|
||||
## Fleet Ops Channel (Phase 4)
|
||||
|
||||
The fleet ops channel replaces Telegram for system notifications, cron job results, and operational alerts.
|
||||
|
||||
### 1. Create Fleet Ops Room
|
||||
|
||||
1. Open Element (or any Matrix client)
|
||||
2. Create a new room named "Fleet Ops" or "Hermes Ops"
|
||||
3. Set room to **invite-only** (not public)
|
||||
4. Invite your bot: `@hermes-bot:your.domain.com`
|
||||
5. Get the room ID from Room Settings -> Advanced -> Internal Room ID
|
||||
- Format: `!randomstring:your.domain.com`
|
||||
|
||||
### 2. Configure Environment
|
||||
|
||||
Add to `~/.hermes/.env`:
|
||||
|
||||
```bash
|
||||
# Fleet ops channel
|
||||
MATRIX_HOME_CHANNEL=!your-room-id:matrix.org
|
||||
MATRIX_HOME_CHANNEL_NAME=Fleet Ops
|
||||
```
|
||||
|
||||
### 3. Test Fleet Ops
|
||||
|
||||
```bash
|
||||
# Test Matrix connection
|
||||
hermes matrix test
|
||||
|
||||
# Send a test message to fleet ops channel
|
||||
hermes matrix send "Fleet ops channel test"
|
||||
|
||||
# Check cron job delivery
|
||||
hermes cron list
|
||||
# Jobs with deliver=origin will now deliver to Matrix if configured
|
||||
```
|
||||
|
||||
### 4. Configure Cron Delivery
|
||||
|
||||
Cron jobs can deliver results to Matrix instead of Telegram:
|
||||
|
||||
```bash
|
||||
# Create a job that delivers to Matrix
|
||||
hermes cron create "Check system health" --schedule "every 1h" --deliver matrix:home
|
||||
|
||||
# Or deliver to a specific Matrix room
|
||||
hermes cron create "Backup status" --schedule "every 6h" --deliver matrix:!room-id:matrix.org
|
||||
```
|
||||
|
||||
### 5. Fleet Ops Notifications
|
||||
|
||||
The following notifications go to the fleet ops channel:
|
||||
|
||||
- **Cron job results**: Success/failure of scheduled tasks
|
||||
- **System alerts**: Memory, disk, GPU usage warnings
|
||||
- **Agent status**: Model changes, provider switches, errors
|
||||
- **Security events**: Auth failures, suspicious activity
|
||||
|
||||
### 6. Crisis Room (Optional)
|
||||
|
||||
For urgent alerts (SOUL.md protocol), create a separate crisis room:
|
||||
|
||||
```bash
|
||||
# Crisis channel for urgent alerts
|
||||
MATRIX_CRISIS_CHANNEL=!crisis-room-id:matrix.org
|
||||
MATRIX_CRISIS_CHANNEL_NAME=Crisis Room
|
||||
```
|
||||
|
||||
### 7. Migrate from Telegram
|
||||
|
||||
Once Matrix is working:
|
||||
|
||||
1. Update cron jobs to deliver to Matrix: `--deliver matrix:home`
|
||||
2. Test all critical notifications
|
||||
3. Disable Telegram delivery for migrated jobs
|
||||
4. Monitor both channels during transition
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Matrix: need MATRIX_ACCESS_TOKEN or MATRIX_USER_ID + MATRIX_PASSWORD"
|
||||
### Bot not receiving messages
|
||||
- Check bot has permission to read room
|
||||
- Verify E2EE is working (see E2EE section)
|
||||
- Check `MATRIX_HOME_CHANNEL` is set correctly
|
||||
|
||||
Neither auth method is configured. Set `MATRIX_ACCESS_TOKEN` in `~/.hermes/.env`
|
||||
or provide `MATRIX_USER_ID` + `MATRIX_PASSWORD`.
|
||||
### Messages not sending
|
||||
- Verify `MATRIX_ACCESS_TOKEN` is valid
|
||||
- Check homeserver is reachable
|
||||
- Look at gateway logs: `hermes gateway logs`
|
||||
|
||||
### "Matrix: whoami failed"
|
||||
### E2EE issues
|
||||
- Install: `pip install "matrix-nio[e2e]"`
|
||||
- Install libolm: `brew install libolm` (macOS) or `apt install libolm-dev` (Linux)
|
||||
- Restart gateway after installing
|
||||
|
||||
The access token is invalid or expired. Generate a new one via the login API.
|
||||
|
||||
### "Matrix: E2EE dependencies are missing"
|
||||
|
||||
Install libolm and matrix-nio with E2EE support:
|
||||
|
||||
```bash
|
||||
brew install libolm # macOS
|
||||
pip install "matrix-nio[e2e]"
|
||||
```
|
||||
|
||||
### "Matrix: login failed"
|
||||
|
||||
- Check username and password.
|
||||
- Ensure the account exists on the target homeserver.
|
||||
- Some homeservers require admin approval for new registrations.
|
||||
|
||||
### Bot Not Responding in Rooms
|
||||
|
||||
1. Check `MATRIX_REQUIRE_MENTION` — if `true` (default), messages must
|
||||
@mention the bot.
|
||||
2. Check `MATRIX_ALLOWED_USERS` — if set, only listed users can interact.
|
||||
3. Check logs: `tail -f ~/.hermes/logs/gateway.log`
|
||||
|
||||
### E2EE Rooms Show "Unable to Decrypt"
|
||||
|
||||
1. Ensure `MATRIX_DEVICE_ID` is set to a stable value.
|
||||
2. Check that `~/.hermes/platforms/matrix/store/` has read/write permissions.
|
||||
3. Verify libolm is installed: `python -c "from nio.crypto import ENCRYPTION_ENABLED; print(ENCRYPTION_ENABLED)"`
|
||||
|
||||
### Slow Message Delivery
|
||||
|
||||
Matrix federation can add latency. For faster responses:
|
||||
- Use the same homeserver for the bot and users.
|
||||
- Set `MATRIX_HOME_ROOM` to a local room.
|
||||
- Check network connectivity between Hermes and the homeserver.
|
||||
|
||||
## Quick Start (Automated)
|
||||
|
||||
Run the interactive setup script:
|
||||
|
||||
```bash
|
||||
python scripts/setup_matrix.py
|
||||
```
|
||||
|
||||
This guides you through homeserver selection, authentication, and verification.
|
||||
|
||||
@@ -662,6 +662,153 @@ def cmd_chat(args):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
||||
def cmd_matrix(args):
|
||||
"""Handle Matrix integration commands."""
|
||||
from hermes_cli.colors import Colors, color
|
||||
import os
|
||||
|
||||
subcmd = getattr(args, 'matrix_command', None)
|
||||
|
||||
if subcmd is None or subcmd == "status":
|
||||
# Show Matrix configuration status
|
||||
print(color("\n=== Matrix Integration Status ===\n", Colors.CYAN))
|
||||
|
||||
homeserver = os.getenv("MATRIX_HOMESERVER", "")
|
||||
access_token = os.getenv("MATRIX_ACCESS_TOKEN", "")
|
||||
user_id = os.getenv("MATRIX_USER_ID", "")
|
||||
device_id = os.getenv("MATRIX_DEVICE_ID", "")
|
||||
home_channel = os.getenv("MATRIX_HOME_CHANNEL", "")
|
||||
crisis_channel = os.getenv("MATRIX_CRISIS_CHANNEL", "")
|
||||
|
||||
if not homeserver:
|
||||
print(color("✗ Matrix not configured", Colors.RED))
|
||||
print(" Set MATRIX_HOMESERVER, MATRIX_ACCESS_TOKEN, MATRIX_USER_ID in ~/.hermes/.env")
|
||||
print(" See docs/matrix-setup.md for setup guide")
|
||||
return 1
|
||||
|
||||
print(color("✓ Homeserver:", Colors.GREEN), homeserver)
|
||||
print(color("✓ User ID:", Colors.GREEN) if user_id else color("✗ User ID: not set", Colors.RED))
|
||||
print(color("✓ Access Token:", Colors.GREEN) if access_token else color("✗ Access Token: not set", Colors.RED))
|
||||
print(color("✓ Device ID:", Colors.GREEN) if device_id else color("✗ Device ID: not set", Colors.YELLOW))
|
||||
|
||||
print()
|
||||
print(color("Channels:", Colors.CYAN))
|
||||
if home_channel:
|
||||
print(color(" ✓ Fleet Ops:", Colors.GREEN), home_channel)
|
||||
else:
|
||||
print(color(" ✗ Fleet Ops: not configured", Colors.YELLOW))
|
||||
print(" Set MATRIX_HOME_CHANNEL for system notifications")
|
||||
|
||||
if crisis_channel:
|
||||
print(color(" ✓ Crisis Room:", Colors.GREEN), crisis_channel)
|
||||
else:
|
||||
print(color(" ○ Crisis Room: not configured", Colors.DIM))
|
||||
|
||||
# Check E2EE support
|
||||
try:
|
||||
import nio
|
||||
print(color(" ✓ E2EE support: available", Colors.GREEN))
|
||||
except ImportError:
|
||||
print(color(" ✗ E2EE support: missing (pip install 'matrix-nio[e2e]')", Colors.YELLOW))
|
||||
|
||||
return 0
|
||||
|
||||
if subcmd == "test":
|
||||
# Test Matrix connection
|
||||
print(color("Testing Matrix connection...", Colors.CYAN))
|
||||
|
||||
homeserver = os.getenv("MATRIX_HOMESERVER", "")
|
||||
access_token = os.getenv("MATRIX_ACCESS_TOKEN", "")
|
||||
|
||||
if not homeserver or not access_token:
|
||||
print(color("✗ Matrix not configured", Colors.RED))
|
||||
return 1
|
||||
|
||||
try:
|
||||
import urllib.request, json, ssl
|
||||
ctx = ssl.create_default_context()
|
||||
|
||||
# Test homeserver reachability
|
||||
req = urllib.request.Request(f"{homeserver}/_matrix/client/versions")
|
||||
resp = urllib.request.urlopen(req, context=ctx, timeout=10)
|
||||
versions = json.loads(resp.read())
|
||||
print(color("✓ Homeserver reachable", Colors.GREEN))
|
||||
|
||||
# Test authentication
|
||||
req = urllib.request.Request(
|
||||
f"{homeserver}/_matrix/client/v3/account/whoami",
|
||||
headers={"Authorization": f"Bearer {access_token}"}
|
||||
)
|
||||
resp = urllib.request.urlopen(req, context=ctx, timeout=10)
|
||||
whoami = json.loads(resp.read())
|
||||
print(color(f"✓ Authenticated as: {whoami.get('user_id')}", Colors.GREEN))
|
||||
|
||||
# Test home channel if configured
|
||||
home_channel = os.getenv("MATRIX_HOME_CHANNEL", "")
|
||||
if home_channel:
|
||||
print(color(f"✓ Fleet Ops channel configured: {home_channel}", Colors.GREEN))
|
||||
|
||||
print(color("\n✓ Matrix integration working!", Colors.GREEN))
|
||||
return 0
|
||||
|
||||
except Exception as e:
|
||||
print(color(f"✗ Matrix test failed: {e}", Colors.RED))
|
||||
return 1
|
||||
|
||||
if subcmd == "send":
|
||||
# Send message to Matrix
|
||||
message = args.message
|
||||
channel = getattr(args, 'channel', None) or os.getenv("MATRIX_HOME_CHANNEL", "")
|
||||
|
||||
if not channel:
|
||||
print(color("✗ No channel specified and MATRIX_HOME_CHANNEL not set", Colors.RED))
|
||||
return 1
|
||||
|
||||
print(color(f"Sending to Matrix channel: {channel}", Colors.CYAN))
|
||||
|
||||
# Use the send_message_tool
|
||||
try:
|
||||
import asyncio
|
||||
from tools.send_message_tool import _send_matrix
|
||||
|
||||
homeserver = os.getenv("MATRIX_HOMESERVER", "")
|
||||
access_token = os.getenv("MATRIX_ACCESS_TOKEN", "")
|
||||
|
||||
if not homeserver or not access_token:
|
||||
print(color("✗ Matrix not configured", Colors.RED))
|
||||
return 1
|
||||
|
||||
result = asyncio.run(_send_matrix(access_token, {"homeserver": homeserver}, channel, message))
|
||||
|
||||
if result.get("success"):
|
||||
print(color("✓ Message sent", Colors.GREEN))
|
||||
return 0
|
||||
else:
|
||||
print(color(f"✗ Send failed: {result.get('error')}", Colors.RED))
|
||||
return 1
|
||||
|
||||
except Exception as e:
|
||||
print(color(f"✗ Error: {e}", Colors.RED))
|
||||
return 1
|
||||
|
||||
if subcmd == "setup":
|
||||
print(color("Matrix Setup Wizard", Colors.CYAN))
|
||||
print("\nTo set up Matrix integration:")
|
||||
print("1. See docs/matrix-setup.md for full guide")
|
||||
print("2. Set environment variables in ~/.hermes/.env:")
|
||||
print(" MATRIX_HOMESERVER=https://your-homeserver.com")
|
||||
print(" MATRIX_ACCESS_TOKEN=your-token")
|
||||
print(" MATRIX_USER_ID=@bot:your-homeserver.com")
|
||||
print(" MATRIX_HOME_CHANNEL=!room-id:your-homeserver.com")
|
||||
print("3. Run: hermes matrix test")
|
||||
print("4. Create cron jobs with --deliver matrix:home")
|
||||
return 0
|
||||
|
||||
print(color(f"Unknown matrix command: {subcmd}", Colors.RED))
|
||||
return 1
|
||||
|
||||
|
||||
def cmd_gateway(args):
|
||||
"""Gateway management commands."""
|
||||
from hermes_cli.gateway import gateway_command
|
||||
@@ -4272,6 +4419,33 @@ For more help on a command:
|
||||
)
|
||||
chat_parser.set_defaults(func=cmd_chat)
|
||||
|
||||
# =========================================================================
|
||||
# matrix command
|
||||
# =========================================================================
|
||||
matrix_parser = subparsers.add_parser(
|
||||
"matrix",
|
||||
help="Matrix sovereign messaging integration",
|
||||
description="Manage Matrix integration for fleet ops and notifications."
|
||||
)
|
||||
matrix_subparsers = matrix_parser.add_subparsers(dest="matrix_command")
|
||||
|
||||
# Matrix test command
|
||||
matrix_test = matrix_subparsers.add_parser("test", help="Test Matrix connection and configuration")
|
||||
|
||||
# Matrix send command
|
||||
matrix_send = matrix_subparsers.add_parser("send", help="Send a message to Matrix channel")
|
||||
matrix_send.add_argument("message", help="Message to send")
|
||||
matrix_send.add_argument("--channel", "-c", help="Channel to send to (default: home channel)")
|
||||
|
||||
# Matrix status command
|
||||
matrix_status = matrix_subparsers.add_parser("status", help="Show Matrix integration status")
|
||||
|
||||
# Matrix setup command
|
||||
matrix_setup = matrix_subparsers.add_parser("setup", help="Interactive Matrix setup wizard")
|
||||
|
||||
matrix_parser.set_defaults(func=cmd_matrix)
|
||||
|
||||
|
||||
# =========================================================================
|
||||
# model command
|
||||
# =========================================================================
|
||||
|
||||
Reference in New Issue
Block a user