6.6 KiB
6.6 KiB
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
# 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_Agentsand.gitare 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.TimeundPriority 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
email:
processed_folder: "Processed" # Zielordner nach Zusammenfassung (leer = kein Verschieben)
daemon:
task_reminder_hour: 8 # Uhrzeit des Morgen-Briefings (Standard: 8)
Deployment
# 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)