claude-session-bus
by Catweazle74
README.md
# claude-session-bus
[](https://github.com/Catweazle74/claude-session-bus/actions/workflows/selftest.yml)
[](LICENSE)
Ein Koordinationsbus, der mehrere **Claude-Code-Sessions** (Linux, macOS, Windows) über eine bestehende
[m1k1o/chat](https://github.com/m1k1o/chat)-Instanz zusammenschaltet. Jede Session hängt als normaler
Chat-Teilnehmer im selben Raum, adressiert die anderen Sessions direkt mit `@nick`, meldet ihren
Status selbst und kann **blockierend auf die Zuarbeit einer anderen Session warten** – ohne dass ein
Mensch zwischen den Rechnern hin- und herspringt.
```
user: @claude-linux bau Feature X
claude-linux: gepusht nach feature/x (abc123). @claude-win @claude-mac bitte bauen und testen
claude-win: Build ok, 12/12 Tests grün
claude-mac: Build bricht ab: fehlende Symbole in libfoo. @claude-linux Log: ...
claude-linux: Fix gepusht (def456). @claude-mac nochmal
```
Während `claude-linux` auf die Antwort wartet, blockiert es in `wait_for_message` – statt den Menschen
zu fragen – und wacht auf, sobald eine der anderen Sessions antwortet.
## Architektur
Ein Prozess pro Maschine (`bridge.py`), drei Bausteine in einem asyncio-Loop:
```
m1k1o/chat (z. B. chat-host:8484)
▲ Socket.IO
│
┌───────┴────────────────────────────────┐
│ bridge.py (Linux / macOS / Windows) │
│ ├─ ChatClient Socket.IO │
│ ├─ MCP-Server 127.0.0.1:8787 │◄── HTTP-MCP ──┐
│ ├─ Router @nick-Regeln │ │
│ └─ ClaudeSession Subprozess ───────┼──► claude -p ─┘
└────────────────────────────────────────┘ (stream-json)
```
- **stdin-Injection** weckt eine untätige Session (neuer Turn).
- **MCP-Tools** bedienen die arbeitende Session (senden / warten / Peers abfragen) mitten im Turn.
## Adressierung (Schutz vor Endlosschleifen)
Eine Session reagiert **nur**, wenn sie mit `@<ihr-nick>`, `@all` oder `@alle` angesprochen wird.
Alle anderen Nachrichten liest sie nur mit und gibt sie beim nächsten eigenen Turn als Kontext weiter.
Zusätzlich greift nach `HOP_LIMIT` (Standard 12) aufeinanderfolgenden Bot→Bot-Runden **ohne**
menschliche Beteiligung eine Bremse; jede Nachricht eines Menschen oder `/reset` setzt sie zurück.
## MCP-Tools, die jede Session bekommt
| Tool | Zweck |
|------|-------|
| `chat_send_message(text, to=[…])` | Nachricht posten; `to` setzt `@nick`-Präfixe |
| `chat_wait_for_message(from_nick, contains, timeout, addressed_only)` | **blockierend** auf Zuarbeit warten |
| `chat_get_messages(limit)` | letzte Nachrichten lesen, ohne zu warten |
| `chat_list_peers()` | wer ist online, mit letztem gemeldeten Status |
| `chat_set_status(state, detail)` | `idle` / `working` / `blocked` / `done` |
## Slash-Kommandos (von der Bridge beantwortet, gehen nicht an Claude)
- `/status` – Nick, Zustand, Session-ID, Queue, Wartende, Hops, Uptime, Peers (antwortet von jeder Session)
- `/help` – Kurzhilfe
- `/reset` – **adressiert** (`@nick /reset`): neue Claude-Session mit frischem Kontext
- `/stop` – **adressiert**: laufenden Turn abbrechen (Prozess neu, Kontext bleibt über `--resume`)
## Chat-Server (m1k1o/chat) aufsetzen
Der Bus braucht **eine** zentrale [m1k1o/chat](https://github.com/m1k1o/chat)-Instanz im LAN, mit der
sich alle Sessions verbinden. Der Container lauscht intern auf Port **80**; in dieser README wird er
nach außen auf **8484** gemappt (passend zu `CHAT_URL=http://<host>:8484`).
Schnellstart per Docker:
```bash
docker run -d --name chat --restart unless-stopped -p 8484:80 -e CACHE_SIZE=200 m1k1o/chat:latest
```
Oder per `docker-compose.yml`:
```yaml
services:
chat:
image: m1k1o/chat:latest
restart: unless-stopped
ports:
- "8484:80"
environment:
CACHE_SIZE: 200 # Anzahl serverseitig gepufferter Nachrichten für neu verbundene Clients
healthcheck:
test: ["CMD", "curl", "http://localhost"]
interval: 60s
timeout: 10s
retries: 10
start_period: 5s
```
```bash
docker compose up -d
```
- **`CACHE_SIZE`** – wie viele letzte Nachrichten der Server puffert und einer neu verbundenen Session
als Verlauf schickt. Standard 0 (kein Verlauf). Für den Bus sinnvoll (z. B. 200), damit eine neu
gestartete Session den letzten Kontext sieht; nicht zu hoch, da auch Bilder gecacht werden.
- Danach in jeder `config.env` `CHAT_URL=http://<host-ip>:8484` setzen – die IP/den Hostnamen des
Docker-Hosts (aus dem LAN erreichbar), **nicht** `localhost`, sonst finden die anderen Maschinen den
Server nicht.
- Prüfen: `curl http://<host-ip>:8484/` sollte `HTTP 200` liefern.
> ⚠️ **Sicherheit:** m1k1o/chat hat **keine Authentifizierung** (siehe Abschnitt „Sicherheit — bitte
> lesen“). Den Port nur im vertrauenswürdigen LAN/VPN exponieren, niemals ins Internet.
## Installation (je Maschine)
Voraussetzungen: **Python ≥ 3.10** und die **Claude Code CLI** (`claude`) im PATH.
### Linux / macOS
```bash
git clone https://github.com/Catweazle74/claude-session-bus.git
cd claude-session-bus
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
cp config.example.env config.env # anpassen: CLAUDE_CWD, CHAT_NICK, ...
```
### Windows (PowerShell)
```powershell
# Falls kein echtes Python vorhanden ist (der Store-Alias "python" zählt nicht):
winget install --id Python.Python.3.12 --scope user
git clone https://github.com/Catweazle74/claude-session-bus.git
cd claude-session-bus
python -m venv .venv
.\.venv\Scripts\pip install -r requirements.txt
Copy-Item config.example.env config.env # anpassen: CLAUDE_CWD, CHAT_NICK, ...
```
`config.env` bearbeiten – vor allem `CLAUDE_CWD` auf das gemeinsame Projekt-Repo setzen
(unter Windows als nativer Pfad, z. B. `C:\Users\<user>\Sourcen\mein-projekt`).
### Verifikation (offline, ohne Chat und Claude)
```bash
.venv/bin/python selftest.py # Windows: .venv\Scripts\python selftest.py
```
Deterministische Tests der Router-Logik (Adressierung, Pingpong-Bremse, wait/pending,
Slash-Kommandos). Sollten alle mit „alle Selbsttests bestanden“ enden.
## Starten
```bash
set -a; . ./config.env; set +a # Windows PowerShell: siehe unten
.venv/bin/python bridge.py
```
`CHAT_URL` ist **Pflicht** – ohne gesetzte Variable (oder `--chat-url`) bricht die Bridge mit einer
Meldung ab, statt still gegen eine Beispieladresse zu verbinden.
Der Nick ergibt sich, wenn nicht gesetzt, aus der Plattform: `claude-linux` / `claude-mac` /
`claude-win`. Overrides auch per CLI-Flag: `.venv/bin/python bridge.py --nick claude-linux --cwd /pfad/zum/repo`.
Windows (PowerShell):
```powershell
Get-Content config.env | Where-Object { $_ -match '=' -and $_ -notmatch '^\s*#' } | ForEach-Object {
$k,$v = $_ -split '=',2; [Environment]::SetEnvironmentVariable($k.Trim(), $v.Trim())
}
.venv\Scripts\python bridge.py
```
## Stoppen
- **Linux (systemd --user):** `systemctl --user stop claude-session-bus`
- **macOS (launchd):** `launchctl unload ~/Library/LaunchAgents/claude-session-bus.plist`
- **Windows:** `Get-Process python | Where-Object Path -like '*claude-session-bus*' | Stop-Process`
- Direkt im Vordergrund gestartet: einfach `Strg+C`.
## Test ohne Browser
```bash
.venv/bin/python test_client.py "@claude-linux liste die Dateien im Repo"
.venv/bin/python test_client.py --listen 120 # nur mitlesen
```
## Autostart
- **Linux (systemd --user):** `systemd/claude-session-bus.service` nach `~/.config/systemd/user/`
kopieren, Pfade anpassen, dann `systemctl --user daemon-reload && systemctl --user enable --now claude-session-bus`.
- **macOS (launchd):** `launchd/claude-session-bus.plist` nach `~/Library/LaunchAgents/` kopieren,
Pfade anpassen, `launchctl load ~/Library/LaunchAgents/claude-session-bus.plist`.
- **Windows (Aufgabenplanung):** `windows/install-task.ps1` (Pfade anpassen) in einer **als Administrator
gestarteten** PowerShell ausführen – `Register-ScheduledTask` scheitert sonst mit „Zugriff verweigert“.
Das Skript erzeugt dabei `windows/run-bridge.ps1` (maschinenspezifisch, nicht eingecheckt).
Deinstallieren: `Unregister-ScheduledTask -TaskName "claude-session-bus" -Confirm:$false`.
Adminfreie Alternative (kein Auto-Restart bei Absturz): einen versteckten Starter in den
Autostart-Ordner legen (`shell:startup`), der `windows/run-bridge.ps1` aufruft, z. B. eine
`claude-session-bus.vbs`:
```vbs
Set sh = CreateObject("WScript.Shell")
sh.Run "powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File ""<pfad>\windows\run-bridge.ps1""", 0, False
```
Nur **eine** der beiden Varianten aktivieren, sonst startet die Bridge doppelt.
## Sicherheit — bitte lesen
Der m1k1o-Chat hat **keine Authentifizierung**. Standardmäßig läuft die Bridge mit
`PERMISSION_MODE=bypassPermissions`. Das bedeutet: **wer den Chat erreicht, kann ohne Rückfrage
Befehle auf allen angebundenen Maschinen ausführen und Dateien ändern.** Deshalb:
- Port des Chats (z. B. 8484) **niemals** ins Internet exponieren – nur LAN oder VPN.
- `CLAUDE_CWD` möglichst eng auf das Projekt-Repo setzen, nicht auf `$HOME` oder `/`.
- Der MCP-Server bindet nur an `127.0.0.1` – nicht öffentlich machen.
- Restriktive Alternative (kein autonomes Schreiben/Ausführen):
```
PERMISSION_MODE=acceptEdits
ALLOWED_TOOLS=Read Grep Glob Bash(git *)
```
Damit fragt Claude bei allem außerhalb der Whitelist zurück – was im Bus-Betrieb aber niemand
bestätigen kann, die Session also effektiv blockiert. Für den unbeaufsichtigten Bus ist
`bypassPermissions` in einem vertrauenswürdigen LAN der praktikable Kompromiss.
## Konfiguration
Alle Optionen sind in [`config.example.env`](config.example.env) dokumentiert und zusätzlich als
CLI-Flags verfügbar (`--help`).
---
## Funktionsstand
- ✅ Chat-Anbindung (Socket.IO), `@nick`-Adressierung, Pingpong-Bremse, Slash-Kommandos
- ✅ MCP-Tools für senden / blockierendes Warten / Peers / Status, in-process auf `127.0.0.1`
- ✅ Claude-Session als Subprozess (`claude -p`, stream-json) inklusive stdin-Injection und `--resume`
- ✅ Autostart-Vorlagen für systemd (Linux), launchd (macOS), Aufgabenplanung (Windows)
- ✅ Offline-Selbsttests der Router-Logik (`selftest.py`), in CI auf jedem Push
- ⚠️ Kein Auth-Konzept — die Sicherheit hängt vollständig am Netz, in dem der Chat läuft
(siehe „Sicherheit — bitte lesen")
---
## Beitrag & Feedback
**Bekannte Limitierungen**:
- `bridge.py` liest `config.env` nicht selbst — die Variablen müssen vorher in die Umgebung
(sourcen, `EnvironmentFile=` in systemd, Wrapper-Skript unter Windows/macOS).
- Der Windows-Autostart per `Register-ScheduledTask` braucht eine Administrator-PowerShell;
ohne Adminrechte nur die Autostart-Ordner-Variante (kein Neustart bei Absturz).
- m1k1o/chat bietet keine Authentifizierung — nur im vertrauenswürdigen LAN/VPN betreiben.
**Bitte melden**:
- Schritte zum Reproduzieren
- Erwartetes vs. tatsächliches Verhalten
- Plattform, Python-Version, Ausgabe von `/status` und `selftest.py` (falls möglich)
---
## Abhängigkeiten
- **Python ≥ 3.10**
- **[Claude Code CLI](https://github.com/anthropics/claude-code)** (`claude` im PATH)
- **python-socketio[asyncio_client] ≥ 5.16, < 6** (Chat-Verbindung)
- **mcp ≥ 2.0, < 3** (MCP-Server für die Session-Tools; mit 1.x nicht kompatibel)
- **[m1k1o/chat](https://github.com/m1k1o/chat)** als zentrale Chat-Instanz im LAN (Docker)
---
## Lizenz
MIT — siehe [LICENSE](LICENSE).
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues