Files
gott/ARCHITECTURE.md
T
Meleki 730c14aa23 docs: Dokumentation aktualisiert – API-Key-Scanner, passive Usage, Chat-Badge, Key-Check
ARCHITECTURE.md:
- Neue Services: KeyScannerService, AnthropicKeyChecker
- scanned_keys Tabelle, api_keys erweitert (status, plan, usage, source_url)
- API-Key-Verwaltung komplett überarbeitet: Key-Check mit korrekten Headers,
  passive Usage-Aktualisierung, GitHub-Scanner, Chat Usage-Badge
- Scanner-Endpunkte dokumentiert (scan, scanned, adopt, recheck)
- Tool-Anzahl 16 → 17

ARCHITECTURE_QUICK.md:
- Gleiche Struktur-Updates (Services, Tabellen, Endpunkte, Tool-Anzahl)
- Chat-Page: Usage-Badge-Overlay + Key-Switch-Modal
- Passive Usage-Aktualisierung nach jedem API-Request

README.md:
- Tool-Anzahl 16 → 17
- API-Key-Verwaltung mit Scanner, passive Usage, Chat-Badge
2026-03-12 22:37:33 +01:00

99 KiB
Raw Blame History

ARCHITECTURE.md – Gott

Gott ist eine selbst-gehostete AI-Chat-Plattform, gebaut auf .NET 10 mit Anthropic Claude API als Haupt-Provider sowie OpenAI-kompatiblen Providern (Nvidia, Pollinations, Gemini). Sie bietet Multi-User-Support, persistente Agent-Memory, 17 Tools (Dateien, Shell, Suche, Memory, Remote-Execution), semantische Suche via lokalen Embeddings, Telegram-Integration, Cronjobs, Remote-Verbindungen und eine Krea-Bildgenerierung – alles über ein Vanilla-JavaScript-Frontend gesteuert.


Inhaltsverzeichnis

  1. Überblick
  2. Tech-Stack
  3. Projektstruktur
  4. Datenmodell
  5. Backend-Architektur
  6. Frontend-Architektur
  7. Multi-Provider-System (OpenAI-kompatibel)
  8. Chat-Pipeline
  9. Tool-System
  10. Agent-System
  11. System-Prompt-Aufbau
  12. Memory-System
  13. Skill-System
  14. Telegram-Integration
  15. Cronjob-System
  16. Krea-Bildgenerierung
  17. Auth & Multi-User
  18. Admin-Benutzerverwaltung
  19. Multi-Agent System (Preparer + Review + Finalizer)
  20. Interaktive Rückfragen (ask_user_choice)
  21. Plan-Modus
  22. Nachrichten teilen (Shared Messages)
  23. Workspace & File-Explorer
  24. Avatar-System
  25. LaTeX/Math-Rendering
  26. Windows Desktop App
  27. OpenClaw Import
  28. Remote-Verbindungen
  29. Semantische Suche (Embedding)
  30. API-Key-Verwaltung
  31. Deployment
  32. Konfiguration
  33. Datenbank-Migrationen

Überblick

┌─────────────────────────────────────────────────────────────┐
│                      Browser / WebView2                     │
│              Vanilla JS SPA (wwwroot/)                      │
├─────────────────────────────────────────────────────────────┤
│                   ASP.NET 10 Minimal API                    │
│              http://0.0.0.0:19000                           │
├──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬────┤
│ Auth │ Chat │ Hist │ Sess │Agent │ Tele │ Cron │ Krea │Adm │
│      │  SSE │      │      │      │ gram │ jobs │ Img  │ in │
│      │      │      │      │      │      │      │      │Keys│
├──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴────┤
│              Services Layer                                 │
│  AnthropicService · OpenAiService · ChatService · ToolService│
│  DatabaseService · MemoryService · SkillService · SseHelper │
│  EmbeddingService · VectorSearchService                     │
│  RemoteConnectionManager · TelegramService                  │
│  CronjobService · KreaService                               │
├─────────────────────────────────────────────────────────────┤
│              SQLite (data/gott.db) via Dapper               │
│              ONNX Runtime (Embeddings)                      │
│              Filesystem (data/agents/, data/skills/)        │
├─────────────────────────────────────────────────────────────┤
│              Anthropic Claude API (claude-sonnet/opus/haiku) │
│              OpenAI-kompatible APIs (Nvidia, Pollinations, Gemini) │
│              Krea API (Bildgenerierung)                     │
│              Telegram Bot API                               │
└─────────────────────────────────────────────────────────────┘

Tech-Stack

Schicht Technologie
Runtime .NET 10 (ohne Nullable, ohne Implicit Usings)
Web ASP.NET Minimal API, Kestrel
Datenbank SQLite via Microsoft.Data.Sqlite + Dapper
AI Anthropic Claude API (Streaming SSE + Non-Streaming), OpenAI-kompatible APIs (Nvidia, Pollinations, Gemini)
Images SixLabors.ImageSharp (Resize, Thumbnails)
Cron Cronos (Cron-Expression-Parsing)
Frontend Vanilla JavaScript SPA (kein Framework)
Markdown marked.js (Client-side Rendering)
LaTeX KaTeX 0.16.21 (Math-Rendering, self-hosted mit woff2-Fonts)
Editor CodeMirror 5 + EasyMDE
Embeddings Microsoft.ML.OnnxRuntime + all-MiniLM-L6-v2 (384-dim Sentence-Embeddings)
Icons Font Awesome
Fonts Inter, JetBrains Mono (self-hosted)
Desktop WPF + WebView2 (.NET 10, Windows-only)

Projektstruktur

gott/
├── Program.cs                    # Startup, DI, Middleware, Routing
├── gott.csproj                   # Projekt-Definition (.NET 10)
├── appsettings.json              # Konfiguration (Tokens, Limits)
├── deploy.sh                     # Deployment-Script (systemctl)
│
├── Models/                       # Daten-Modelle (Records)
│   ├── UserRecord.cs
│   ├── AgentRecord.cs
│   ├── SessionRecord.cs
│   ├── ChainRecord.cs
│   ├── MessageRecord.cs          # + AttachmentRecord
│   ├── ArchiveRecord.cs
│   ├── CronjobRecord.cs
│   ├── KreaImageRecord.cs
│   ├── SharedMessageRecord.cs    # Geteilte Nachrichten (Share-Token)
│   ├── TelegramBotRecord.cs     # Telegram Bot Entität
│   ├── ChatModels.cs             # ChatMessage, ChatRequest, AttachmentInfo/Block
│   ├── ApiKeyRecord.cs           # API-Key-Verwaltung (Provider, Name, Key, IsActive, Status, Plan, Usage, SourceUrl)
│   ├── ScannedKeyRecord.cs       # Gescannte GitHub-Keys (SourceUrl, Status, Plan, Usage, AdoptedApiKeyId)
│   └── ChatContext.cs            # Runtime-Kontext für einen Chat + ReviewContext
│
├── Services/                     # Business-Logic
│   ├── DatabaseService.cs        # SQLite Schema, Migrationen, Core (partial class)
│   ├── DatabaseService.Sessions.cs  # Sessions, Archives, Chains, Messages, Attachments
│   ├── DatabaseService.Agents.cs    # Agents, Agent Skills
│   ├── DatabaseService.Users.cs     # Users, Shared Messages
│   ├── DatabaseService.Integrations.cs # Telegram, Cronjobs, API Keys, OpenClaw Import
│   ├── AuthService.cs            # Token-basierte Authentifizierung
│   ├── ChatService.cs            # Kontext-Aufbau, History-Builder
│   ├── AnthropicService.cs       # Claude API (Streaming + Non-Streaming)
│   ├── OpenAiService.cs          # OpenAI-kompatible Provider (Nvidia, Pollinations, Gemini)
│   ├── SseHelper.cs              # Shared SSE-Utilities (WriteSseEvent, TryWriteSse, FinalizeChain)
│   ├── ToolService.cs            # Tool-Definitionen + Ausführung (17 Tools)
│   ├── SystemPromptBuilder.cs    # Modularer System-Prompt aus Blöcken
│   ├── MemoryService.cs          # Agent-Gedächtnis (Dateisystem)
│   ├── SkillService.cs           # Skill-Verwaltung (Dateisystem)
│   ├── EmbeddingService.cs       # Lokales Sentence-Embedding (all-MiniLM-L6-v2, ONNX)
│   ├── VectorSearchService.cs    # Semantische Suche über Message-Embeddings + Memory-Files
│   ├── EmbeddingBackgroundService.cs # Backfill + Live-Embedding neuer Messages (BackgroundService)
│   ├── RemoteConnectionManager.cs # WebSocket-basierte Remote-Verbindungen (Command-Execution)
│   ├── TelegramService.cs        # Telegram Bot API Integration
│   ├── CronjobService.cs         # BackgroundService für Cron-Tasks
│   ├── KreaService.cs            # Krea Image Generation API
│   ├── ImageService.cs           # Bild-Resize + WebP-Konvertierung (512px + 256px Thumbnail)
│   ├── StreamingTracker.cs       # Tracking aktiver Streams + CancellationTokenSource für Stop
│   ├── WorkspaceHelper.cs       # Workspace-Pfad-Auflösung (relativ → absolut)
│   ├── KeyScannerService.cs      # GitHub Code-Search nach geleakten API-Keys
│   └── AnthropicKeyChecker.cs    # Anthropic Key-Validierung + Usage-Header-Auswertung
│
├── Endpoints/                    # HTTP API (Minimal API)
│   ├── AuthEndpoint.cs           # Login, Logout, Me
│   ├── ChatEndpoint.cs           # POST /api/chat (SSE Streaming)
│   ├── HistoryEndpoint.cs        # History, Archive, Attachments, Marks
│   ├── SessionEndpoint.cs        # CRUD + SystemPrompt, Exec, Git-Status
│   ├── AgentEndpoint.cs          # CRUD
│   ├── WorkspaceEndpoint.cs      # File-Tree, File-Read/Write, Browse, Agent-Files
│   ├── TelegramEndpoint.cs       # Bot-CRUD, Webhook, Session-Config, Registration
│   ├── OpenClawEndpoint.cs      # OpenClaw Session Import
│   ├── CronjobEndpoint.cs        # CRUD + Toggle, Manual Run
│   ├── KreaEndpoint.cs           # Generate, List, File-Serve
│   ├── SkillEndpoint.cs          # List, Agent-Skill-Mapping, Output-Files
│   ├── ModelsEndpoint.cs         # Provider-Modelle (nvidia, pollinations, gemini, refresh)
│   ├── SharedEndpoint.cs         # Nachrichten teilen (öffentliche Links)
│   ├── AdminEndpoint.cs          # Admin: User-CRUD, Impersonate (Admin-only)
│   ├── ApiKeysEndpoint.cs        # Admin: API-Key-CRUD, Activate/Deactivate, Check, Scan, Adopt (Admin-only)
│   ├── RemoteEndpoint.cs         # Remote-Verbindungen: WebSocket, Assign/Unassign, PowerShell-Script
│   ├── ServerSettingsEndpoint.cs  # Admin: Server-Settings lesen/schreiben (Admin-only)
│   ├── ProfileEndpoint.cs        # Profil, Persona, Passwort
│   ├── SettingsEndpoint.cs       # User-Settings (JSON blob)
│   ├── BackupEndpoint.cs         # Backup als tar.gz Download
│   └── InfoEndpoint.cs           # Build-Zeitstempel + Embedding-Status
│
├── Middleware/
│   └── AuthMiddleware.cs         # Cookie-basierte Token-Validierung
│
├── Extensions/
│   └── HttpContextExtensions.cs  # GetUserId(), IsAdmin()
│
├── Templates/                    # Standard-Templates für neue Agents
│   ├── IDENTITY.md               # Wer bin ich? (Name, Sprache)
│   ├── SOUL.md                   # Persönlichkeit, Verhalten
│   └── USER.md                   # Infos über den User
│
├── wwwroot/                      # Frontend (Vanilla JS SPA)
│   ├── index.html                # Single HTML Entry Point
│   ├── css/                      # Stylesheets
│   │   ├── theme.css             # CSS Custom Properties (Dark Theme)
│   │   ├── base.css              # Reset, Grundlayout
│   │   ├── main.css              # Sidebar, Layout-Struktur
│   │   ├── chat.css              # Chat-Nachrichten, Bubbles
│   │   ├── dashboard.css         # Dashboard-Grid
│   │   ├── form.css              # Formulare, Inputs, Avatar-Editor-Modal
│   │   ├── markdown.css          # Markdown + KaTeX Rendering-Styles
│   │   ├── file-explorer.css     # File-Explorer Panel
│   │   ├── login.css             # Login-Seite
│   │   ├── mobile.css            # Responsive Anpassungen
│   │   ├── tooltip.css           # Tooltip-Styles
│   │   ├── fonts.css             # @font-face Definitionen
│   │   ├── placeholder.css       # Placeholder/Loading States
│   │   ├── katex.min.css          # KaTeX Math-Rendering Styles
│   │   ├── codemirror.min.css    # CodeMirror Editor
│   │   ├── easymde.min.css       # EasyMDE Editor
│   │   └── fonts/                # KaTeX woff2 Fonts (21 Dateien)
│   ├── js/
│   │   ├── app.js                # App-Initialisierung, Auth-Check
│   │   ├── router.js             # Client-side SPA Router
│   │   ├── api.js                # API-Client (fetch wrapper)
│   │   ├── ui-helpers.js         # DOM-Helpers ($, esc, truncate), Toast, ScrollDown, Meta-Bar
│   │   ├── markdown.js           # Markdown-Rendering (renderMarkdown, LaTeX/Code-Schutz)
│   │   ├── cards.js              # Card-Builder (buildSessionCard, buildAgentCard)
│   │   ├── msg-actions.js        # Nachrichten-Aktionen (Delete, Mark, Share, Reply, Timestamp)
│   │   ├── tool-ui.js            # Tool-Boxes, Diffs, Todo-Liste, Visibility-Logik
│   │   ├── modals.js             # Modale Dialoge (System-Prompt, Command-Output, Krea-Image, Remote)
│   │   ├── stream-ui.js          # Stream-Bubble, Review-Streaming
│   │   ├── bubbles.js            # Message Bubbles (User, Assistant, Error, Warning, Choice, Review)
│   │   ├── chat.js               # Chat-Logic, SSE-Streaming, Plan-Mode
│   │   ├── history.js            # History-Rendering, Polling
│   │   ├── archive.js            # Archiv-Loading
│   │   ├── reply.js              # Reply/Quote-Handling
│   │   ├── files.js              # File-Upload, Workspace-Refs
│   │   ├── session.js            # Session-Verwaltung
│   │   ├── file-explorer.js      # File-Explorer Komponente
│   │   ├── avatar-editor.js      # Wiederverwendbares Avatar-Editor-Modal
│   │   ├── commands-ui.js        # Custom-Commands UI
│   │   ├── emoji.js              # Emoji-Picker
│   │   ├── emoji.userdata.js     # Häufig genutzte Emojis
│   │   ├── tooltip.js            # Tooltip-System
│   │   ├── title.js              # Tab-Titel-Management + Embedding-Warnung
│   │   ├── pages/                # Seiten-Komponenten
│   │   │   ├── chat-page.js      # Haupt-Chat-Ansicht (inkl. Remote-Button, Usage-Badge-Overlay, Key-Switch-Modal)
│   │   │   ├── dashboard.js      # Dashboard / Home (inkl. API-Keys-Link)
│   │   │   ├── session-page.js   # Session-Einstellungen
│   │   │   ├── agent-page.js     # Agent-Editor
│   │   │   ├── telegram-bot-page.js # Telegram-Bot-Editor
│   │   │   ├── cronjob-page.js   # Cronjob-Verwaltung
│   │   │   ├── profile-page.js   # Profil-Bearbeitung
│   │   │   ├── admin-page.js      # Admin: Benutzerverwaltung
│   │   │   ├── api-keys-page.js   # Admin: API-Key-Verwaltung + Check + GitHub-Scanner
│   │   │   ├── settings-page.js  # App-Einstellungen
│   │   │   ├── login-page.js     # Login-Formular
│   │   │   └── shared-page.js    # Öffentliche geteilte Nachricht
│   │   └── lib/                  # Vendor-Libraries
│   │       ├── marked.min.js     # Markdown Parser
│   │       ├── codemirror.min.js # Code Editor
│   │       ├── codemirror.cjs    # CM CommonJS Wrapper
│   │       ├── easymde.min.js    # Markdown Editor
│   │       ├── katex.min.js      # KaTeX Math-Rendering Engine
│   │       └── cm-mode-*.min.js  # CodeMirror Syntax-Modes
│   ├── remote.ps1                # PowerShell-Script für Remote-Client-Verbindung
│   ├── fonts/                    # Self-hosted Fonts (Inter, JetBrains Mono)
│   └── lib/font-awesome/         # Font Awesome Icons
│
├── WindowsApp/                   # Windows Desktop Client (WPF)
│   ├── Gott.csproj               # .NET 10 Windows, WebView2
│   ├── App.xaml / App.xaml.cs     # WPF Application
│   ├── MainWindow.xaml/cs        # WebView2 Host Window
│   └── appsettings.json          # Server-URL Konfiguration
│
└── Build/                        # Build-Output (NICHT editieren!)
    ├── Linux/
    │   ├── bin/  obj/  publish/
    └── Windows/
        ├── bin/  obj/  publish/
    └── data/
        ├── gott.db               # SQLite Datenbank
        ├── agents/               # Agent Memory-Dateien
        │   └── {agentId}/
        │       ├── IDENTITY.md
        │       ├── SOUL.md
        │       ├── MEMORY.md
        │       └── memory/       # Tages-Logs etc.
        ├── skills/               # Skill-Verzeichnisse
        │   └── {slug}/
        │       ├── SKILL.md
        │       ├── PROMPT.md
        │       └── output/
        ├── images/               # Krea-generierte Bilder
        ├── models/               # ONNX-Modelle (Embedding)
        │   └── all-MiniLM-L6-v2/ # Sentence-Embedding-Modell (model.onnx + vocab.txt)
        ├── models_cache.json     # Gecachte Provider-Modelle (Nvidia, Pollinations, Gemini)
        ├── logs/                 # Payload-Logs (optional)
        └── backup/               # Backup-Archive

Datenmodell

Entity-Relationship

User (1) ─── (*) Agent
User (1) ─── (*) Session
Agent (1) ─── (*) Session     (Session hat optional einen Agent)
Agent (1) ─── (*) Session     (Session hat optional einen Review-Agent)
Agent (1) ─── (*) Session     (Session hat optional einen Finalizer-Agent)
Agent (*) ─── (*) Skill       (via agent_skills Tabelle)
Session (1) ─── (*) Chain     (ein Chat-Request = eine Chain)
Session (1) ─── (*) Archive   (archivierte Chains)
Chain (1) ─── (*) Message
Message (1) ─── (*) Attachment
Session (1) ─── (*) Cronjob
User (1) ─── (*) Cronjob
User (1) ─── (*) SharedMessage
Message (1) ─── (*) SharedMessage
User (1) ─── (*) TelegramBot
TelegramBot (1) ─── (*) Session  (via telegram_bot_id)

Tabellen

Tabelle Beschreibung
users Benutzer (username, password_hash, display_name, is_admin, persona, settings, default_path)
tokens Auth-Tokens (token → user_id)
agents AI-Agenten (model – z.B. claude-sonnet-4-6 oder nvidia:deepseek-ai/deepseek-r1, custom_commands, auto_commit, use_soul/identity/user_info/memory, use_web_search, web_search_version, allow_user_choice, task_instruction, avatar_scale/offset, avatar_small, is_public)
sessions Chat-Sessions (description, image, image_small, workspace, context, custom_commands, telegram_bot_id, telegram_chat_id, avatar_scale/offset, preparer_agent_id, review_agent_id, max_review_iterations, finalizer_agent_id)
chains Request-Chains (model, tokens, iterations, timing, tool_choice, tool_names, stream_error_info, plan_mode, archive_id)
messages Einzelne Nachrichten (text, tool_use, tool_result, error, web_search_result), Tag für Sub-Agent-Markierung oder Import-Herkunft (openclaw-import), SortKey für korrekte Reihenfolge, thought_signature (Gemini)
attachments Datei-Anhänge (base64, image/document)
archives Archivierte Chain-Gruppen
agent_skills Agent ↔ Skill Zuordnung
cronjobs Geplante Tasks (cron expression, prompt, notify_session_id, is_enabled, last_run, next_run)
shared_messages Geteilte Nachrichten (Share-Token, Ablaufdatum)
telegram_bots Telegram Bots (bot_token, webhook_secret, name, is_public) – eigenständige Entität
api_keys API-Keys pro Provider (key_id, provider, name, api_key, is_active, status, plan, usage_7d, usage_5h, source_url, checked_at) – nur ein Key pro Provider aktiv
scanned_keys Gescannte GitHub-Keys (scanned_key_id, api_key, source_url, status, plan, usage_7d, usage_5h, adopted_api_key_id, deleted)
message_embeddings Sentence-Embeddings für semantische Suche (message_id, vector BLOB, session_id, agent_id)
memory_file_embeddings Embeddings von Memory-Dateien (agent_id, file_path, chunk_index, vector BLOB)

Zentrale Records

ChainRecord – Repräsentiert einen kompletten Request-Response-Zyklus:

  • ChainId – Eindeutige ID
  • SessionId – Zugehörige Session
  • AgentId – Zugehöriger Agent
  • Model – Verwendetes Modell (z.B. claude-sonnet-4-6, nvidia:deepseek-ai/deepseek-r1, gemini:gemini-2.5-flash)
  • SystemPrompt – Der vollständige System-Prompt (gespeichert für Nachvollziehbarkeit)
  • InputTokens, OutputTokens, CacheCreationTokens, CacheReadTokens – Token-Verbrauch
  • Iterations – Anzahl der Tool-Loop-Durchläufe
  • StopReason – end_turn, tool_use, max_iterations, error, client_disconnected, awaiting_user_choice, preparer_query
  • ToolChoice – Verwendete Tool-Choice-Strategie (automatisch: any wenn Workspace/Skills/Memory, sonst auto)
  • ToolNames – Komma-separierte Liste der verwendeten Tools
  • ArchiveId – Zugehöriges Archiv (wenn archiviert)
  • StreamErrorInfo – Fehlerdetails bei Stream-Abbrüchen
  • PlanMode – Ob die Chain im Plan-Modus erstellt wurde (informativ)
  • DurationMs – Gesamtdauer der Chain

MessageRecord – Eine einzelne Nachricht innerhalb einer Chain:

  • Role – user, assistant
  • Type – text, tool_use, tool_result, error, web_search_result
  • Content – Textinhalt oder JSON (bei tool_use: Input-JSON)
  • ToolName, ToolCallId – Bei Tool-Aufrufen
  • IsError – Ob die Nachricht ein Fehler ist
  • Iteration – Welche Tool-Loop-Iteration
  • AttachmentCount – Anzahl angehängter Dateien
  • AttachmentNames – JSON-Array mit Dateinamen
  • Tag – Markierung (null = normal, "preparer"/"review"/"finalizer" = Sub-Agent-Message (wird aus API-History gefiltert), "openclaw-import" = importierte Nachricht (wird immer in History einbezogen))
  • IsMarked – Als wichtig markierte Nachricht (wird in System-Prompt aufgenommen)
  • ThoughtSignature – Gemini thought_signature (für Gemini-Tool-Calls, wird im nächsten Request zurückgesendet)
  • DeletedOn – Soft-Delete Zeitstempel

SessionWithStats – Erweitertes Session-Objekt für Listen-Endpunkt:

  • Enthält alle SessionRecord-Felder + MessageCount, ArchiveMessageCount, TotalMessageCount
  • TelegramConfigured, TelegramLinked – Telegram-Status (Bot zugewiesen / Chat-ID verknüpft)
  • GitStatus – Inline Git-Status-Summary (Add, Edit, Delete, Outgoing) oder null wenn kein Workspace (wird im Endpoint hinzugefügt, nicht Teil des Records)
  • Image wird durch ImageSmall ersetzt (Thumbnail für Dashboard-Performance)

GitStatusSummary – Kompakte Git-Status-Info:

  • Add, Edit, Delete – Anzahl geänderter Dateien nach Typ
  • Outgoing – Anzahl ausgehender (nicht gepushter) Commits

Backend-Architektur

Program.cs – Startup

Die Program.cs ist der zentrale Einstiegspunkt und konfiguriert:

  1. Service-Registrierung – Alle Services als Singletons im DI-Container
  2. Datenbank-Initialisierung – DatabaseService erstellt Schema + Migrationen
  3. Default-User – Wird automatisch angelegt falls keine User existieren
  4. Middleware – Static Files → AuthMiddleware → Endpoints
  5. Endpoint-Mapping – Alle 17 Endpoint-Gruppen registriert
  6. Server – Kestrel auf http://0.0.0.0:{Port} (Port aus Config, Default 19000)

Initialisierungsreihenfolge:

RemoteConnectionManager → AuthService → DatabaseService → EnsureDefaultUser
→ ImageService, StreamingTracker, MemoryService, SkillService
→ EmbeddingService → VectorSearchService
→ ToolService → ChatService
→ AnthropicService (Token aus DB: api_keys) → OpenAiService (+ LoadModelsAsync)
→ TelegramService → KreaService
→ CronjobService (BackgroundService) + EmbeddingBackgroundService (BackgroundService)

Services

Service Typ Aufgabe
DatabaseService Singleton SQLite CRUD, Schema-Init, Migrationen, alle DB-Operationen
AuthService Singleton Token-Erzeugung/-Validierung, Passwort-Hashing (SHA256)
ChatService Singleton Chat-Kontext aufbauen, History aus DB rekonstruieren
AnthropicService Singleton Claude API Kommunikation (Streaming SSE + Non-Streaming), passive Usage-Aktualisierung nach jedem Request
OpenAiService Singleton OpenAI-kompatible Provider (Nvidia, Pollinations, Gemini) mit Tool-Calling, Streaming, Modell-Caching
ToolService Singleton Tool-Definitionen bereitstellen, Tool-Aufrufe ausführen
WorkspaceHelper Static Workspace-Pfad-Auflösung (relativ → absolut), Path-Traversal-Schutz
SystemPromptBuilder Static Modularer System-Prompt aus konfigurierbaren Blöcken + Reminder-Generierung
MemoryService Singleton Agent-Gedächtnis auf Dateisystem (MEMORY.md, IDENTITY.md etc.)
SkillService Singleton Skill-Discovery und -Management aus Dateisystem
TelegramService Singleton Telegram Bot API, Webhook-Handling, Nachrichten senden
CronjobService Background Minütlicher Check auf fällige Cronjobs, Ausführung via Claude
SseHelper Static Shared SSE-Utilities: WriteSseEvent, TryWriteSse, FinalizeChain, TruncateToolResult
EmbeddingService Singleton Lokales Sentence-Embedding via all-MiniLM-L6-v2 (ONNX, 384 Dimensionen), WordPiece-Tokenisierung
VectorSearchService Singleton Semantische Suche über Message-Embeddings + Memory-File-Embeddings (Cosine Similarity)
EmbeddingBackgroundService Background Backfill bestehender Messages + Live-Embedding neuer Messages/Memory-Files
RemoteConnectionManager Singleton WebSocket-basierte Remote-Verbindungen, Command-Execution auf verbundenen Clients
KreaService Singleton Krea API für Bildgenerierung, Job-Polling, Image-Download
ImageService Singleton Bild-Resize + WebP-Konvertierung (512px + 256px Thumbnail) für Avatare und Session-Bilder
StreamingTracker Singleton Trackt aktive Streams + CancellationTokenSource pro Session für Stop-Button
KeyScannerService Singleton GitHub Code-Search nach geleakten API-Keys (13 Sprachen, 24 Pfad-Extensions), Background-Scan
AnthropicKeyChecker Static Anthropic Key-Validierung via API-Request, Usage-Header-Auswertung (Plan, 7d/5h Usage)

Endpoints (API)

Alle Endpoints folgen dem Minimal API-Pattern mit Extension Methods (MapXxxEndpoints).

Gruppe Basis-Route Methoden
Auth /api/auth/ POST login, POST logout, GET me, GET autologin
Chat /api/chat POST (SSE Streaming), POST stop
History /api/history GET history, GET poll, POST archive, GET archives, GET archive/{id}, GET attachments/{id}, PUT messages/{id}/mark, PUT messages/{id}/delete, GET chains/{id}
Sessions /api/sessions/ CRUD + GET system-prompt, GET system-prompt-blocks, GET streaming, POST exec, GET git-status (Liste inkl. inline Git-Status + Thumbnail)
Agents /api/agents/ CRUD (Liste inkl. inline Skills + Thumbnail)
Admin /api/admin/ GET users, POST users, PUT users/{id}, PUT users/{id}/password, DELETE users/{id}, POST users/{id}/impersonate, POST users/{id}/login-link (Admin-only)
Workspace /api/workspace/ GET tree, GET/PUT file, GET browse, POST mkdir, DELETE dir, POST browse/mkdir, GET agent/tree, GET/PUT agent/file, POST agent/mkdir, GET raw
Telegram /api/telegram/ Bot-CRUD (/bots, /bots/available), POST webhook/{botId} (unauthenticated), Session-Config, Webhook-Management
OpenClaw /api/openclaw/ GET sessions (Liste importierbarer Sessions), POST import (Import in bestehende Session)
Cronjobs /api/cronjobs/ CRUD + POST toggle, POST run
Krea /api/images/ POST generate, GET list, GET file/{name}, GET file/{name}/thumb, GET status
Skills /api/skills GET list, GET/PUT agent skills, Output-Files + Thumbnails
Profile /api/profile GET, PUT, PUT password
Settings /api/settings GET, PUT
Backup /api/backup POST (Admin only, tar.gz Download)
Shared /api/shared/, /api/messages/{id}/share Share erstellen, öffentlich abrufen, auflisten, löschen
Models /api/models/ GET nvidia, GET pollinations, GET gemini, POST refresh
API Keys /api/admin/api-keys/ CRUD + PUT activate/deactivate, POST check, POST scan, GET scan/status, GET scanned, POST scanned/{id}/adopt, POST scanned/{id}/recheck, DELETE scanned/{id} (Admin-only)
Remote /api/remote WebSocket-Endpoint für Remote-Clients, GET connections, POST assign/unassign, GET /remote.ps1
Info /api/info GET (Build-Zeitstempel + Embedding-Verfügbarkeit)
ServerSettings /api/admin/server-settings GET, PUT (Admin-only, liest/schreibt appsettings.Production.json)

Middleware

AuthMiddleware prüft jede /api/-Anfrage auf ein gültiges gott_token-Cookie.

Ausnahmen (kein Auth nötig):

  • Statische Dateien (nicht /api/)
  • POST /api/auth/login
  • GET /api/auth/autologin (Token-basierter Autologin via Link)
  • POST /api/telegram/webhook/{botId} (authentifiziert via Secret-Header)
  • GET /api/shared/{token} (öffentlicher Zugriff auf geteilte Nachrichten)
  • /api/remote (WebSocket-Endpoint für Remote-Clients)
  • GET /api/images/file/* (Krea-Bilder und Thumbnails, öffentlich)

API-Key Auth (ohne User-Kontext):

  • /api/images/*-Routen akzeptieren einen X-Api-Key-Header. Wenn der Key mit KreaApiKey aus der Config übereinstimmt, wird der Request ohne User-Authentifizierung durchgelassen. Normaler Cookie-Auth funktioniert weiterhin als Fallback.

Bei Erfolg werden UserId und IsAdmin in HttpContext.Items gesetzt (bei API-Key-Auth sind diese nicht gesetzt).

Models

Die Models in Models/ sind reine Daten-Records ohne Business-Logic (Ausnahme: ChatMessage hat Helper-Methoden für Content-Extraktion und UserRecord hat GetEffectivePersona()).

ChatContext ist ein Runtime-Objekt das den vollständigen Kontext eines Chat-Requests hält:

  • Chain-ID, Session-ID, Model-ID
  • Aufgelöster System-Prompt (Text + strukturierte Blöcke)
  • Workspace-Pfad, Tool-Choice (automatisch bestimmt)
  • Prompt-Blöcke (PromptBlocks) – für Reminder-Generierung in der History
  • Referenzen auf Agent und Session Records

Templates

Templates/ enthält Vorlagen die beim Erstellen eines neuen Agents in dessen Memory-Verzeichnis kopiert werden:

  • IDENTITY.md – Name und Grundinfos (Platzhalter {NAME} wird ersetzt)
  • SOUL.md – Persönlichkeit und Verhaltensgrundsätze
  • USER.md – Informationen über den User (global, nicht agent-spezifisch)

Frontend-Architektur

Das Frontend ist eine Single-Page Application ohne Build-Step, komplett in Vanilla JavaScript.

Routing

router.js implementiert ein Hash-basiertes Client-Side-Routing:

Route Page Beschreibung
#/ dashboard.js Session-Übersicht
#/chat/{sessionId} chat-page.js Chat-Ansicht
#/session/{sessionId} session-page.js Session-Einstellungen
#/agent/{agentId} agent-page.js Agent-Editor
#/telegram-bot/{botId} telegram-bot-page.js Telegram-Bot-Editor
#/cronjobs cronjob-page.js Cronjob-Verwaltung
#/profile profile-page.js Profil
#/settings settings-page.js App-Einstellungen
#/admin admin-page.js Benutzerverwaltung (Admin-only)
#/server-settings server-settings-page.js Servereinstellungen (Admin-only)
#/login login-page.js Login
#/shared/{token} shared-page.js Öffentliche geteilte Nachricht (kein Auth)

Kern-Module

  • app.js – Initialisierung, Auth-Check, globale Event-Handler
  • api.js – Zentraler API-Client mit fetch()-Wrapper, Auth-Redirect bei 401
  • ui-helpers.js – DOM-Helpers ($, esc, truncate), Toast-System, ScrollDown, Meta-Bar, Button-Builder
  • markdown.js – Markdown-Rendering (renderMarkdown), LaTeX/Code-Schutz, Krea-Gallery-Wrapping
  • cards.js – Card-Builder (buildAgentCard(), buildSessionCard(), buildTelegramBotCard())
  • msg-actions.js – Nachrichten-Aktionen (Delete, Mark, Share, Reply-Button, Timestamp)
  • tool-ui.js – Tool-Boxes (Diffs, Todos, File-Content), Visibility-Logik
  • modals.js – Modale Dialoge (System-Prompt, Command-Output, Krea-Image)
  • stream-ui.js – Stream-Bubble, Review-Streaming-Rendering
  • bubbles.js – Message Bubbles (User, Assistant, Error, Warning, Choice, Review, Attachments)
  • chat.js – SSE-Stream-Handling, sendMessage, Plan-Mode
  • history.js – Chat-History laden, paginieren, rendern, Polling
  • archive.js – Archiv-Loading und -Rendering
  • reply.js – Reply/Quote-Handling (Set, Clear, Format)
  • files.js – File-Upload, Workspace-Refs
  • session.js – Session-State-Management
  • file-explorer.js – Workspace File-Explorer Panel (Dateien, Ordner erstellen/löschen, Folder-Browser)
  • avatar-editor.js – Wiederverwendbares Avatar-Editor-Modal (Upload, Paste, AI-Generate, Scale)
  • commands-ui.js – Custom-Commands UI-Komponente

Wiederverwendbare Card-Builder (cards.js)

  • buildAgentCard(agent) – Erzeugt ein .card DOM-Element für einen Agent (Avatar, Name, Model-Badge, Feature-Badges: autoCommit, useSoul, useIdentity, useUserInfo, useMemory, webSearch, Skills, Public/Fremd). Skills werden inline vom API-Endpunkt mitgeliefert. Wird im Dashboard und im Agent-Picker-Modal (Session-Formular) verwendet.
  • buildSessionCard(session, agent) – Erzeugt ein .card DOM-Element für eine Session (Avatar, Name, Badges: Agent, Kontext, Telegram, Meta: Nachrichten/Archiv/Workspace, Git-Status). Git-Status wird inline vom API-Endpunkt mitgeliefert. Wird im Dashboard und im Session-Picker-Modal (Cronjob-Formular) verwendet.
  • buildTelegramBotCard(bot) – Erzeugt ein .card DOM-Element für einen Telegram Bot (Name, maskierter Token, Session-Count, Public/Fremd-Badges). Wird im Dashboard und im Bot-Picker-Modal (Session-Formular) verwendet.
  • Picker-Modals – Agent- und Session-Auswahl in Formularen (Session-/Cronjob-Seiten) erfolgt über modale Dialoge mit den Card-Buildern statt über Dropdowns.
  • emoji.js – Emoji-Picker mit Kategorien und Suche
  • tooltip.js – Tooltip-System für Hover-Infos
  • title.js – Dynamisches Tab-Titel-Management

Styling

CSS ist in modulare Dateien aufgeteilt mit CSS Custom Properties für Theming:

  • theme.css – Alle Farben, Abstände, Schriften als CSS Variables
  • base.css – Reset und Grundlayout
  • main.css – Sidebar, Content-Area, Responsive Layout
  • chat.css – Chat-Bubbles, Streaming-Animation, Tool-Outputs
  • markdown.css – Rendering von Markdown in Nachrichten
  • mobile.css – Responsive Breakpoints und Anpassungen

Multi-Provider-System (OpenAI-kompatibel)

Neben Anthropic Claude unterstützt Gott drei OpenAI-kompatible Provider. Der Agent-Model-String bestimmt den Provider:

Prefix Provider Base-URL API-Key
(kein) Anthropic Claude api.anthropic.com AnthropicToken
nvidia: Nvidia (g4f.space Proxy) g4f.space/api/nvidia/v1 keiner
pollinations: Pollinations text.pollinations.ai/openai keiner
gemini: Google Gemini generativelanguage.googleapis.com/v1beta/openai GeminiApiKey

Model-String-Format

provider:model-id – z.B. nvidia:deepseek-ai/deepseek-r1, gemini:gemini-2.5-flash, pollinations:openai-fast

Modell-Caching

Beim Server-Start werden verfügbare Modelle von den Provider-APIs geladen und in data/models_cache.json gecacht. Bei nachfolgenden Starts wird der Cache verwendet (kein API-Call). Manueller Refresh via POST /api/models/refresh.

OpenAiService

OpenAiService implementiert:

  • Streaming via SSE (OpenAI-Format: choices[0].delta)
  • Tool-Calling (identische Tools wie AnthropicService)
  • Agentic Loop (Tool-Results → nächste Iteration)
  • Gemini thought_signature – wird aus extra_content.google.thought_signature gelesen, in DB persistiert (MessageRecord.ThoughtSignature), und beim History-Rebuild in extra_content.google.thought_signature zurückgesendet

Routing

ChatService.ResolveModelId() prüft den Model-String:

  • Enthält : mit bekanntem Provider-Prefix → OpenAiService.StreamChat()
  • Sonst → AnthropicService.StreamChat()

Chat-Pipeline

Der Chat-Flow von User-Input bis zur gerenderten Antwort:

1. User tippt Nachricht + optionale Attachments (Bilder/Dokumente)
   ↓
2. Frontend: POST /api/chat { content, sessionId }
   ↓
3. ChatEndpoint:
   a) User-Message + Attachments in DB speichern
   b) ChatService.PrepareContext() → Agent, Model, System-Prompt, Chain
   c) ChatService.BuildHistoryFromDb() → vollständige Message-History
   d) Model-Routing: Anthropic → AnthropicService.StreamChat(), OpenAI-Provider (nvidia:/pollinations:/gemini:) → OpenAiService.StreamChat()
   ↓
4. Agentic Loop (AnthropicService oder OpenAiService):
   ┌─────────────────────────────────────────┐
   │  while (iterations < maxIterations)      │
   │    → Claude API Request (SSE)            │
   │    → Stream-Processing:                  │
   │      • Text-Tokens → SSE an Frontend     │
   │      • Tool-Use → ToolService.Execute()  │
   │      • Tool-Results → nächste Iteration  │
   │    → Messages in DB persistieren         │
   │    → Stop wenn: end_turn / max_iterations│
   │    → CancellationToken bei Abbruch       │
   └─────────────────────────────────────────┘
   ↓
4b. Review-Phase (optional, wenn ReviewAgent konfiguriert):
   ┌─────────────────────────────────────────┐
   │  Nach end_turn des Worker-Agents:        │
   │    → RunReview() mit Review-Agent        │
   │    → Review-Agent prüft (eigene Tools)   │
   │    → [APPROVED] → Fertig                 │
   │    → Feedback → an Worker als User-Msg   │
   │    → Worker korrigiert → erneuter Review  │
   │    → Max Review-Runden → Fertig          │
   └─────────────────────────────────────────┘
   ↓
4c. Finalizer-Phase (optional, wenn FinalizerAgent konfiguriert):
   ┌─────────────────────────────────────────┐
   │  Nach Review (oder direkt nach Worker):  │
   │    → RunFinalizer() mit Finalizer-Agent  │
   │    → Finalizer arbeitet (eigene Tools)   │
   │    → z.B. git commit, deploy, cleanup    │
   │    → Kein Feedback-Loop (einmalig)       │
   └─────────────────────────────────────────┘
   ↓
5. Frontend: SSE Events empfangen und rendern
   • "text" → Markdown parsen, Token für Token anzeigen
   • "tool_*" → Tool-Aufrufe collapsible darstellen
   • "review_*" → Review-Bubbles mit eigenem Styling
   • "done" → Token-Stats, Dauer, Model anzeigen

Abbruch (Stop-Button)

Der Stop-Mechanismus arbeitet auf zwei Ebenen:

1. Expliziter Stop-Endpoint (POST /api/chat/stop):

  • Frontend ruft apiStopChat(sessionId) auf
  • StreamingTracker hält pro Session einen CancellationTokenSource
  • StreamingTracker.Cancel(sessionId) cancelt den Token sofort
  • Der Chat-Handler verknüpft den Stop-Token mit dem Request-Token via CreateLinkedTokenSource

2. CancellationToken-Propagierung:

  1. Frontend: AbortController.abort() → SSE-Fetch abgebrochen + POST /api/chat/stop
  2. StreamingTracker.Cancel() → CancellationTokenSource wird gecancelled
  3. AnthropicService: ThrowIfCancellationRequested() am Loop-Anfang, vor/nach Tool-Execution
  4. ToolService.ExecuteTool(): CancellationToken wird durchgereicht → bei execute wird der Prozess gekillt
  5. WriteSseEvent(): Alle SSE-Writes mit CancellationToken → sofortiger Abbruch
  6. Chain wird mit StopReason = "client_disconnected" finalisiert

Warum zwei Ebenen? Kestrel erkennt einen Client-Disconnect erst beim nächsten Write auf den Response-Stream. Wenn das Backend in einer langen Tool-Ausführung steckt, wird nichts geschrieben – der explizite Stop-Endpoint garantiert sofortigen Abbruch.

Streaming vs Non-Streaming

  • Web-Chat: Streaming via SSE (text/event-stream). Tokens werden in Echtzeit gerendert.
  • Telegram: Non-Streaming via ChatNonStreaming(). Vollständige Antwort wird abgewartet und als Telegram-Nachricht gesendet.
  • Cronjobs: Non-Streaming, wie Telegram.

History-Optimierung

Die History-Rekonstruktion in BuildHistoryFromDb() ist optimiert:

  • Max 120 Messages: Die History wird auf maximal 120 Messages begrenzt (älteste entfernt)
  • Ältere Chains: Nur text-Messages (user + assistant), keine Tool-Calls
  • Letzte Chain: Vollständig mit allen Tool-Use/Tool-Result Blöcken
  • Attachments: Nur für die letzte User-Message geladen (spart enorme Token)
  • Tool-Results: In der History auf 20.000 Zeichen gekürzt (vollständig in DB)
  • System-Prompt-Reminder: Alle ~30 Messages wird ein automatisch generierter Reminder als User/Assistant-Paar injiziert (z.B. [System Reminder] Beachte weiterhin den System-Prompt (Identity, Workspace, Kontext, Memory, ...)). Bekämpft das "Lost-in-the-Middle"-Problem bei langen Konversationen. Der Reminder-Text wird aus den aktiven Prompt-Block-Labels generiert (SystemPromptBuilder.BuildReminder()). Nur aktiv wenn ≥2 Blöcke vorhanden.

Tool-System

Der Agent hat Zugriff auf folgende Tools, abhängig von Konfiguration:

Datei-Tools (wenn Workspace konfiguriert)

Tool Beschreibung
read_file Datei lesen (relativer Pfad zum Workspace)
write_file Datei erstellen/überschreiben
edit_file Exakten Textabschnitt in Datei ersetzen
list_files Verzeichnis-Listing
delete_file Datei oder leeres Verzeichnis löschen
execute Shell-Befehl ausführen (bash, konfigurierbares Timeout)
background_execute Shell-Befehl als Hintergrund-Prozess starten (gibt PID zurück, wartet nicht auf Ende)
glob Dateien via Glob-Pattern finden
grep Dateien nach Regex/Text durchsuchen
todo_write Todo-Liste schreiben (als Datei im Workspace)

Memory-Tools (wenn UseMemory aktiviert)

Tool Beschreibung
memory_read Memory-Datei des Agents lesen
memory_write Memory-Datei schreiben (überschreiben/append)
memory_list Alle Memory-Dateien des Agents auflisten
memory_search Semantische Suche über vergangene Chat-Nachrichten und Memory-Dateien (benötigt Embedding-Modell)

Remote-Execution (wenn Remote-Verbindung zugeordnet)

Tool Beschreibung
remote_execute Shell-Befehl auf einem verbundenen Remote-Client ausführen (via WebSocket)

Cross-Session Messaging (wenn konfiguriert)

Tool Beschreibung
send_to_session Nachricht an eine andere Session senden und dort eine Agent-Antwort auslösen

Interaktive Rückfragen (wenn AllowUserChoice aktiviert)

Tool Beschreibung
ask_user_choice Stellt dem User eine Frage mit 2-5 Auswahlmöglichkeiten

Dieses Tool wird nicht ausgeführt, sondern als SSE-Event an den Client weitergeleitet. Siehe Interaktive Rückfragen.

Web-Suche (wenn WebSearchVersion konfiguriert)

Nutzt Anthropics eingebaute Web-Suche als Server-Side-Tool.

Plan-Modus: Read-only Tools

Im Plan-Modus werden nur folgende Tools bereitgestellt: read_file, list_files, glob, grep, execute, todo_write, memory_*, memory_search, remote_execute, ask_user_choice. Write-Tools (write_file, edit_file, delete_file) werden gefiltert.

Tool-Choice (automatisch)

Die Tool-Choice-Strategie wird automatisch bestimmt (nicht konfigurierbar pro Agent):

  • any: Automatisch wenn Workspace, Skills oder Memory vorhanden. Erste Iteration erzwingt Tool-Nutzung, danach auto. Verhindert dass der Agent nur Text antwortet wenn Tools benötigt werden.
  • auto: Wenn keine Tools verfügbar. Claude entscheidet frei.
  • none: Im /no-tools-Modus.

Pfad-Sicherheit

Alle Dateipfade werden via ResolvePath() aufgelöst und gegen den Workspace/Memory-Ordner geprüft – Path-Traversal-Angriffe werden verhindert.


Agent-System

Ein Agent definiert die Persönlichkeit und Fähigkeiten der AI:

Eigenschaft Beschreibung
Name Anzeigename
Avatar Base64 Data-URL (WebP, 512px) + AvatarSmall (WebP, 256px Thumbnail)
Model sonnet, sonnet-4-5, sonnet-4-6, opus, opus-4-5, opus-4-6, haiku, haiku-4-5
CustomCommands JSON-Array mit Slash-Commands (Label + Prompt)
AutoCommit "" (nichts), "mention" (anmerken – nur auf User-Request), "enforce" (erzwingen – nach jeder Änderung), "forbid" (strikt verboten)
UseSoul SOUL.md in System-Prompt einbinden
UseIdentity IDENTITY.md in System-Prompt einbinden
UseUserInfo User-Persona in System-Prompt einbinden
UseMemory Memory-Tools aktivieren
WebSearchVersion Web-Suche aktivieren (z.B. web_search_20260209)
AllowUserChoice ask_user_choice-Tool verfügbar (Default: true)
TaskInstruction Aufgabe/Anweisung – optionaler Text, wird als ## Anweisungen-Block in System-Prompt eingefügt
IsPublic Andere User können den Agent in ihren Sessions verwenden (aber nicht bearbeiten)

Model-Auflösung

"sonnet"     → claude-sonnet-4-6
"sonnet-4-5" → claude-sonnet-4-5
"sonnet-4-6" → claude-sonnet-4-6
"opus"       → claude-opus-4-6
"opus-4-5"   → claude-opus-4-5
"opus-4-6"   → claude-opus-4-6
"haiku"      → claude-haiku-4-5
"haiku-4-5"  → claude-haiku-4-5
(default)    → claude-sonnet-4-6

System-Prompt-Aufbau

Der SystemPromptBuilder erzeugt den System-Prompt modular aus konfigurierbaren Blöcken:

┌──────────────────────────────────────────┐
│ 1. IDENTITY.md (UseIdentity)             │  → Wer ist der Agent?
│ 2. SOUL.md (UseSoul)                     │  → Persönlichkeit, Verhalten
│ 3. Anweisungen (TaskInstruction)         │  → Aufgaben-/Anweisungstext (optional)
│ 4. User-Persona (UseUserInfo)            │  → Infos über den User
│ 5. Workspace-Info                        │  → Tools + Workspace-Pfad
│ 6. Rückfragen (AllowUserChoice)          │  → Hinweis zu ask_user_choice Tool
│ 7. Session-Kontext                       │  → Freiformtext
│ 8. Skills (Agent-Skills)                 │  → Skill-Prompts
│ 9. Memory (UseMemory)                    │  → Memory-Regeln + MEMORY.md Inhalt
│10. Git-Verhalten (AutoCommit)            │  → Commit-Regeln
│11. Markierte Nachrichten                 │  → Vom User als wichtig markierte Messages
│    [Plan-Modus-Block]                    │  → Nur wenn planMode=true (überspringt 10)
│    [Preparer-Instruktionsblock]          │  → Nur für Preparer-Agents
└──────────────────────────────────────────┘

Jeder Block hat:

  • Icon – Font Awesome Icon-Klasse
  • Label – Beschreibender Titel
  • Content – Markdown-Text

Die Blöcke sind über die API als JSON abrufbar (GET /api/sessions/{id}/system-prompt-blocks), sodass das Frontend sie einzeln inspizierbar darstellen kann.


Memory-System

Jeder Agent hat ein eigenes Dateisystem-basiertes Gedächtnis:

data/agents/{agentId}/
├── IDENTITY.md      # Identität (aus Template initialisiert)
├── SOUL.md          # Persönlichkeit (aus Template initialisiert)
├── MEMORY.md        # Haupt-Memory (kuratierte Informationen)
└── memory/          # Unterordner für Tages-Logs, Themen
    ├── YYYY-MM-DD.md
    └── ...

Funktionsweise

  1. Initialisierung: Beim Erstellen eines Agents werden IDENTITY.md und SOUL.md aus Templates/ kopiert
  2. Lesen: Der Agent kann seine Memory-Dateien via memory_read Tool lesen
  3. Schreiben: Via memory_write (überschreiben oder append)
  4. Auflisten: Via memory_list alle Dateien durchsuchen
  5. System-Prompt: MEMORY.md Inhalt wird automatisch in den System-Prompt eingebettet
  6. IDENTITY.md und SOUL.md: Werden als eigene System-Prompt-Blöcke eingebunden (wenn aktiviert)

Sandbox

Alle Pfade werden gegen das Agent-Verzeichnis geprüft – kein Zugriff außerhalb möglich.


Skill-System

Skills sind Dateisystem-basierte Erweiterungen die einem Agent zugeordnet werden können:

data/skills/{slug}/
├── SKILL.md          # Metadaten (Name, Description, Version im Frontmatter)
├── PROMPT.md         # System-Prompt-Erweiterung (in Agent-Prompt eingebettet)
├── _meta.json        # Alternative Metadaten (Fallback)
└── output/           # Skill-Output (Bilder, Dateien, etc.)

SKILL.md Frontmatter

---
name: Mein Skill
description: Beschreibung
version: 1.0
---

Agent-Zuordnung

Skills werden über die agent_skills Tabelle einem Agent zugeordnet. Der PROMPT.md-Inhalt aller zugeordneten Skills wird als ein System-Prompt-Block eingefügt.

Workspace-Implikation

Wenn ein Agent Skills hat aber kein Workspace konfiguriert ist, wird automatisch /tmp als Workspace gesetzt (damit execute für Skill-Commands funktioniert).


Telegram-Integration

Telegram Bots sind eigenständige Entitäten mit einer eigenen Tabelle (telegram_bots), die am Dashboard verwaltet werden (wie Agents, Sessions, Cronjobs). Ein Bot kann mehreren Sessions zugewiesen werden – jede Session hat ihren eigenen Chat-Kontext.

Datenmodell

Telegram Bot (telegram_bots):

  • BotId – UUID
  • UserId – Owner
  • Name – Anzeigename
  • BotToken – Bot-Token von @BotFather
  • WebhookSecret – Einmalig generierter Token für Webhook-Verifizierung
  • IsPublic – Andere User können den Bot in ihren Sessions verwenden (aber nicht bearbeiten)

Session-Felder:

  • TelegramBotId – Verweis auf den zugewiesenen Bot (wie AgentId)
  • TelegramChatId – Verknüpfte Chat-ID (1 Session = max. 1 Telegram-Chat)

Webhook-Flow

1. User erstellt Telegram Bot im Dashboard (Name + Token)
2. User registriert Webhook auf der Bot-Page
   → Setzt Webhook-URL: {baseUrl}/api/telegram/webhook/{botId}
3. User weist Bot einer Session zu (Session-Settings, Bot-Picker)
4. Telegram sendet Updates an Webhook
5. AuthMiddleware lässt Webhook-Requests durch (kein Cookie nötig)
6. TelegramEndpoint prüft X-Telegram-Bot-Api-Secret-Token Header
7. TelegramService verarbeitet Update:
   - Bot laden via botId
   - Chat-ID extrahieren
   - Session suchen: telegram_bot_id = botId AND telegram_chat_id = chatId
   - /start → Auto-Link (wenn genau 1 unverknüpfte Session) oder Chat-ID anzeigen
   - /clear → History archivieren
   - /status → Session-Info anzeigen
   - Text → An Claude weiterleiten (Non-Streaming)

Bei /start oder einer normalen Nachricht, wenn keine Session für den Chat verknüpft ist:

  1. Suche Sessions mit diesem Bot, die noch keine Chat-ID haben
  2. Genau 1 gefunden → Automatisch verknüpfen + Bestätigungsnachricht
  3. 0 oder mehrere gefunden → "Deine Chat-ID ist X, bitte im Web-UI zuweisen"

Unlink ist nur über das Web-UI möglich (kein Telegram-Befehl).

Non-Streaming Chat

Telegram-Nachrichten werden über AnthropicService.ChatNonStreaming() verarbeitet. Die History wird genauso aus der DB aufgebaut wie beim Web-Chat. Antworten über 4096 Zeichen werden automatisch in Chunks aufgeteilt.

Dashboard & Frontend

  • Dashboard: Telegram-Bots-Section mit Cards (Name, maskierter Token, Session-Count)
  • Bot-Page (#/telegram-bot/{botId}): Name, Token, Webhook-Secret (readonly), Webhook-Verwaltung (registrieren/status/entfernen), Public-Checkbox, Löschen
  • Session-Page: Bot-Picker (wie Agent-Picker), readonly Chat-ID mit Unlink-Button

Cronjob-System

Der CronjobService ist ein BackgroundService der minütlich nach fälligen Jobs prüft.

Datenmodell

Feld Beschreibung
CronExpression Standard-Cron-Format (5 Felder), via Cronos
SessionId Session in der der Job läuft
Prompt Text der als User-Message an Claude gesendet wird
NotifySessionId Optionale Session für Benachrichtigung
IsEnabled Aktiviert/Deaktiviert
NextRunAt Nächste geplante Ausführung (UTC)

Ausführungsflow

1. CronjobService prüft jede Minute
2. Fällige Jobs (next_run_at <= jetzt) werden geladen
3. Für jeden Job:
   a) ChatService.PrepareContext() – Chain + System-Prompt aufbauen
   b) History aus DB laden
   c) Prompt als User-Message anhängen + in DB speichern
   d) AnthropicService.ChatNonStreaming() ausführen
   e) Telegram-Benachrichtigung senden (auf Arbeits-Session)
   f) Optional: Zusammenfassung in Notify-Session schreiben + Telegram dort
   g) Nächste Ausführung berechnen + DB aktualisieren

Benachrichtigungen

  • Arbeits-Session: Wenn die Session Telegram hat, wird die Antwort dort gepostet
  • Notify-Session: Wenn konfiguriert, wird eine Zusammenfassung in eine andere Session geschrieben und der Agent dort antwortet darauf

Krea-Bildgenerierung

Die KreaService ermöglicht Bildgenerierung über die Krea API.

Unterstützte Modelle

flux, flux-kontext, flux-1.1-pro, flux-1.1-pro-ultra,
nano-banana, nano-banana-pro, imagen-3, imagen-4, imagen-4-fast, imagen-4-ultra,
ideogram-2-turbo, ideogram-3, seedream-3, seedream-4,
chatgpt-image, runway-gen-4

Flow

1. POST /api/images/generate { prompt, model, width, height, ... }
2. KreaService sendet Request an Krea API
3. Job-Polling bis Status "completed"
4. Bilder herunterladen nach data/images/
5. Metadaten als JSON speichern
6. Response mit Dateinamen + URLs

Bild-Serving

  • GET /api/images – Liste aller generierten Bilder (aus Metadaten-JSON)
  • GET /api/images/file/{filename} – Einzelnes Bild ausliefern (ohne Auth)
  • GET /api/images/file/{filename}/thumb – Thumbnail (320px WebP, gecacht in data/cache/images/, ohne Auth)
  • GET /api/images/status – Generierungsstatus abfragen

Bild-Dateien und Thumbnails sind ohne Authentifizierung abrufbar (für externe Einbindung).


Auth & Multi-User

Authentifizierung

  • Login: Username + Passwort → SHA256 Hash-Vergleich → Token generieren
  • Token: 32 Bytes Random, als gott_token HttpOnly Cookie (365 Tage)
  • Validierung: Jeder API-Call prüft Token → User-ID
  • Logout: Token aus DB löschen + Cookie entfernen

Multi-User-Isolation

  • Sessions sind an user_id gebunden
  • Agents sind an user_id gebunden
  • Cronjobs sind an user_id gebunden
  • Jeder User sieht nur seine eigenen Daten
  • Admin-Flag (is_admin) für Backup-Endpoint, Admin-Benutzerverwaltung, Impersonate

Default-Path (Base-Path)

Jeder User hat einen optionalen DefaultPath – den Basis-Ordner für alle Workspaces. Wird nur vom Admin gesetzt.

  • Session-Workspace: Speichert nur den relativen Pfad zum DefaultPath (z.B. myapp statt /home/user/projects/myapp)
  • Auflösung: WorkspaceHelper.ResolveWorkspace() kombiniert DefaultPath + relativen Workspace → absoluter Pfad
  • System-Prompt: Bekommt den aufgelösten absoluten Pfad, damit der Agent korrekt navigieren kann
  • Path-Traversal-Schutz: .. in relativen Workspace-Pfaden wird blockiert (400 Bad Request)
  • Legacy-Support: Absolute Pfade in session.Workspace funktionieren weiterhin als Fallback
  • Folder-Browser: Startet beim DefaultPath, User kann nicht über den Base-Path hinaus navigieren

Default-User

Beim ersten Start wird automatisch ein Default-User erstellt (DatabaseService.EnsureDefaultUser()).

User-Persona

Jeder User hat eine optionale Persona – ein Freitext der beschreibt wer er ist. Diese wird (wenn UseUserInfo am Agent aktiv ist) in den System-Prompt als "Dein Gegenüber" eingebettet.


Admin-Benutzerverwaltung

Admins können alle User verwalten über AdminEndpoint.cs (alle Endpoints erfordern is_admin).

API-Endpunkte

Methode Route Beschreibung
GET /api/admin/users Alle User auflisten
POST /api/admin/users Neuen User erstellen
PUT /api/admin/users/{id} User bearbeiten (Name, Username, Admin, DefaultPath)
PUT /api/admin/users/{id}/password Passwort zurücksetzen
DELETE /api/admin/users/{id} User löschen (+ Tokens, Shared Messages)
POST /api/admin/users/{id}/impersonate Als anderer User einloggen (Login-as-User)
POST /api/admin/users/{id}/login-link Autologin-Token generieren → URL zurückgeben

Impersonate (Login-as-User)

Admins können sich als beliebiger User einloggen ohne dessen Passwort zu kennen:

  1. POST /api/admin/users/{id}/impersonate → Erstellt Token für Zieluser
  2. Setzt neuen gott_token-Cookie → Admin-Session wird zum Zieluser
  3. location.reload() → Frontend lädt mit neuem User-Kontext

Admins können für jeden User einen Autologin-Link generieren – z.B. für Setup oder Support:

  1. POST /api/admin/users/{id}/login-link → Erstellt Token, gibt { token } zurück
  2. Frontend baut URL: {window.location.origin}/api/auth/autologin?token={token}
  3. Link wird im Modal angezeigt mit Copy-Button
  4. GET /api/auth/autologin?token={token} → Setzt Cookie + Redirect zu / (ohne Auth, wie Login)

Frontend (admin-page.js)

  • Erreichbar über Dashboard-Link "Benutzerverwaltung" (nur für Admins sichtbar)
  • User-Liste als Cards mit Edit/Delete/Login-Link-Buttons
  • Inline-Formular für Create/Edit
  • Login-Link-Modal mit Copy-Funktion
  • Sich selbst löschen ist nicht möglich

Multi-Agent System (Preparer + Review + Finalizer)

Das Multi-Agent-System ermöglicht bis zu vier Agents pro Session: einen Worker, einen optionalen Vorbereiter (Preparer), einen optionalen Reviewer und einen optionalen Finalizer.

Architektur

User-Message
  → Preparer-Phase (optional):
      → Preparer-Agent bekommt: User-Message + History (inkl. eigener vorheriger Messages)
      → Preparer arbeitet (kann Tools nutzen: read_file, execute etc.)
      → Erledigt Vorarbeit mit seinen Fähigkeiten (z.B. JSON bauen, Daten aufbereiten)
      → [QUESTION] → Rückfrage an User, Flow stoppt, User muss erneut eingeben
      → Antwort ohne [QUESTION] → automatisch weiterleiten an Worker
  → Worker-Agent arbeitet (Tools, Iterationen) → end_turn
  → Review-Phase (optional):
      → Review-Agent bekommt: Konversation als Kontext
      → Review-Agent prüft (kann Tools nutzen: read_file, execute etc.)
      → [APPROVED] → Fertig, Antwort an User
      → Feedback-Text → wird als User-Message an Worker-Agent eingefügt
      → Worker-Agent korrigiert → end_turn → Review-Agent prüft erneut
      → Max Review-Runden erreicht → Fertig (mit letzter Worker-Antwort)
  → Finalizer-Phase (optional):
      → Finalizer-Agent bekommt: gesamte Konversation
      → Finalizer arbeitet (eigene Tools, z.B. git commit, deploy)
      → Kein Feedback-Loop – einmalige Ausführung
      → Fertig

Konfiguration

Auf Session-Ebene (nicht Agent-Ebene):

DB-Feld SessionRecord Beschreibung
preparer_agent_id PreparerAgentId ID des Vorbereiter-Agents (optional, null = kein Preparer)
review_agent_id ReviewAgentId ID des Review-Agents (optional, null = kein Review)
max_review_iterations MaxReviewIterations Max. Review-Runden (Default: 3)
finalizer_agent_id FinalizerAgentId ID des Finalizer-Agents (optional, null = kein Finalizer)

Vorbereiter-Agent (Preparer)

Der Preparer wird vor dem Worker-Agent aufgerufen. Er analysiert die User-Anfrage, kann Vorarbeit leisten (z.B. Daten aufbereiten, JSON bauen, Code analysieren) und gibt das Ergebnis an den Worker weiter. Bei unklaren Anfragen stellt er Rückfragen.

Logik-Pattern: Default = Forward

Die Logik ist invertiert gegenüber dem Review-Pattern: Jede Antwort wird automatisch weitergeleitet, außer sie enthält explizit [QUESTION]. Das ist robuster als ein Pflicht-Tag wie [FORWARD], weil LLMs dazu neigen, Tags zu vergessen.

Antwort Ergebnis
Ohne [QUESTION] Automatisch weitergeleitet (ShouldForward = true)
Mit [QUESTION] Rückfrage an User, Flow stoppt (ShouldForward = false)

Backend-Flow (Preparer)

  1. ChatEndpoint – Prüft ob ctx.Preparer vorhanden
  2. AnthropicService.RunPreparer() – Ruft RunAgentChat() auf mit agentType = "preparer"
  3. Entscheidung – ShouldForward prüft ob [QUESTION] im Text:
    • Forward: Aufbereiteter Text wird als [Vorbereitet von AgentName]:-User-Message in DB gespeichert, History wird neu geladen, StreamChat startet
    • Rückfrage: SSE preparer_done mit forwarded: false, Stream endet mit stopReason: "preparer_query", User muss erneut eingeben

Preparer-History

Der Preparer bekommt seine eigene History (BuildHistoryFromDb(sessionId, includeTag: "preparer")), damit er seine vorherigen Rückfragen und User-Antworten sieht. Der Session-Agent bekommt die History ohne Preparer-Messages (Tag-Filter).

System-Prompt

Der Preparer bekommt einen speziellen Instruktionsblock an seinen System-Prompt angehängt:

  • Erklärt die Rolle als Vorbereiter
  • Definiert [QUESTION]-Mechanismus für Rückfragen
  • Instruiert aktive Vorarbeit mit eigenen Fähigkeiten und Tools
  • Betont: Antworten werden automatisch weitergeleitet

SSE-Events (Preparer)

Event Daten Beschreibung
preparer_start { agent: "Name" } Preparer-Phase beginnt
preparer_text { text: "..." } Preparer-Agent-Text (Token-Stream)
preparer_tool_use { tool: "name", input: "..." } Preparer nutzt Tool
preparer_done { forwarded: true/false } Preparer-Phase beendet

Backend-Flow (Review)

  1. ChatService.PrepareContext() – Wenn session.ReviewAgentId gesetzt:

    • Review-Agent aus DB laden
    • Eigenen SystemPrompt für den Review-Agent bauen (Identity, Soul, Memory, Skills)
    • Eigene Tool-Definitionen für den Review-Agent
    • ReviewContext mit Model, SystemPrompt, Tools, Agent-Referenz erstellen
  2. ChatEndpoint – Übergibt ctx.Review an AnthropicService.StreamChat()

  3. AnthropicService.StreamChat() – Nach end_turn des Worker-Agents:

    • Prüft ob ReviewContext vorhanden und reviewRound < MaxReviewIterations
    • Ruft RunReview() auf
  4. RunReview() – Orchestriert eine einzelne Review-Runde:

    • Baut Review-Messages auf: Konversation als Context + Prüfanweisung
    • SSE-Event review_start an Client senden
    • Ruft RunAgentChat() auf (generische Methode für Review/Finalizer, eigener API-Call an Claude)
    • Review-Agent kann Tools nutzen (eigener Tool-Loop mit max. 25 Iterationen)
    • SSE-Events review_text und review_tool_use für Live-Streaming
    • Prüft ob Antwort [APPROVED] enthält:
      • Ja → SSE review_approved, return HasFeedback = false
      • Nein → SSE review_feedback, return HasFeedback = true + Feedback-Text
  5. Zurück in StreamChat() – Bei Feedback:

    • Feedback als User-Message in DB speichern (mit [Review-Feedback von AgentName (Runde X/Y)] Prefix)
    • Worker-Agent bekommt Feedback als nächste User-Message
    • continue → nächste while-Loop-Iteration → Worker korrigiert → Review erneut
    • reviewRound++ bis MaxReviewIterations erreicht

ReviewContext / FinalizerContext (Model)

// Identische Struktur für Review und Finalizer
public class ReviewContext
{
    public string Model { get; set; }          // Claude-Modell des Agents
    public string SystemPrompt { get; set; }   // Eigener System-Prompt
    public AgentRecord Agent { get; set; }     // Agent-Record für Name/Avatar
    public List<object> Tools { get; set; }    // Tool-Definitionen
    public int MaxReviewIterations { get; set; } // Max Runden (nur bei Review relevant)
}
// ChatContext hat: ReviewContext Review + ReviewContext Finalizer

SSE-Events

Event Daten Beschreibung
review_start { agent: "Name" } Review-Phase beginnt
review_text { text: "..." } Review-Agent-Text (Token-Stream)
review_tool_use { tool: "name", input: "..." } Review-Agent nutzt Tool
review_feedback { feedback: "..." } Review nicht bestanden, Feedback an Worker
review_approved { message: "..." } Review bestanden

DB-Persistierung

  • Worker-Antworten: Normale Messages (role=assistant, type=text, tag=null)
  • Preparer-Antworten: Messages mit tag="preparer" (aus API-History gefiltert, nur für Frontend-Anzeige)
  • Aufbereiteter Prompt: Als User-Message mit Prefix [Vorbereitet von AgentName]:
  • Review-Feedback: Als User-Messages mit Prefix [Review-Feedback von AgentName (Runde X/Y)]:
  • Review-Agent-Antworten: Messages mit tag="review" (aus API-History gefiltert)
  • Finalizer-Antworten: Messages mit tag="finalizer" (aus API-History gefiltert)

Frontend

Session-Page (session-page.js):

  • Zweiter Agent-Picker: "Review-Agent" (nutzt buildAgentCard() + openAgentPickerModal())
  • Input für "Max. Review-Runden" (Number-Input, Default 3)

Chat-UI (chat.js):

  • SSE-Event-Handler für review_start, review_text, review_tool_use, review_feedback, review_approved
  • Review-Bubbles mit eigenem Styling (sekundäre Farbe, Agent-Name-Header)

History-Rendering (history.js, bubbles.js):

  • renderMarkdown parst [Review: AgentName] → styled Header mit Icon
  • renderMarkdown parst [Review-Feedback von AgentName (...)] → styled Feedback-Header
  • renderMarkdown filtert [APPROVED] aus (wird ausgeblendet)
  • History erkennt Review-Nachrichten und rendert sie als .review-bubble statt normaler Bubbles
  • Review-Nachrichten werden nicht mit normalen Nachrichten gemergt

Shared-Page (shared-page.js):

  • Gleiche Review-Bubble-Erkennung für geteilte Nachrichten

Finalizer-Agent

Der Finalizer wird nach dem Review (oder direkt nach dem Worker, falls kein Review-Agent konfiguriert) aufgerufen. Er führt abschließende Arbeiten durch (z.B. Git-Commit, Deployment, Cleanup) – ohne Feedback-Loop.

Konfiguration

DB-Feld SessionRecord Beschreibung
finalizer_agent_id FinalizerAgentId ID des Finalizer-Agents (optional, null = kein Finalizer)

Backend-Flow

  1. ChatService.PrepareContext() – Wenn session.FinalizerAgentId gesetzt:

    • Finalizer-Agent aus DB laden
    • FinalizerContext aufbauen (analog zu ReviewContext: Model, SystemPrompt, Tools)
  2. AnthropicService.StreamChat() – Nach Review-Phase (oder direkt nach Worker):

    • Prüft ob FinalizerContext vorhanden
    • Ruft RunFinalizer() auf
  3. RunFinalizer() – Baut Messages auf (gesamte Konversation + Finalisierungs-Anweisung), ruft RunAgentChat() auf (generische Methode, auch vom Review genutzt)

  4. RunAgentChat() – Generische Methode für Preparer/Review/Finalizer:

    • Eigener API-Call an Claude mit Agent-Config
    • Tool-Loop mit SSE-Events ({type}_text, {type}_tool_use)
    • Antwort als Message in DB persistieren (mit Tag = agentType, wird aus API-History gefiltert)

SSE-Events

Event Daten Beschreibung
finalizer_start { agent: "Name" } Finalizer-Phase beginnt
finalizer_text { text: "..." } Finalizer-Agent-Text (Token-Stream)
finalizer_tool_use { tool: "name", input: "..." } Finalizer nutzt Tool
finalizer_done {} Finalizer-Phase beendet

Frontend

  • Session-Page: Vierter Agent-Picker: "Vorbereiter-Agent", "Review-Agent", "Finalizer-Agent" im "Weitere Einstellungen"-Bereich
  • Chat-UI: Preparer-Bubbles (.preparer-bubble, Info-Farbe, 🔍-Icon), Finalizer-Bubbles (.finalizer-bubble, grüne Farbe, 🏁-Icon)
  • History: [Preparer: AgentName] → styled Header mit fa-filter Icon, [Vorbereitet von AgentName] → styled Forwarded-Header, [Finalizer: AgentName] → styled Header, [FORWARD]/[QUESTION] werden ausgeblendet
  • Dashboard: 🏁-Badge auf Session-Cards mit Finalizer

Interaktive Rückfragen (ask_user_choice)

Das ask_user_choice-Tool ermöglicht dem Agent, dem User klickbare Auswahlmöglichkeiten zu präsentieren, wenn es mehrere sinnvolle Wege gibt oder eine Entscheidung vom User getroffen werden muss.

Tool-Definition

{
  "name": "ask_user_choice",
  "description": "Stellt dem User eine Frage mit Auswahlmöglichkeiten",
  "input_schema": {
    "properties": {
      "question": { "type": "string" },
      "choices": { "type": "array", "items": { "type": "string" }, "minItems": 2, "maxItems": 5 }
    }
  }
}

Agent-Konfiguration

  • allow_user_choice (AgentRecord) – Boolean, Default true. Steuert ob das Tool verfügbar ist.
  • Dashboard-Badge: 🔵 Rückfragen wenn aktiv
  • System-Prompt-Hinweis: "Nutze ask_user_choice sparsam – nur wenn die Entscheidung vom User getroffen werden soll"
  • Bei Review/Finalizer/Cronjobs: Immer deaktiviert (kein User zum Fragen)

Backend-Flow

  1. Claude ruft ask_user_choice auf → Backend erkennt im ProcessStream
  2. Tool wird nicht ausgeführt – stattdessen SSE-Event user_choice gesendet
  3. stopReason wird auf "awaiting_user_choice" gesetzt (Guard-Clause verhindert Überschreibung durch message_delta)
  4. tool_use-Block wird in DB gespeichert, Chain wird finalisiert
  5. User wählt Option → Frontend sendet POST /api/chat mit choiceToolCallId + choiceResult
  6. Backend findet die Chain mit dem offenen tool_use, speichert tool_result dort
  7. Neuer StreamChat startet – History enthält tool_use + tool_result, Claude arbeitet weiter

Frontend-Flow

  • Live: SSE-Event user_choice → addChoiceBubble() rendert Frage + klickbare Buttons
  • History: tool_use mit toolName === 'ask_user_choice' → Voraus-Suche nach tool_result:
    • Gefunden: addChoiceBubbleStatic() mit ausgewählter Option (hervorgehoben, andere ausgegraut)
    • Nicht gefunden: Aktive Buttons (klickbar, z.B. nach Page-Refresh)
  • Robustheit: Guards gegen choices als String statt Array (Array.isArray() Check)
  • CSS: .choice-bubble, .choice-btn (Primary-Color-Outline), .choice-selected/.choice-unselected

SSE-Events

Event Daten Beschreibung
user_choice { toolCallId, question, choices[] } Rückfrage mit Auswahloptionen

Plan-Modus

Der Plan-Modus ist ein Read-only-Betriebsmodus, in dem der Agent den Code analysieren, Rückfragen stellen und Pläne erstellen kann – aber keine Dateien ändern oder Befehle ausführen darf.

Aktivierung

  • Frontend: Toggle-Button (🗺️ fa-map) im Chat-Input-Bereich
  • API: planMode: true im ChatRequest
  • Pro Chain: plan_mode Feld in der Chain (rein informativ für History-Anzeige)
  • Kein Agent-Setting – wird pro Nachricht vom User gesteuert

Backend-Auswirkungen

Aspekt Normal Plan-Modus
Tools Alle (read_file, write_file, edit_file, delete_file, execute, ...) Nur read-only: read_file, list_files, glob, grep, execute, todo_write, memory_*, ask_user_choice
System-Prompt Normal + Plan-Modus-Block: "Du darfst NUR lesen und analysieren, KEINE Änderungen vornehmen"
toolChoice "any" (automatisch wenn Workspace/Skills/Memory) Immer "auto" (Claude darf frei antworten)
Chain-Speicherung plan_mode = 0 plan_mode = 1

System-Prompt-Anpassungen im Plan-Modus

Folgende Blöcke werden übersprungen: Git-Commits. Der Tools-Block listet nur Read-only-Tools auf. Skills werden als "nur zur Kenntnis, nicht ausführbar" markiert.

Frontend

  • Toggle: #planModeBtn – wechselt _planModeActive, ändert Button-Styling + Placeholder-Text
  • Chain-Meta: Badge 📋 Plan-Modus bei Chains die im Plan-Modus erstellt wurden
  • System-Prompt-Modal: Zeigt den angepassten System-Prompt wenn Plan-Modus aktiv
  • Session-Wechsel: Plan-Modus wird zurückgesetzt

Choice-Response im Plan-Modus

Wenn im Plan-Modus eine ask_user_choice-Rückfrage kommt und der User antwortet, erbt die Choice-Response den planMode des vorherigen Chains.


Anthropic Claude unterstützt Web-Suche als Server-Tool. Das System integriert Web-Search mit Source-Tracking und Rendering.

Backend

  • Streaming: server_tool_use (Suchanfrage) → web_search_tool_result (Ergebnisse mit Sources)
  • Sources extrahieren: Aus web_search_tool_result-Block werden url + title als JSON-Array extrahiert
  • Persistierung: web_search_result-Messages in DB (type=web_search_result, content = JSON-Array der Sources). Leere Ergebnisse (Sources=[]) werden nicht gespeichert.
  • SSE-Events: web_search_start (Suche beginnt) → web_search_end (Suche fertig, mit Sources)

Frontend – Streaming

  • web_search_start → Tool-Box mit Spinner erstellen, Stream-Bubble pausieren (nicht finalisieren)
  • web_search_end → Tool-Box mit Sources finalisieren
  • text_start → in bestehende Bubble weiter schreiben (kein neuer Block)
  • pauseStreamBubble() / endStreamBubble() Konzept: Text-Blöcke zwischen Web-Searches werden in einer Bubble zusammengefasst
  • text_end pausiert nur (Cursor weg), endStreamBubble() nur bei finalen Events (done, tool_start, error)

Frontend – History

  • web_search_result-Messages werden als Tool-Box mit klickbaren Source-Links gerendert (Domain + Title)
  • _mergeConsecutiveAssistantTexts() fügt Text-Messages zusammen, web_search_result-Messages dazwischen unterbrechen die Merge-Kette nicht
  • Leere web_search_result-Messages (Sources=[]) werden übersprungen

Frontend – Shared-Page

  • SharedEndpoint gibt web_search_result-Messages mit aus (Typ-Filter: text + web_search_result)
  • shared-page.js rendert web_search_result als Tool-Box mit Source-Links
  • Merge-Funktion überspringt web_search_result beim Rückwärts-Suchen, damit Texte zusammengeführt werden

Nachrichten teilen (Shared Messages)

Einzelne Nachrichten oder ganze Threads können als öffentliche Links geteilt werden – ohne Login aufrufbar.

Datenmodell

Tabelle shared_messages:

Spalte Typ Beschreibung
id INTEGER Primary Key
share_token TEXT UUID – öffentlicher Zugangsschlüssel
message_id INTEGER FK auf messages.id
user_id INTEGER Wer hat geteilt
include_context INTEGER 0 = Einzelnachricht, 1 = Thread bis dahin
created_at TEXT Erstellzeitpunkt
expires_at TEXT Optional: Ablaufdatum

API-Endpunkte (SharedEndpoint.cs)

Methode Route Auth Beschreibung
POST /api/messages/{id}/share ✅ Share erstellen (Body: {includeContext})
GET /api/shared/{token} ❌ Öffentlich: Geteilte Nachricht abrufen
GET /api/shared ✅ Eigene Shares auflisten
DELETE /api/shared/{token} ✅ Share-Link widerrufen

Frontend-Flow

  1. Share-Button (🔗) erscheint an jeder Nachricht im Chat (neben Reply, Delete, Mark)
  2. Klick öffnet Kontext-Menü: "Einzelne Nachricht" oder "Thread teilen"
  3. POST /api/messages/{id}/share → Token zurück → URL in Zwischenablage kopiert
  4. Toast: "Link kopiert!"

Öffentliche Ansicht (#/shared/{token})

  • Route #/shared/{token} → shared-page.js
  • Kein Auth nötig – Auth-Bypass in app.js + AuthMiddleware
  • Minimales Layout: Header ("// gott · Geteilte Nachricht"), Nachrichten mit Markdown-Rendering
  • Zwei Modi: single (eine Nachricht) oder context (Thread mit User/Assistant-Wechsel)

Workspace & File-Explorer

Workspace

Eine Session kann einen Workspace-Pfad haben. Dieser wird relativ zum DefaultPath des Users gespeichert (z.B. myapp) und via WorkspaceHelper.ResolveWorkspace() zum absoluten Pfad aufgelöst. Der Workspace:

  • Aktiviert die Datei-/Shell-Tools für den Agent
  • Ermöglicht den File-Explorer im Frontend
  • Bietet git status Informationen
  • Erlaubt das Ausführen von Shell-Befehlen (foreground + background)

WorkspaceHelper

Services/WorkspaceHelper.cs – Statische Hilfsklasse für Workspace-Pfade:

Methode Beschreibung
ResolveWorkspace(session, user) Relativer Workspace + DefaultPath → absoluter Pfad
ValidateRelativeWorkspace(workspace) Prüft auf .., ~, absolute Pfade → null bei ungültig
ToRelativeWorkspace(absolute, defaultPath) Absoluter Pfad → relativ zum DefaultPath

File-Explorer API

Endpoint Beschreibung
GET /api/workspace/tree Verzeichnisbaum (mit Ignore-Filtern)
GET /api/workspace/file Dateiinhalt lesen (max 2MB)
PUT /api/workspace/file Datei speichern
POST /api/workspace/mkdir Ordner erstellen im Workspace
DELETE /api/workspace/dir Leeren Ordner löschen im Workspace
GET /api/workspace/browse Verzeichnis-Browser (für Pfad-Auswahl)
POST /api/workspace/browse/mkdir Ordner erstellen per absolutem Pfad
GET /api/workspace/raw Raw-Datei ausliefern (Bilder, PDFs)
GET /api/workspace/agent/tree Agent-Memory-Verzeichnis
GET/PUT /api/workspace/agent/file Agent-Memory-Dateien lesen/schreiben
POST /api/workspace/agent/mkdir Ordner erstellen im Agent-Memory

Ignored Directories

bin, obj, node_modules, .git, .vs, .idea, publish, dist, out, build, target, .cache

Session-Exec

POST /api/sessions/{id}/exec führt Shell-Befehle im Workspace aus:

  • foreground: Synchron, wartet auf Ergebnis (30s Timeout)
  • background: Fire-and-forget via systemd-run

Avatar-System

Sessions und Agents können ein Bild/Avatar haben mit konfigurierbarem Zoom.

Datenfelder

Feld Tabellen Beschreibung
image / avatar sessions / agents Base64-kodiertes Bild (WebP, max 512px via ImageService)
image_small / avatar_small sessions / agents Thumbnail (WebP, 256px, Q70) für Listen/Dashboard
avatar_scale sessions, agents Zoom-Faktor (0.5× – 3×, Default 1.0)
avatar_offset_x sessions, agents Horizontale Position (-50% – +50%, Default 0), via CSS translate()
avatar_offset_y sessions, agents Vertikale Position (-50% – +50%, Default 0), via CSS translate()

Darstellung via CSS transform: scale(S) translate(X%, Y%) im .card-image Container (overflow: hidden).

Bild-Verarbeitung (ImageService)

Alle Bilder werden beim Upload in WebP konvertiert (statt PNG), was ~60-80% Speicherersparnis bringt:

Variante Methode Max. Größe Qualität Verwendung
Voll ResizeDataUrl() 512px Q80 Editor, Detail-Ansicht (GET /api/agents/{id}, GET /api/sessions/{id})
Thumbnail ResizeDataUrlSmall() 256px Q70 Listen, Dashboard (GET /api/agents, GET /api/sessions)

Die Listen-Endpoints liefern das Thumbnail als avatar/image-Feld (Fallback auf Voll-Bild wenn kein Thumbnail existiert). Die Detail-Endpoints liefern das volle Bild.

Avatar-Editor (avatar-editor.js)

Wiederverwendbares Modal-Modul, genutzt in Session- und Agent-Pages:

const editor = AvatarEditor.init({
    previewEl:      document.querySelector('.avatar-preview'),
    currentImage:   existingBase64OrNull,
    currentScale:   1.0,
    initialOffsetX: 0,
    initialOffsetY: 0,
    onChange:        (imageData, scale, offsetX, offsetY) => { /* Live-Preview */ }
});
// Werte auslesen: editor.getImage(), editor.getScale(), editor.getOffsetX(), editor.getOffsetY()
// Aufräumen: editor.destroy()

Features:

  • Upload: Datei-Input für Bild-Upload
  • Paste: Ctrl+V → Bild aus Zwischenablage einfügen
  • AI-Generate: Text-Prompt → Krea API → Bild generieren (nur wenn KreaToken konfiguriert)
  • Scale: Range-Slider 0.5× – 3× mit Live-Preview
  • Offset X/Y: Range-Slider -50% – +50% für horizontale/vertikale Positionierung
  • Clear: Bild entfernen

Dashboard-Darstellung

Cards zeigen Avatare mit transform: scale(S) translate(X%, Y%) im .card-image Container (overflow: hidden). Die Helper buildAgentCard() und buildSessionCard() in cards.js nutzen buildTransformStyle(scale, offsetX, offsetY) dafür.


LaTeX/Math-Rendering

Chat-Nachrichten unterstützen LaTeX-Formeln via KaTeX:

Syntax

  • $$...$$ → Block-Math (zentriert, eigene Zeile)
  • $...$ → Inline-Math (im Fließtext)

Rendering-Pipeline (in markdown.js renderMarkdown())

1. Code-Blöcke extrahieren und schützen (Platzhalter)
2. Block-LaTeX ($$...$$) extrahieren und schützen
3. Inline-LaTeX ($...$) extrahieren und schützen
4. Markdown-Rendering via marked.js
5. Code-Blöcke wiederherstellen
6. LaTeX-Platzhalter durch KaTeX.renderToString() ersetzen
7. Bei fehlerhaftem LaTeX: Fallback als <code class="katex-error">

Abhängigkeiten

  • wwwroot/js/lib/katex.min.js – KaTeX Engine (v0.16.21)
  • wwwroot/css/katex.min.css – Styles
  • wwwroot/css/fonts/ – 21 woff2-Fonts (self-hosted)

Funktioniert überall wo renderMarkdown() aufgerufen wird: Chat, Streaming, History, Archiv, Shared Page.


Windows Desktop App

Im WindowsApp/-Ordner liegt ein minimaler WPF WebView2 Client:

  • .NET 10 Windows, Microsoft.Web.WebView2
  • Lädt die Web-UI in einem nativen Fenster
  • Server-URL konfigurierbar via appsettings.json
  • Dark Background um weißen Flash zu vermeiden
  • Externe Links öffnen im Standard-Browser
  • Fenster: 930px breit, 95% Bildschirmhöhe, zentriert

OpenClaw Import

Sessions können mit Chatverlauf aus einer OpenClaw-Instanz befüllt werden. Die Import-Quelle ist eine SQLite-Datenbank (Build/<OS>/publish/data/openclaw-sessions.db).

Funktionsweise

  • GET /api/openclaw/sessions – Listet alle Sessions aus der OpenClaw-DB mit Metadaten (Message-Count, Model, Summary, Preview-Messages)
  • POST /api/openclaw/import – Importiert eine OpenClaw-Session in eine bestehende Gott-Session

Import-Logik

  1. Liest alle message-Entries aus der OpenClaw-DB, gruppiert nach chainId
  2. Nur Text-Nachrichten werden importiert – Tool-Use/Tool-Result werden übersprungen
  3. User-Message-Bereinigung: Webchat-Prefixe ([Direct 1:1 webchat ...], [Current message ...], [cron:...]), Conversation info-Blöcke werden entfernt
  4. Pro Chain wird ein ChainRecord + MessageRecords erstellt, alle mit tag = 'openclaw-import'
  5. Timestamps werden aus OpenClaw übernommen (created_at)
  6. Re-Import = Update: Vorherige Import-Chains (erkennbar am Tag) werden gelöscht und neu importiert. Bestehende Compactions werden ebenfalls gelöscht.

Sortierung (sort_key)

Importierte Messages werden immer vor normalen Messages einsortiert, da sie historisch älter sind:

sort_key = CASE WHEN tag = 'openclaw-import' THEN id - 10000000000 ELSE id END

Alle History-Queries (initial load, before/after-Paging, Polling) sortieren nach sort_key. OpenClaw-Messages bekommen negative sort_keys → erscheinen immer ganz oben. Innerhalb jeder Gruppe (OpenClaw / normal) wird nach id sortiert.

Frontend

  • Dashboard: Session-Menü → „OpenClaw Import" → Modal mit Session-Auswahl + Preview
  • Chat: Importierte Nachrichten zeigen ein blaues „OC"-Badge

Remote-Verbindungen

Remote-Clients (z.B. Windows-PCs) können sich via WebSocket mit dem Server verbinden. Über die Verbindung kann der AI-Agent Shell-Befehle auf dem Remote-Client ausführen.

Architektur

┌──────────────┐  WebSocket  ┌───────────────┐  Tool-Call  ┌───────────────┐
│ Remote-Client│◄────────────►│  Gott Server  │◄───────────►│  AI-Agent     │
│ (PowerShell) │  (bidirekt.) │  RemoteEndpoint│            │  remote_execute│
└──────────────┘              └───────────────┘              └───────────────┘

Verbindungsaufbau

  1. Remote-Client führt irm https://server/remote | iex aus → lädt remote.ps1
  2. Script baut WebSocket-Verbindung zu /api/remote auf
  3. Sendet hello-Message mit Hostname, Username, OS-Version
  4. RemoteConnectionManager registriert die Verbindung

Session-Zuweisung

  • Im Chat: Remote-Button → Modal zeigt aktive Verbindungen
  • Admin weist Verbindung einer Session zu (POST /api/remote/assign)
  • AI-Agent bekommt remote_execute-Tool → führt Befehle auf dem Remote-Client aus
  • Ergebnis wird synchron via WebSocket zurückgeliefert (Timeout: konfigurierbarer ExecuteTimeout)

Protokoll (JSON über WebSocket)

Richtung Type Payload
Client → Server hello hostname, username, os
Server → Client execute command
Client → Server result exitCode, output, error
Client → Server ping –
Server → Client pong –

Semantische Suche (Embedding)

Lokale Sentence-Embeddings ermöglichen semantische Suche über Chat-Nachrichten und Memory-Dateien.

Technologie

  • Modell: all-MiniLM-L6-v2 (ONNX Runtime, 384-dimensionale Embeddings)
  • Tokenisierung: WordPiece (BERT-kompatibel, eigene Implementierung)
  • Speicherung: SQLite-Tabellen message_embeddings + memory_file_embeddings (Vektor als BLOB)
  • Suche: Brute-Force Cosine Similarity (ausreichend für <100k Embeddings)

Komponenten

Service Aufgabe
EmbeddingService ONNX-Modell laden, Embeddings generieren (thread-safe via SemaphoreSlim)
VectorSearchService Schema-Management, Embedding-Storage, Similarity-Search
EmbeddingBackgroundService Backfill beim Start + Live-Queue für neue Messages/Memory-Files

Funktionsweise

  1. Backfill beim Start: Alle bestehenden Text-Messages (user + assistant, ≥10 Zeichen) werden embedded
  2. Memory-Backfill: Alle .md-Dateien in Agent-Verzeichnissen werden in 500-Zeichen-Chunks embedded
  3. Live-Embedding: Neue Messages/Memory-Writes werden via Queue sofort embedded
  4. Suche (memory_search Tool): Query wird embedded, Cosine Similarity gegen alle Embeddings berechnet, Top-N Ergebnisse zurückgegeben

Konfiguration

Das ONNX-Modell muss unter data/models/all-MiniLM-L6-v2/ liegen (model.onnx + vocab.txt). Wenn nicht vorhanden, wird der Service deaktiviert und das Frontend zeigt eine Warnung.


API-Key-Verwaltung

API-Keys werden in der Datenbank verwaltet (Tabellen api_keys + scanned_keys) statt in der Konfigurationsdatei.

Funktionsweise

  • Mehrere Keys pro Provider (z.B. anthropic) können gespeichert werden
  • Nur ein Key pro Provider kann gleichzeitig aktiv sein
  • Aktivierung deaktiviert automatisch alle anderen Keys desselben Providers
  • Live-Aktualisierung: Bei Aktivierung/Deaktivierung wird der Token sofort im laufenden Service aktualisiert (kein Neustart nötig)
  • Migration: Bestehender AnthropicToken aus appsettings.Production.json wird beim ersten Start automatisch migriert
  • Source-URL: Bei adoptierten Scan-Keys wird die GitHub-URL gespeichert

Key-Check (nur Anthropic)

POST /api/admin/api-keys/{id}/check sendet eine minimale Anfrage an die Anthropic API (claude-sonnet-4-20250514, max_tokens=1) mit denselben Headers wie der echte Chat-Client (Authorization: Bearer, anthropic-beta, User-Agent, x-app, anthropic-dangerous-direct-browser-access) und liest die Response-Headers aus:

  • Status: valid, invalid, rate_limited, quota_exceeded, error
  • Plan-Erkennung: Max (overage > 0), Pro (kein fallback-Header), Pro/Max (sonst), API Console (keine unified-Headers)
  • Budget-Auslastung: 5h und 7d Prozentwerte aus unified-* Headers

Passive Usage-Aktualisierung

Nach jedem API-Request an Anthropic (Streaming, Sub-Agent, NonStreaming) werden die Response-Headers automatisch ausgelesen und Plan/Usage des aktiven API-Keys in der DB aktualisiert (AnthropicKeyChecker.ExtractMetaFromHeaders()). Kein separater Check-Request nötig – die Daten sind immer aktuell.

GitHub-Scanner (KeyScannerService)

Durchsucht GitHub Code-Search nach geleakten Anthropic API-Keys:

  • 13 Sprachen (Python, JavaScript, TypeScript, Shell, Markdown, JSON, YAML, TOML, Go, Rust, Ruby, Java, PHP)
  • 24 Pfad-Extensions (.env, .cfg, .ini, .conf, .txt, .log, .md, .json, .yaml, .yml, .toml, .py, .js, .ts, .sh, .bash, .go, .rs, .rb, .java, .php, .config, .properties, .xml)
  • Ablauf: POST /api/admin/api-keys/scan → GitHub-Suche → neue Keys in scanned_keys speichern → jeden Key mit AnthropicKeyChecker prüfen → Status + Plan + Usage aktualisieren
  • Adopt: POST /api/admin/api-keys/scanned/{id}/adopt → Key in api_keys übernehmen, Name = user/repo, Source-URL = vollständige GitHub-URL
  • Live-Updates: Scan-Ergebnisse werden nach jeder Iteration in der DB gespeichert (nicht erst am Ende)

Chat Usage-Badge (Frontend)

  • Overlay oben zentriert im Chat (nur für Admins) mit visuellen Usage-Balken (Sitzung + Woche)
  • Farbstufen: Grün (<70%), Orange (70-89%), Rot (≥90%)
  • Auto-Hide: Ausgeblendet beim Hochscrollen (wenn Auto-Scroll deaktiviert)
  • Auto-Refresh: Badge aktualisiert sich bei neuen Nachrichten (via pollHistory)
  • Key-Switch-Modal: Klick auf Badge öffnet Modal mit allen API-Keys, Zeile klickbar zum Wechseln
  • Manueller Check: 🔄-Button neben Badge prüft Key und aktualisiert

Deployment

WICHTIG: Das Deployment ist ein manueller Vorgang, der durch den Benutzer auf dem Server durchgeführt werden muss. Das System führt kein automatisches Deployment durch.

Goldene Regel für Änderungen

  • Arbeiten Sie AUSSCHLIESSLICH im Verzeichnis wwwroot/ für Frontend-Änderungen.
  • Editiere NIEMALS Dateien in Build/*/publish/wwwroot/! Diese Verzeichnisse werden bei jedem Build überschrieben.
  • Das Verzeichnis Build/*/publish/data/gott.db darf niemals manuell gelöscht, geleert oder direkt modifiziert werden.

Deployment-Vorgang (Beispiel für Linux)

Das vorhandene Shell-Skript deploy.sh dient lediglich als Hilfestellung für den manuellen Prozess:

  1. Frontend-Anpassungen vornehmen (in wwwroot/).
  2. Manuelles Deployment auf dem Server ausführen:
    # Beispiel-Ablauf:
    systemctl stop gott
    dotnet publish -c Release -o Build/Linux/publish
    systemctl start gott
    

systemd

Die Anwendung ist als systemd-Service konfiguriert und läuft standardmäßig auf Port 19000.


Konfiguration

appsettings.json

{
  "Port": 19000,                // Server-Port (Default 19000, erfordert Neustart)
  "MaxIterations": 100,         // Max Tool-Loop Iterationen pro Chat
  "MaxHistory": 120,            // Max Messages in Chat-History
  "ReminderInterval": 30,      // System-Prompt-Reminder alle N Messages
  "ExecuteTimeout": 180,       // Timeout für Shell-Befehle in Sekunden
  "PayloadLogging": false,      // API-Payloads loggen (Debug)
  "PayloadLoggingGzip": false,  // Payload-Logs als .gz komprimieren
  "KreaToken": "",               // Krea API Token (optional)
  "KreaApiKey": "",               // API-Key für Krea-Endpoints ohne User-Auth (optional)
  "GeminiApiKey": ""              // Google Gemini API Key (kostenlos via aistudio.google.com/apikey)
}

Hinweis: AnthropicToken wird nicht mehr über appsettings.json konfiguriert, sondern über die API-Key-Verwaltung im Admin-Bereich (DB-Tabelle api_keys). Bestehende Tokens werden beim ersten Start automatisch aus appsettings.Production.json migriert.

appsettings.Production.json

Überschreibt Werte aus appsettings.json im Production-Environment. Wird nicht beim Publish mitkopiert (liegt nur im Build/<OS>/publish/-Verzeichnis). Verwaltung über die Admin-UI (Servereinstellungen, #/server-settings).

Environment

  • ASPNETCORE_ENVIRONMENT=Production → lädt appsettings.Production.json
  • Tokens und Secrets werden über die Server-Settings-UI in appsettings.Production.json geschrieben

Datenbank-Migrationen

Die DatabaseService.InitializeDatabase() handhabt Schema-Erstellung und Migrationen in einem einzigen Methoden-Aufruf:

  1. Tabellen-Erstellung via CREATE TABLE IF NOT EXISTS
  2. Spalten-Migration via TryAddColumn() – fängt "column already exists" ab
  3. Daten-Migration (z.B. auto_commit von INTEGER zu TEXT, use_web_search zu web_search_version)
  4. Token-Migration – Bestehender AnthropicToken aus appsettings.Production.json wird automatisch in api_keys-Tabelle migriert
  5. Bild-Migration – Konvertierung bestehender PNG/JPEG-Avatare zu WebP + Generierung von Thumbnails (avatar_small, image_small)

Dieses Pattern ermöglicht:

  • Idempotente Ausführung bei jedem App-Start
  • Keine separate Migrations-Verwaltung nötig
  • Neue Features können einfach Spalten hinzufügen
  • Abwärtskompatibel – bestehende Daten bleiben erhalten