Files
ai-agent/CLAUDE.md
Christoph K. b1a576f61e tests
2026-03-20 07:08:00 +01:00

153 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
**my-brain-importer** is a personal AI assistant and RAG (Retrieval-Augmented Generation) system written in Go. It ingests Markdown notes into a Qdrant vector database, answers questions using a local LLM (LocalAI), and is primarily controlled via Discord. A background daemon sends proactive email summaries and a daily morning briefing.
## Commands
```bash
# Build all binaries (Linux + Windows cross-compile)
bash build.sh
# Primary entry point: Discord Bot (includes daemon)
go run ./cmd/discord/
# CLI tools
go run ./cmd/ingest/ # Markdown importieren
go run ./cmd/ingest/ bild.json # JSON importieren
go run ./cmd/ask/ "your question here" # Frage stellen
# Test: IMAP-Verbindung
go run ./cmd/mailtest/
# Test: LLM-Zusammenfassung ohne IMAP
go run ./cmd/mailtest/ -llm-only
# Run tests
go test ./...
# Tidy dependencies
go mod tidy
# Deployment auf Remote-Server (192.168.1.118)
cp deploy.env.example deploy.env # einmalig: Credentials eintragen
bash deploy.sh # build + upload + systemctl restart
```
Binaries are output to `./bin/`. The `config.yml` file must exist in the working directory at runtime.
## Architecture
```
Discord (primäres Interface)
↓ Slash-Commands + @Mention
cmd/discord/main.go
├── internal/agents/research/ → brain.AskQuery() + Konversationsverlauf
├── internal/agents/memory/ → brain.RunIngest(), brain.IngestChatMessage()
├── internal/agents/task/ → tasks.json (atomisches JSON, DueDate + Priority)
└── internal/agents/tool/email/ → IMAP + LLM-Zusammenfassung + Move to Processed
[Daemon-Goroutine] startDaemon()
├── Email-Check (alle N min) → #localagent Discord-Channel
└── Morgen-Briefing (täglich 8h) → Tasks + Emails kombiniert
cmd/ingest/ + cmd/ask/ (CLI-Tools, direkt nutzbar)
internal/brain/ (Core RAG-Logik)
Qdrant (gRPC) + LocalAI (HTTP, OpenAI-kompatibel)
```
### Packages
| Package | Zweck |
|---------|-------|
| `cmd/discord/` | Discord Bot + Daemon (primärer Einstiegspunkt) |
| `cmd/ask/` | CLI-Tool: Fragen stellen |
| `cmd/ingest/` | CLI-Tool: Markdown/JSON importieren |
| `cmd/mailtest/` | Testprogramm: IMAP + LLM-Test |
| `internal/brain/` | Core RAG: Embeddings, Qdrant-Suche, LLM-Streaming |
| `internal/config/` | Konfiguration + Client-Initialisierung (globale `Cfg`) |
| `internal/agents/` | Agent-Interface (`Request`/`Response`/`HistoryMessage`) |
| `internal/agents/research/` | Research-Agent: Wissensdatenbank-Abfragen (mit History) |
| `internal/agents/memory/` | Memory-Agent: Ingest + Chat-Speicherung |
| `internal/agents/task/` | Task-Agent: Aufgabenverwaltung (tasks.json) |
| `internal/agents/tool/` | Tool-Dispatcher |
| `internal/agents/tool/email/` | IMAP-Client + LLM-Email-Analyse + Move to Processed |
### Discord Commands
| Slash-Command | @Mention | Funktion |
|---------------|----------|---------|
| `/ask`, `/research` | `@bot <frage>` | Wissensdatenbank abfragen (mit Chat-Gedächtnis) |
| `/asknobrain` | | Direkt an LLM (kein RAG) |
| `/memory store` | `@bot remember <text>` | Text speichern |
| `/memory ingest` | `@bot ingest` | Markdown neu einlesen |
| `/task add <text> [faellig] [prioritaet]` | `@bot task add <text> [--due YYYY-MM-DD] [--priority hoch]` | Task hinzufügen |
| `/task list/done/delete` | `@bot task <aktion>` | Aufgaben verwalten |
| `/email summary/unread/remind` | `@bot email <aktion>` | Email-Analyse |
| `/remember` | | Alias für `/memory store` |
| `/ingest` | | Alias für `/memory ingest` |
## Key Patterns
- **Deterministic IDs**: SHA256 of `source:text` — upserting the same content is always idempotent
- **Excluded directories**: `05_Agents` and `.git` are skipped during markdown ingest
- **config.yml** must be present in the working directory at runtime
- **Agent Interface**: alle Agenten implementieren `Handle(Request) Response`
- **Defer-first Pattern**: Discord-Handlers senden sofort Defer, dann berechnen — nie >3s warten
- **LLM-Fallback**: Email-Zusammenfassung zeigt Rohliste wenn LLM nicht erreichbar
- **Daemon**: läuft als Goroutine im Discord-Bot-Prozess (`startDaemon()`)
- **config.Cfg**: globale Variable — bei Tests muss `config.LoadConfig()` aufgerufen oder Cfg direkt gesetzt werden
- **Konversationsverlauf**: Pro Discord-Channel werden die letzten 10 Frage-Antwort-Paare in-memory gehalten und als History an `brain.AskQuery()` übergeben
- **Task-Felder**: `DueDate *time.Time` und `Priority string` (hoch/mittel/niedrig) — rückwärtskompatibel (omitempty)
- **Email processed_folder**: Nach Zusammenfassung werden ungelesene Emails in konfigurierten IMAP-Ordner verschoben (leer = deaktiviert)
- **Morgen-Briefing**: `dailyBriefing()` kombiniert offene Tasks (mit Fälligkeits-Highlighting) + ungelesene Emails täglich um 8:00
## config.yml Neue Felder
```yaml
email:
processed_folder: "Processed" # Zielordner nach Zusammenfassung (leer = kein Verschieben)
daemon:
task_reminder_hour: 8 # Uhrzeit des Morgen-Briefings (Standard: 8)
```
## Deployment
```bash
# deploy.env (nicht in Git):
DEPLOY_HOST=192.168.1.118
DEPLOY_USER=christoph
DEPLOY_PASS=...
DEPLOY_DIR=/home/christoph/brain-bot
SERVICE_NAME=brain-bot
DEPLOY_CONFIG=true
# Systemd-Service (einmalig):
sudo systemctl unmask brain-bot # falls masked
```
Script `deploy.sh` baut das Linux-Binary, überträgt es per `sshpass`/`scp` und startet den systemd-Service neu.
## Model Limitations
Das konfigurierte Modell (`Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF`) hat folgende Grenzen:
- **Kontextfenster**: Begrenzt — bei sehr langen Email-Listen oder vielen Chunks kann die Antwort abgeschnitten werden (`MaxTokens: 600`)
- **Latenz**: Lokales Modell auf NAS — Antwortzeiten variieren (560s je nach Last)
- **Encoding**: Betreffzeilen in `windows-1252` (Strato) werden nicht dekodiert — das LLM interpretiert sie trotzdem meist korrekt
- **Halluzinationen**: Das Modell kann bei unklarem Kontext eigenes Wissen einmischen — ist im System-Prompt mit "Aus meinem Wissen:" markiert
- **Streaming-Timeout**: Kein expliziter Timeout auf LLM-Calls — bei Hänger wird Discord-Interaktion erst nach 15min ungültig
## External Services
- **Qdrant** (`192.168.1.4:6334`) — Vektordatenbank, gRPC
- **LocalAI** (`192.168.1.118:8080`) — lokales LLM, OpenAI-kompatibles API
- **Strato IMAP** (`imap.strato.de:143`, STARTTLS) — Email-Abruf
- **Discord** — primäres Interface (Bot-Token in `config.yml`)