disclaw/ARCHITECTURE.md
Nick Tabeling 69e0b7d727 initial
2026-04-08 14:21:19 +02:00

408 lines
16 KiB
Markdown

# DisClaw -- Architektur
## Projektuebersicht
DisClaw ist ein Discord-Bot, der einen Discord-Server in einen Multi-Agenten-Arbeitsbereich verwandelt. Jeder Discord-Kanal wird einem lokalen Workspace-Ordner zugeordnet, in dem ein eigenstaendiger Claude-Code-Agent lebt. Ein zentraler Management-Agent (DisClaw selbst) orchestriert das Erstellen neuer Agenten und deren Kanaele. Die Kommunikation mit den Agenten erfolgt ausschliesslich ueber Discord-Nachrichten.
**Engine: Claude Code CLI** -- DisClaw verwendet die lokal installierte Claude Code CLI (`claude`) als KI-Engine. Es wird kein API-Key benoetigt. Die CLI wird pro Nachricht als Kindprozess gestartet und liest die `CLAUDE.md` im Workspace-Ordner automatisch als Agenten-Identitaet.
---
## MVP-Umfang
### Enthalten
1. Discord-Bot verbindet sich mit einem Server (Token wird beim Setup angegeben)
2. DisClaw erstellt beim ersten Start automatisch seinen eigenen Management-Kanal (`#disclaw`)
3. `/new-agent`-Befehl im Management-Kanal -- legt neuen Discord-Kanal, Workspace-Ordner und Agenten-Identitaet an
4. Jeder Agent-Kanal hat seinen eigenen Ordner, eigene `CLAUDE.md`, eigene `.claude/`-Konfiguration
5. Nachrichten in Agent-Kanaelen werden direkt von Claude Code beantwortet (kein @mention noetig)
6. Keine Berechtigungseinschraenkungen -- jeder Agent hat vollen Zugriff
7. Setup ueber `/setup` Custom Command in Claude Code
8. Agenten-Erstellung ueber `/new-agent` Custom Command in Claude Code (ohne Discord)
### Explizit zurueckgestellt (siehe "Zukuenftige Phasen")
- Berechtigungssystem / rollenbasierter Zugriff
- Weitere Slash-Commands ueber `/new-agent` hinaus
- Agent-zu-Agent-Koordination / Delegation
- Docker-Isolation
- Kostentracking / Budgetlimits
- Web-UI
- Dateisystem-Watcher
---
## Systemarchitektur
```
Discord Server
|
v
+-------------------+
| Discord Bot | discord.js v14 -- empfaengt Nachrichten und Slash-Commands
+-------------------+
|
v
+-------------------+
| Message Router | Ordnet Nachrichten dem richtigen Agent zu (anhand channel_id)
+-------------------+
|
+---> Management-Kanal? ---> DisClaw Command Handler (/new-agent)
|
+---> Agent-Kanal? -------> Agent Runner
|
v
+-------------------+
| Agent Runner | Startet Claude Code CLI als Kindprozess
+-------------------+
|
v
+-------------------+
| Claude Code CLI | claude -p "prompt" --output-format json
+-------------------+ cwd = workspace-ordner (liest CLAUDE.md)
|
v
Antwort --> Discord-Kanal
```
### Komponentenverantwortlichkeiten
| Komponente | Verantwortlichkeit |
|---|---|
| **Discord Bot** | Verbindung zum Server, Empfang von Events, Senden von Antworten |
| **Message Router** | Entscheidet anhand der `channel_id`, ob eine Nachricht an den DisClaw-Handler oder einen Agent Runner geht |
| **Command Handler** | Verarbeitet `/new-agent` -- erstellt Kanal, Ordner, DB-Eintrag, `agent.yaml`, `CLAUDE.md`, `.claude/` |
| **Agent Runner** | Startet `claude` CLI als Kindprozess mit dem Workspace als cwd, parst JSON-Ausgabe |
| **SQLite DB** | Speichert Kanal-Workspace-Zuordnungen und Konversationshistorie |
---
## Ordnerstruktur
```
disclaw/
src/
index.ts # Einstiegspunkt -- Bot starten, Events registrieren
bot.ts # Discord-Bot-Setup und Event-Handler
router.ts # Message Router -- Nachricht -> Handler-Zuordnung
commands/
new-agent.ts # /new-agent Slash-Command-Handler
agent/
runner.ts # Agent Runner -- Claude CLI als Kindprozess starten
identity.ts # CLAUDE.md und agent.yaml erstellen und laden
db/
database.ts # SQLite-Verbindung und Queries
config/
loader.ts # .env und disclaw.yaml laden
workspaces/ # Dynamisch erzeugt -- ein Unterordner pro Agent
agent-name/
CLAUDE.md # Agenten-Identitaet (wird von Claude Code automatisch gelesen)
agent.yaml # DisClaw-Routing-Metadaten (Name, Rolle, Channel-ID)
.claude/
commands/ # Agenten-spezifische Custom Commands (leer fuer den Anfang)
settings.json # Agenten-spezifische Claude-Code-Einstellungen
... # Arbeitsdateien des Agenten
.claude/
commands/
setup.md # /setup -- Gefuehrtes Erstsetup
new-agent.md # /new-agent -- Agent ueber CLI erstellen
CLAUDE.md # Projekt-CLAUDE.md (DisClaw-Beschreibung fuer Claude Code)
disclaw.yaml # Globale Konfiguration
.env # DISCORD_BOT_TOKEN, DISCORD_GUILD_ID, CLAUDE_PATH
package.json
tsconfig.json
```
---
## Datenmodell (SQLite)
### Tabelle: `workspaces`
Bildet Discord-Kanaele auf lokale Workspace-Ordner ab.
```sql
CREATE TABLE workspaces (
id INTEGER PRIMARY KEY AUTOINCREMENT,
channel_id TEXT NOT NULL UNIQUE, -- Discord Channel-ID
guild_id TEXT NOT NULL, -- Discord Server-ID
agent_name TEXT NOT NULL UNIQUE, -- Eindeutiger Agentenname
workspace_path TEXT NOT NULL, -- Absoluter Pfad zum Workspace-Ordner
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
```
### Tabelle: `conversations`
Speichert die Konversationshistorie pro Agent (fuer Kontext bei Neustart).
```sql
CREATE TABLE conversations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
workspace_id INTEGER NOT NULL REFERENCES workspaces(id),
discord_msg_id TEXT NOT NULL UNIQUE, -- Discord Message-ID (Deduplizierung)
role TEXT NOT NULL, -- 'user' oder 'assistant'
content TEXT NOT NULL,
author_name TEXT, -- Discord-Username des Absenders
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_conversations_workspace ON conversations(workspace_id, created_at);
```
Entscheidung: Die Konversationstabelle dient primaer dazu, bei einem Bot-Neustart den Kontext wiederherstellen zu koennen. Sie ist kein Chat-Archiv -- alte Eintraege koennen bei Bedarf gekuerzt werden.
---
## Konfiguration
### `.env`
```env
DISCORD_BOT_TOKEN=...
DISCORD_GUILD_ID=... # Optionaler Fallback, wenn nur ein Server unterstuetzt wird
CLAUDE_PATH=... # Optional: Pfad zur claude CLI (Standard: "claude" im PATH)
```
**Kein ANTHROPIC_API_KEY noetig.** DisClaw verwendet die Claude Code CLI, die mit einem Claude Pro/Max-Abonnement funktioniert.
### `disclaw.yaml` (globale Konfiguration)
```yaml
# Pfad, unter dem Workspace-Ordner erstellt werden
workspaces_root: "./workspaces"
# Name des Management-Kanals
management_channel: "disclaw"
# Claude Code CLI Befehl (Standard: "claude")
claude_command: "claude"
# Timeout in Sekunden fuer Claude-CLI-Prozesse (Standard: 120)
claude_timeout_seconds: 120
```
### `agent.yaml` (pro Workspace -- nur DisClaw-Metadaten)
```yaml
name: "frontend-dev"
display_name: "Frontend Dev"
role: "Frontend-Entwickler fuer das Webprojekt"
channel_id: "1234567890"
```
### `CLAUDE.md` (pro Workspace -- Agenten-Identitaet)
Die `CLAUDE.md`-Datei ist der primaere Identitaetsmechanismus. Claude Code liest sie automatisch, wenn der Workspace als Arbeitsverzeichnis gesetzt wird. Sie enthaelt:
- Name und Rolle des Agenten
- Persoenlichkeitsmerkmale
- Verhaltensrichtlinien
- Projektspezifischen Kontext
---
## Nachrichtenfluss
Schritt-fuer-Schritt-Ablauf, wenn ein Benutzer eine Nachricht in einem Agent-Kanal schreibt:
```
1. Discord Event: messageCreate
- Bot prueft: Nachricht von einem Bot? -> Ignorieren
- Bot prueft: Nachricht in einem bekannten Kanal? -> Weiter
2. Message Router
- DB-Abfrage: SELECT * FROM workspaces WHERE channel_id = ?
- Kein Treffer? -> Nachricht ignorieren
- Treffer im Management-Kanal? -> Command Handler
- Treffer in Agent-Kanal? -> Agent Runner
3. Agent Runner
- Lade agent.yaml aus dem Workspace-Ordner (Validierung)
- Baue Prompt zusammen:
- Konversationshistorie aus der DB
- Laufzeitkontext (Channel-Name, Datum)
- Neue Benutzernachricht
- Starte Claude Code CLI als Kindprozess:
claude -p "<prompt>" --output-format json
mit cwd = workspace_path
- Claude Code liest automatisch die CLAUDE.md im Workspace
- Parse JSON-Ausgabe und extrahiere Textantwort
4. Antwort zurueck
- Speichere User-Nachricht in conversations (role: 'user')
- Speichere Agent-Antwort in conversations (role: 'assistant')
- Sende Antwort in den Discord-Kanal
- Bei langen Antworten: automatisch aufteilen (Discord-Limit: 2000 Zeichen)
```
### Sonderfaelle
- **Lange Antworten**: Nachrichten ueber 2000 Zeichen werden an sinnvollen Stellen aufgeteilt (Zeilenumbrueche bevorzugt)
- **Typing-Indikator**: Bot zeigt "tippt..." an, waehrend Claude arbeitet
- **Fehlerbehandlung**: Bei CLI-Fehlern wird eine verstaendliche Nachricht im Kanal gepostet
- **Timeout**: Claude-CLI-Prozesse werden nach 120 Sekunden (konfigurierbar) abgebrochen
- **CLI nicht gefunden**: Verstaendliche Fehlermeldung mit Installationshinweis
---
## Agenten-Identitaet
Jeder Agent hat eine eigene Identitaet, die aus der `CLAUDE.md`-Datei im Workspace-Ordner geladen wird. Claude Code liest diese Datei automatisch.
### Identitaetsmechanismus
```
CLAUDE.md (im Workspace) = Primaere Identitaet
- Name, Rolle, Persoenlichkeit
- Verhaltensrichtlinien
- Projektspezifischer Kontext
agent.yaml (im Workspace) = DisClaw-Routing-Metadaten
- Name (fuer DB-Lookup)
- Channel-ID (fuer Kanal-Zuordnung)
- Display-Name (fuer Anzeige)
Konversationshistorie (aus DB) = Laufzeitkontext
- Letzte 30 Nachrichten werden dem Prompt vorangestellt
```
Im Gegensatz zur vorherigen Architektur (Claude Agent SDK mit System-Prompt) wird die Identitaet nicht programmatisch zusammengebaut, sondern direkt von Claude Code aus der `CLAUDE.md` gelesen. Das bedeutet:
- Aenderungen an der `CLAUDE.md` werden sofort wirksam (bei der naechsten Nachricht)
- Benutzer koennen die `CLAUDE.md` direkt bearbeiten, um das Verhalten anzupassen
- Die gleiche `CLAUDE.md` funktioniert auch, wenn man Claude Code interaktiv im Workspace-Ordner startet
### Workspace-Erstellung
Beim `/new-agent`-Befehl werden Name und Rolle als Parameter uebergeben. Daraus werden generiert:
1. `agent.yaml` -- Routing-Metadaten
2. `CLAUDE.md` -- Reichhaltige Identitaetsdatei mit Rolle, Persoenlichkeit und Richtlinien
3. `.claude/commands/` -- Verzeichnis fuer agenten-spezifische Custom Commands
4. `.claude/settings.json` -- Claude-Code-Einstellungen
```
/new-agent name:frontend-dev role:Frontend-Entwickler
```
---
## Setup-Ablauf
### Voraussetzungen
- Node.js v20+
- Claude Code CLI (`npm install -g @anthropic-ai/claude-code`)
- Claude Pro oder Max Abonnement (fuer die CLI)
- Discord-Bot-Token
### Ersteinrichtung
Die einfachste Methode ist der `/setup` Custom Command in Claude Code:
```bash
cd disclaw/
claude
# Dann im Claude-Code-Chat:
/setup
```
Alternativ manuell:
```
1. Benutzer erstellt Discord-Bot ueber Discord Developer Portal
2. Benutzer konfiguriert .env (DISCORD_BOT_TOKEN, DISCORD_GUILD_ID)
3. Benutzer fuehrt `npm install && npm run build && npm run start` aus
4. Bot startet:
a. Laedt .env und disclaw.yaml
b. Initialisiert SQLite-Datenbank (erstellt Tabellen falls noetig)
c. Verbindet sich mit Discord
d. Prueft: Existiert der Management-Kanal (#disclaw)?
- Nein -> Erstellt ihn, speichert channel_id in der DB
- Ja -> Laedt bestehende Zuordnung
e. Registriert /new-agent Slash-Command
f. Sendet Begruessungsnachricht im Management-Kanal
5. Bot wartet auf Events (messageCreate, interactionCreate)
```
### /new-agent Ablauf
```
1. Benutzer schreibt /new-agent name:researcher role:Recherche-Agent
2. Command Handler:
a. Validiert: Name eindeutig? Keine Sonderzeichen?
b. Erstellt Discord-Kanal: #researcher
c. Erstellt Ordner: workspaces/researcher/
d. Generiert: workspaces/researcher/CLAUDE.md (Agenten-Identitaet)
e. Generiert: workspaces/researcher/agent.yaml (Metadaten)
f. Generiert: workspaces/researcher/.claude/ (Konfiguration)
g. Speichert Zuordnung in DB (workspaces-Tabelle)
h. Antwortet im Management-Kanal: "Agent 'researcher' erstellt in #researcher"
3. Ab sofort: Nachrichten in #researcher werden vom Researcher-Agent beantwortet
```
---
## Architekturentscheidungen
### ADR-001: Claude Code CLI statt Agent SDK
**Status**: Akzeptiert (ersetzt vorherige Entscheidung fuer Claude Agent SDK)
**Kontext**: Agenten koennten ueber das Claude Agent SDK (`@anthropic-ai/claude-agent-sdk`), durch die Claude Code CLI oder direkt ueber die Anthropic API angesprochen werden.
**Entscheidung**: Wir verwenden die Claude Code CLI (`claude -p "prompt" --output-format json`). Vorteile:
- Kein API-Key noetig -- funktioniert mit Claude Pro/Max-Abonnement
- Automatische CLAUDE.md-Erkennung als Identitaetsmechanismus
- Zugang zu allen Claude-Code-Tools (Dateisystem, Bash, etc.)
- Einfacherer Setup-Prozess fuer Endbenutzer
**Konsequenzen**: Pro Nachricht wird ein neuer Prozess gestartet (kein persistenter Agent-Zustand). Die Konversationshistorie wird ueber die DisClaw-Datenbank verwaltet und dem Prompt vorangestellt. Leichter Overhead durch Prozess-Spawn, aber akzeptabel fuer den Chat-Anwendungsfall.
### ADR-002: SQLite statt reiner Dateispeicherung
**Status**: Akzeptiert
**Kontext**: Kanal-Zuordnungen und Konversationen koennten in JSON-Dateien oder in SQLite gespeichert werden.
**Entscheidung**: SQLite ueber better-sqlite3. Synchrone API passt zum Message-Handler-Modell, atomare Schreibvorgaenge verhindern Datenverlust.
**Konsequenzen**: Eine Abhaengigkeit mehr (better-sqlite3 ist eine native Erweiterung). Dafuer zuverlaessige Persistenz, einfache Abfragen und gute Performance bei kleinen bis mittleren Datenmengen.
### ADR-003: Ein Bot-Prozess, CLI-Prozesse pro Nachricht
**Status**: Akzeptiert (aktualisiert)
**Kontext**: Man koennte pro Agent einen persistenten Prozess starten, alle Agenten in einem Bot-Prozess verwalten, oder pro Nachricht einen CLI-Prozess starten.
**Entscheidung**: Ein einzelner Bot-Prozess (Node.js) empfaengt Discord-Nachrichten und startet pro Nachricht einen `claude` CLI-Prozess. Der CLI-Prozess terminiert nach der Antwort.
**Konsequenzen**: Einfacheres Ressourcenmanagement -- kein Speicher fuer idle Agenten. Leichter Overhead durch Prozess-Spawn. Konversationskontext muss explizit ueber die DB verwaltet werden. Ein abgestuerzter CLI-Prozess betrifft nur eine einzelne Nachricht, nicht den gesamten Bot.
### ADR-004: CLAUDE.md als Identitaetsmechanismus
**Status**: Akzeptiert
**Kontext**: Die Agenten-Identitaet (Name, Rolle, Persoenlichkeit, Anweisungen) muss Claude mitgeteilt werden. Optionen: System-Prompt via API, CLAUDE.md-Datei, oder beides.
**Entscheidung**: Die `CLAUDE.md`-Datei im Workspace-Ordner ist der primaere Identitaetsmechanismus. Claude Code liest sie automatisch. Kein programmatisch zusammengebauter System-Prompt mehr.
**Konsequenzen**: Benutzer koennen Agenten-Verhalten durch direkte Bearbeitung der `CLAUDE.md` anpassen. Die gleiche Konfiguration funktioniert interaktiv und ueber DisClaw. Weniger Code in der Identity-Schicht.
---
## Zukuenftige Phasen
In der Reihenfolge der voraussichtlichen Prioritaet:
1. **Berechtigungssystem** -- Rollenbasierter Zugriff, definieren welche Agenten welche Dateien / Befehle nutzen duerfen
2. **Weitere Slash-Commands** -- `/list-agents`, `/delete-agent`, `/agent-config`
3. **Agent-zu-Agent-Kommunikation** -- Agenten koennen einander Aufgaben delegieren
4. **Docker-Isolation** -- Jeder Agent laeuft in einem eigenen Container
5. **Streaming-Antworten** -- Teilantworten waehrend Claude arbeitet in Discord anzeigen
6. **Web-Dashboard** -- Uebersicht ueber Agenten, Konversationen und Nutzung
7. **Dateisystem-Watcher** -- Agenten reagieren auf Datei-Aenderungen in ihrem Workspace