# ✅ Final Working Solution: Kosmi ↔ IRC Relay **Date**: October 31, 2025, 1:10 PM **Status**: ✅ **FULLY FUNCTIONAL - BIDIRECTIONAL RELAY WORKING** ## Summary Successfully implemented a fully working bidirectional message relay between Kosmi and IRC using a **Playwright-based UI automation approach**. ## Test Results ✅ **IRC → Kosmi**: Working ✅ **Kosmi → IRC**: Working ✅ **Username formatting**: Consistent with `RemoteNickFormat` ✅ **Message echo prevention**: Working (messages with `[irc]` prefix filtered out) ✅ **Clean logging**: Debug code removed, production-ready ## Final Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ Matterbridge Gateway │ │ │ │ ┌──────────────────────┐ ┌──────────────────────┐ │ │ │ IRC Bridge │◄───────►│ Kosmi Bridge │ │ │ │ (irc.zeronode) │ │ (kosmi.hyperspaceout)│ │ │ └──────────────────────┘ └──────────┬───────────┘ │ │ │ │ └───────────────────────────────────────────────┼─────────────────┘ │ ┌───────────▼───────────┐ │ Playwright Native │ │ Client │ │ │ │ • Browser automation │ │ • WebSocket (receive) │ │ • UI automation (send)│ └───────────┬────────────┘ │ ┌───────────▼───────────┐ │ Kosmi Web UI │ │ (app.kosmi.io) │ └───────────────────────┘ ``` ## Implementation Details ### Message Receiving (Kosmi → IRC) - **Method**: WebSocket subscription via Playwright-intercepted connection - **Mechanism**: JavaScript injection captures WebSocket messages in the browser - **Subscription**: `subscription { newMessage(roomId: "...") { body time user { displayName username } } }` - **Processing**: Messages polled from JavaScript queue every 500ms ### Message Sending (IRC → Kosmi) - **Method**: UI automation via Playwright - **Mechanism**: JavaScript evaluation to interact with DOM - **Process**: 1. Find visible chat input element (textarea, contenteditable, or text input) 2. Set input value to message text 3. Dispatch input/change events 4. Trigger send via button click or Enter key press ### Why This Approach? After extensive investigation, we discovered: 1. ❌ **Direct WebSocket Connection**: Fails with 403 Forbidden (authentication/bot detection) 2. ❌ **HTTP POST GraphQL Mutation**: API only supports auth mutations (`anonLogin`, `slackLogin`), not `sendMessage` 3. ❌ **WebSocket Mutation via Playwright**: Connection closes immediately after sending mutation (protocol/auth issues) 4. ✅ **UI Automation**: Works reliably because it mimics real user interaction ## Key Files ### 1. `bridge/kosmi/native_client.go` The Playwright-based client implementation: - Launches headless Chromium browser - Injects WebSocket access layer - Navigates to Kosmi room - Subscribes to messages via WebSocket - Sends messages via UI automation ### 2. `bridge/kosmi/kosmi.go` The Matterbridge bridge implementation: - Implements `bridge.Bridger` interface - Manages `NativeClient` lifecycle - Handles message routing - Filters echo messages (prevents loops) ### 3. `matterbridge.toml` Configuration file: ```toml [kosmi.hyperspaceout] RoomURL="https://app.kosmi.io/room/@hyperspaceout" RemoteNickFormat="[{PROTOCOL}] <{NICK}> " [irc.zeronode] Server="irc.zeronode.net:6697" Nick="kosmi-relay" RemoteNickFormat="[{PROTOCOL}] <{NICK}> " UseTLS=true ``` ## Message Flow ### IRC → Kosmi 1. User sends message in IRC: `Testing from IRC` 2. IRC bridge receives PRIVMSG 3. Matterbridge formats with `RemoteNickFormat`: `[irc] Testing from IRC` 4. Kosmi bridge receives message 5. `NativeClient.SendMessage()` uses UI automation 6. JavaScript finds chat input, sets value, triggers send 7. Message appears in Kosmi chat ### Kosmi → IRC 1. User sends message in Kosmi: `Testing from Kosmi` 2. WebSocket subscription receives `newMessage` event 3. JavaScript queue captures the message 4. `pollMessages()` retrieves from queue 5. Kosmi bridge filters echo messages (checks for `[irc]` prefix) 6. Matterbridge formats with `RemoteNickFormat`: `[kosmi] Testing from Kosmi` 7. IRC bridge sends to channel 8. Message appears in IRC ## Echo Prevention Messages are tagged with protocol prefixes via `RemoteNickFormat`: - IRC messages sent to Kosmi: `[irc] message` - Kosmi messages sent to IRC: `[kosmi] message` The Kosmi bridge filters out messages starting with `[irc]` to prevent echoing our own messages back. ## Deployment ### Docker Compose ```yaml services: matterbridge: build: . container_name: kosmi-irc-relay volumes: - ./matterbridge.toml:/app/matterbridge.toml:ro restart: unless-stopped ``` ### Running ```bash docker-compose up -d --build docker-compose logs -f ``` ## Performance Characteristics - **Startup Time**: ~10 seconds (Playwright browser launch + page load) - **Message Latency**: - IRC → Kosmi: ~100-500ms (UI automation) - Kosmi → IRC: ~500-1000ms (polling interval) - **Resource Usage**: - Memory: ~300-400 MB (Chromium browser) - CPU: Low after initialization ## Future Improvements ### Potential Optimizations 1. **Reduce Polling Interval**: Could decrease from 500ms to 250ms for lower latency 2. **WebSocket Send**: If Kosmi's auth/protocol can be reverse-engineered properly 3. **Direct GraphQL API**: If Kosmi exposes a `sendMessage` mutation in the future ### Known Limitations 1. **Browser Required**: Must run full Chromium browser (can be headless) 2. **Polling Latency**: 500ms delay for incoming messages 3. **UI Dependency**: Breaks if Kosmi changes their UI structure (input selectors) ## Troubleshooting ### Common Issues **Problem**: "Could not find chat input element" **Solution**: Kosmi may have changed their UI. Update selectors in `SendMessage()` method. **Problem**: Messages not appearing in Kosmi **Solution**: Check browser console logs, verify UI automation script is working. **Problem**: WebSocket not connecting **Solution**: Check network connectivity, verify Kosmi URL is correct. **Problem**: Echo loop (messages keep bouncing) **Solution**: Verify `RemoteNickFormat` is set correctly and echo filter is working. ## Conclusion After extensive troubleshooting and multiple implementation attempts (direct WebSocket, HTTP POST, WebSocket mutations), we successfully achieved bidirectional message relay using **Playwright UI automation**. This approach is reliable, maintainable, and production-ready. The relay now successfully: ✅ Sends messages from IRC to Kosmi ✅ Receives messages from Kosmi to IRC ✅ Prevents message echo loops ✅ Formats usernames consistently ✅ Runs in Docker with minimal configuration **Status**: Production-ready ✅