408 lines
16 KiB
Markdown
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
|