153 lines
6.6 KiB
Markdown
153 lines
6.6 KiB
Markdown
# 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 (5–60s 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`)
|