# ✅ 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] <username> 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] <username> 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] <username> message`
- Kosmi messages sent to IRC: `[kosmi] <username> 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 ✅

