Co-authored-by: Cursor <cursoragent@cursor.com>
Kosmi-IRC Relay via Matterbridge
A Matterbridge plugin that bridges Kosmi chat rooms with IRC channels, enabling bidirectional message relay.
Features
- ✅ Real-time message relay between Kosmi and IRC
- ✅ Headless Chrome automation for reliable Kosmi connection
- ✅ WebSocket interception using Chrome DevTools Protocol
- ✅ Anonymous Kosmi access (no authentication required)
- ✅ Message formatting with source indicators
- ✅ Automatic reconnection handling
- ✅ Support for any Kosmi room via URL configuration
Architecture
This implementation extends Matterbridge with a custom Kosmi bridge that:
- Launches a headless Chrome instance using
chromedp - Navigates to the Kosmi room and injects a WebSocket interceptor before page load
- Captures GraphQL WebSocket messages (
wss://engine.kosmi.io/gql-ws) from the page - Relays messages bidirectionally with proper formatting:
- Kosmi → IRC:
[Kosmi] <username> message - IRC → Kosmi:
[IRC] <username> message
- Kosmi → IRC:
Why Headless Chrome?
Kosmi's WebSocket API requires browser session cookies and context that are difficult to replicate with a native WebSocket client. Using headless Chrome automation ensures:
- ✅ Automatic session management
- ✅ Proper cookie handling
- ✅ Reliable WebSocket connection
- ✅ No authentication complexity
Installation
Option 1: Docker (Recommended) 🐳
The easiest way to run the bridge:
# 1. Edit configuration
nano matterbridge.toml
# 2. Build and run
docker-compose up -d
# 3. View logs
docker-compose logs -f
See: DOCKER_QUICKSTART.md for 5-minute setup guide
Option 2: Build from Source
Prerequisites
- Go 1.21 or higher
- Chrome or Chromium browser installed
- Access to an IRC server
- A Kosmi room URL
Building
# Clone the repository
git clone <repository-url>
cd irc-kosmi-relay
# Download dependencies
go mod download
# Build the bridge
go build -o matterbridge
Configuration
Edit matterbridge.toml to configure your bridge:
# Kosmi configuration
[kosmi.hyperspaceout]
RoomURL="https://app.kosmi.io/room/@hyperspaceout"
# IRC configuration
[irc.libera]
Server="irc.libera.chat:6667"
Nick="kosmi-relay"
UseTLS=false
# Gateway to connect Kosmi and IRC
[[gateway]]
name="kosmi-irc-gateway"
enable=true
[[gateway.inout]]
account="kosmi.hyperspaceout"
channel="main"
[[gateway.inout]]
account="irc.libera"
channel="#your-channel"
Configuration Options
Kosmi Settings
RoomURL(required): Full URL to the Kosmi room- Format:
https://app.kosmi.io/room/@roomnameorhttps://app.kosmi.io/room/roomid
- Format:
Server(optional): WebSocket endpoint (default:wss://engine.kosmi.io/gql-ws)Debug(optional): Enable debug logging
IRC Settings
See Matterbridge IRC documentation for full IRC configuration options.
Usage
# Run the bridge
./matterbridge -conf matterbridge.toml
# Run with debug logging
./matterbridge -conf matterbridge.toml -debug
How It Works
Kosmi Connection
The bridge connects to Kosmi using headless Chrome automation:
- Launch Chrome: Starts a headless Chrome instance via
chromedp - Inject Hook: Uses
Page.addScriptToEvaluateOnNewDocumentto inject a WebSocket interceptor before any page scripts run - Navigate: Loads the Kosmi room URL
- Intercept: The injected script hooks
window.WebSocketconstructor to capture all WebSocket messages - Poll: Continuously polls the message queue populated by the interceptor
- Process: Extracts chat messages from GraphQL subscription data
Critical Implementation Detail
The WebSocket hook must be injected before page load using Page.addScriptToEvaluateOnNewDocument. This ensures the hook is active when Kosmi's JavaScript creates the WebSocket connection. If injected after page load, the WebSocket will already be established and messages won't be captured.
Message Flow
IRC User → IRC Server → Matterbridge → Headless Chrome → Kosmi Room
Kosmi User → Kosmi Room → WebSocket → Chrome Interceptor → Matterbridge → IRC Server → IRC Channel
Message Filtering
- The bridge ignores its own messages by checking for the
[IRC]prefix - This prevents message loops between Kosmi and IRC
Technical Details
GraphQL API
The Kosmi bridge uses the following GraphQL operations:
Subscription (receiving messages):
subscription {
newMessage(roomId: "roomId") {
body
time
user {
displayName
username
}
}
}
Mutation (sending messages):
mutation {
sendMessage(roomId: "roomId", body: "message text") {
id
}
}
File Structure
bridge/kosmi/
├── kosmi.go # Main bridge implementation
├── chromedp_client.go # Headless Chrome client with WebSocket interception
└── graphql.go # GraphQL message structures (deprecated native client)
gateway/bridgemap/
└── bkosmi.go # Bridge registration
cmd/test-kosmi/
└── main.go # Standalone test program
matterbridge.toml # Configuration file
go.mod # Go module dependencies
Troubleshooting
Connection Issues
Problem: Bridge fails to connect to Kosmi
Solutions:
- Verify Chrome/Chromium is installed:
which google-chrome chromium chromium-browser - Verify the room URL is correct
- Check network connectivity to
app.kosmi.io - Enable debug logging to see detailed connection logs
- Look for "✓ WebSocket hook confirmed installed" in logs
- Look for "Status: WebSocket connection intercepted" in logs
Message Not Relaying
Problem: Messages aren't being relayed between Kosmi and IRC
Solutions:
- Verify both Kosmi and IRC connections are established
- Check the gateway configuration in
matterbridge.toml - Ensure channel names match in the gateway configuration
- Check logs for errors
Authentication Errors
Problem: Kosmi connection fails with authentication error
Note: Kosmi doesn't require authentication. If you see auth errors, verify:
- The WebSocket URL is correct
- The room ID is valid
- Network isn't blocking WebSocket connections
Development
Adding Features
The bridge follows Matterbridge's bridge interface:
type Bridger interface {
Send(msg config.Message) (string, error)
Connect() error
JoinChannel(channel config.ChannelInfo) error
Disconnect() error
}
Testing
To test the bridge:
- Start the bridge with debug logging
- Send a message in the Kosmi room
- Verify it appears in IRC with
[Kosmi]prefix - Send a message in IRC
- Verify it appears in Kosmi with
[IRC]prefix
Known Limitations
- Anonymous Access: The bridge connects anonymously to Kosmi, so it will have a randomly assigned username
- Message Sending: The GraphQL mutation for sending messages may need adjustment based on Kosmi's actual API
- Room Discovery: The bridge connects to a specific room; it doesn't support room discovery or listing
Credits
- Based on Matterbridge by 42wim
- Kosmi API reverse engineering from chrome extension analysis
License
Same as Matterbridge (Apache 2.0)