bifroest/ai_workspace_architekturkonzept.md
2026-10-27 08:34:17 +01:00

2507 lines
113 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# AI Workspace -- Technisches und fachliches Architekturkonzept
**Version:** 0.2\
**Status:** Architekturentwurf für eine erste Demo und spätere
Unternehmensnutzung\
**Zielgruppe:** Entwicklung, Architektur, IT-Security und technische
Verantwortliche
**Änderungen gegenüber 0.1:** Entscheidungen aus dem Architekturreview
eingearbeitet (siehe Abschnitt 2.1 und 16). Wesentlich sind:
Ausführung jedes Chat-Runs im Worker, SSE über PostgreSQL,
Team-Zuordnung von Workspaces, Freigabe durch Workspace-Admins,
DENY-by-default für nicht eingestufte Tools, Git-Schreibzugriff nur
über Branch und Pull Request, Munin als Agentic Memory, Hugin als
Quelle für Regeln, Skills, Befehle, Subagenten und MCP-Anbindungen,
DuckDB für Uploads sowie ein überarbeiteter Task-Lebenszyklus.
------------------------------------------------------------------------
## 1. Ziel und Produktidee
Die Anwendung ist eine kontextgebundene KI-Arbeitsplattform für Teams
und Mitarbeitende im Unternehmen. Sie ist ausdrücklich **kein frei
zugänglicher allgemeiner Chatbot**. Nutzer richten zunächst einen
Workspace ein und verbinden darin eine oder mehrere freigegebene
Datenquellen. Erst danach wird das Chatinterface für diesen Kontext
zugänglich.
Typische Quellen und Integrationen:
- Git-Repositories, beispielsweise Bitbucket Data Center
- Datenbanken
- Datei-Uploads, beispielsweise CSV, JSON, Dokumente oder Logs
- Zentrale MCP-Server im Firmennetz, darunter Munin als Agentic Memory
- Hugin als Register für Regeln, Skills, Befehle, Subagenten und
MCP-Anbindungen (Konfigurationsquelle, keine Datenquelle)
- Lokal gestartete MCP-Prozesse innerhalb einer kontrollierten
Server-/Worker-Laufzeit (nicht im MVP)
- Weitere Unternehmenssysteme über MCP oder native Connectoren
Die KI soll folgende Arbeitsweisen unterstützen:
1. **Lesen und analysieren:** Dateien, Repository-Inhalte,
Datenbankinformationen und andere freigegebene Daten untersuchen.
2. **Änderungen nach Freigabe:** Änderungen an Dateien, Code oder Daten
sowie andere schreibende Aktionen kontrolliert ausführen.
3. **Mehrstufige Aufgaben:** Mehrere Schritte und Tool-Aufrufe
ausführen, Zwischenergebnisse persistieren, auf Freigaben warten und
nach Unterbrechungen fortgesetzt werden können.
Die Plattform ist die zentrale Arbeits- und Steuerungsebene zwischen
Nutzern, KI-Modellen, Datenquellen und Werkzeugen. Sie ersetzt weder die
Quellsysteme noch das KI-Modell.
### Leitprinzipien
1. **Context first:** Ein regulärer Chat setzt einen gültigen Workspace
und erlaubte Datenquellen voraus.
2. **Tool-driven:** Die KI kann nur freigegebene Tools und Connectoren
verwenden.
3. **Human in the loop:** Riskante Aktionen können oder müssen explizit
freigegeben werden.
4. **Durable execution:** Aufgabenstatus und relevante
Zwischenergebnisse überleben HTTP-Timeouts und Worker-Neustarts.
5. **Security by design:** Rechte werden serverseitig geprüft;
Modellantworten sind keine Berechtigungsnachweise.
6. **Modularer Monolith:** Ein gemeinsames Codeprojekt mit klaren
fachlichen Modulen, ohne vorzeitig eine Microservice-Landschaft
einzuführen.
7. **Austauschbarkeit:** LLM-Zugang, Identitätsprovider und
Datenquellen werden hinter internen Abstraktionen gehalten.
------------------------------------------------------------------------
## 2. Festgelegte Rahmenbedingungen
-----------------------------------------------------------------------
Bereich Entscheidung
----------------------------------- -----------------------------------
Frontend Jinja2-Templates und HTMX
Backend FastAPI
Frontend-Kommunikation Klassische
HTML-Antworten/Fragmente, HTMX und
SSE für Streaming und Status
Persistenz PostgreSQL als zentrale Datenbank
Redis Für das MVP nicht vorgesehen
LLM-Anbindung OpenAI-kompatibles AI Gateway mit
einem API-Key pro Team; in der
Entwicklung zunächst die OpenAI-API
mit `gpt-6-luna`
MCP Zentrale Server im Firmennetz über
Streamable HTTP; lokal gestartete
Prozesse nicht im MVP
Zielgruppe Teams und Mitarbeitende im
Unternehmen
Anmeldung in der Demo Zunächst einfache Demo-Anmeldung;
Architektur für spätere
Keycloak-/OIDC-Integration vorsehen
Agentenfähigkeiten Lesen, Änderungen nach Freigabe und
mehrstufige Aufgaben
Freigabemodell In der Demo risikobasiert;
zusätzlich konfigurierbarer Modus,
in dem jede schreibende Aktion eine
Freigabe benötigt; Nutzer
beantragen, Workspace-Admins geben
frei
Deployment OpenShift; Infrastruktur und
Plattformbetrieb sind nicht Teil
dieses Konzepts
-----------------------------------------------------------------------
### 2.1 Architekturentscheidungen (Review v0.2)
-----------------------------------------------------------------------
Thema Entscheidung
----------------------------------- -----------------------------------
Identität gegenüber Quellen Service-Account bzw. technischer
Token pro Quelle; der
Workspace-Admin bestätigt, dass
alle Mitglieder diese Daten sehen
dürfen. Nutzer-Delegation (Token
Exchange) als spätere Erweiterung
Ausführung Jede Chat-Nachricht wird als Run im
Worker ausgeführt; FastAPI legt
Runs nur an und liefert Events aus
Streaming Tabelle `run_events`, PostgreSQL
`LISTEN/NOTIFY` als Signal, SSE mit
`Last-Event-ID`
Team-Zuordnung Jeder Workspace gehört genau einem
Team; daraus folgen Gateway-Key,
Limits und Munin-Workspace
Git-Schreibzugriff Ausschließlich Branch `ai/*` und
Pull Request; kein direkter Push
auf Zielbranches
Lokale MCP-Prozesse Nicht im MVP; stdio-Server bei
Bedarf als eigenes Deployment mit
HTTP-Transport
Nicht eingestufte Tools `DENY`, bis ein Admin sie
klassifiziert; Tool-Definitionen
werden per Hash gepinnt
Freigaben Nutzer beantragen,
Workspace-Admins entscheiden;
Anträge laufen nach einer Frist ab
Policy-Technik DB-Tabelle und Python-Regeln;
Gateway-Guardrails als zusätzliche
Schicht
Benachrichtigung Nur In-App im MVP
Retrieval Agentisch über Such-/Lese-Tools;
Munin (MCP) als Agentic Memory
Agentenverhalten Regeln, Skills, Befehle, Subagenten
und MCP-Anbindungen aus Hugin;
Auswahl pro Workspace, Versionen
festgeschrieben, keine Rechte durch
Hugin-Inhalte (7.9)
Datenanalyse Uploads über DuckDB mit
ausschließlich lesenden
SQL-Abfragen
Erste Datenquelle Git allgemein (Lesen per Clone),
Pull Requests über Bitbucket Data
Center; Ersatz: Testdatenbank
Datenschutz und Betriebsrat Wird separat behandelt; Demo nur
mit Testnutzern und Testdaten
-----------------------------------------------------------------------
### Nicht-Ziele für die erste Version
- Kein allgemeiner Chat ohne Workspace-Kontext
- Kein eigenständiges React-/SPA-Frontend
- Keine Redis-Abhängigkeit im MVP
- Keine Microservice-Aufteilung ohne konkrete Notwendigkeit
- Keine beliebige Ausführung vom Nutzer eingegebener Programme oder
MCP-Endpunkte
- Keine freie Code-Ausführung durch die KI; Datenanalyse erfolgt über
lesendes SQL in DuckDB
- Keine lokal gestarteten (stdio-)MCP-Prozesse im MVP
- Kein direkter Push auf Zielbranches
- Keine automatische, unbeschränkte Agentenautonomie ohne Policies,
Limits und Audit
- Keine detaillierte Ausarbeitung des OpenShift-Deployments
- Keine Prüfung von Tool-Ergebnissen auf Prompt Injection durch diese
Anwendung; das ist Aufgabe der Gateway-Guardrails
- Keine Skills, Regeln oder Agentendefinitionen aus Dateien des
verbundenen Repositorys (z. B. `.claude/skills/`); maßgeblich ist
nur Hugin
- Kein selbstständiges Nachladen von Hugin-Paketen durch die KI im MVP
- Datenschutz-Folgenabschätzung und Betriebsvereinbarung werden
separat behandelt
------------------------------------------------------------------------
## 3. Gesamtarchitektur
``` mermaid
flowchart TB
U["Mitarbeitende im Unternehmen"]
subgraph UI["Weboberfläche"]
J["Jinja2 Templates"]
H["HTMX Interaktionen"]
S["SSE Streaming und Task-Status"]
end
subgraph APP["Modularer Monolith – FastAPI und Worker aus einer Codebasis"]
AUTH["Identity und Access"]
WS["Workspace und Data Sources"]
CHAT["Chat API und SSE"]
ORCH["AI Orchestrator (Worker)"]
POLICY["Policy und Approval Engine"]
TASK["Task Engine (Worker)"]
AUDIT["Audit und Event Logging"]
end
subgraph DATA["Persistenz und Secrets"]
PG[("PostgreSQL")]
OBJ["Dateiablage / Object Storage"]
SEC["Secret Store"]
end
subgraph INTEGRATIONS["Integrationsschicht"]
MCP["MCP Client Manager"]
CON["Native Connectoren"]
GATE["OpenAI-kompatibles AI Gateway"]
end
subgraph TARGETS["Unternehmenssysteme"]
REMOTE["MCP-Server im Firmennetz"]
MUNIN["Munin Agentic Memory (MCP)"]
HUGIN["Hugin Register (Skills, Regeln, Agenten)"]
REPO["Git-Server und Bitbucket Data Center"]
DB["Datenbanken und weitere Quellen"]
DUCK["DuckDB für Uploads"]
LLM["Verfügbare KI-Modelle"]
end
U --> UI
UI --> APP
AUTH --> WS
CHAT -- "Run anlegen" --> PG
TASK -- "Job beanspruchen" --> PG
TASK --> ORCH
ORCH --> POLICY
ORCH --> MCP
ORCH --> CON
ORCH --> GATE
MCP --> REMOTE
MCP --> MUNIN
WS -- "Abgleich" --> HUGIN
CON --> REPO
CON --> DB
CON --> DUCK
GATE --> LLM
WS --> PG
CHAT --> PG
TASK --> PG
POLICY --> PG
AUDIT --> PG
MCP -. "Zugangsdatenreferenzen" .-> SEC
CON -. "Zugangsdatenreferenzen" .-> SEC
WS -. "Dateien" .-> OBJ
```
Das Diagramm zeigt logische Verantwortlichkeiten, nicht zwingend
separate Deployments. FastAPI, Orchestrator, Policy Engine und Task
Engine liegen im selben Codeprojekt. Es gibt zwei Prozesstypen:
- **Web-Prozess (FastAPI):** UI, Autorisierung, Anlegen von Runs,
Freigabeentscheidungen und Ausliefern von Events per SSE.
- **Worker-Prozess:** Führt jeden Run aus, also auch einfache
Chat-Antworten, inklusive Modellaufrufen, Tool-Schleife und
Freigabepausen.
Es gibt damit genau einen Ausführungspfad für Chat und mehrstufige
Tasks. Ein Chat-Run ist ein Task mit typischerweise wenigen Schritten.
### Verantwortlichkeiten
-----------------------------------------------------------------------
Komponente Aufgabe
----------------------------------- -----------------------------------
FastAPI + Jinja2 + HTMX UI, Routing, Formulare,
HTML-Fragmente, Streaming und
Statusaktualisierung
Identity & Access Demo-Identität, spätere
OIDC-/Keycloak-Integration, Rollen
und Teamzuordnung
Workspace Service Workspaces, Datenquellen,
Mitgliedschaften und Konfiguration
AI Orchestrator Modellaufrufe, Kontextaufbau,
Tool-Calling-Schleife und
Antwortgenerierung; läuft im Worker
MCP Client Manager MCP-Verbindungen, Capability
Discovery, Tool-Aufrufe und
Lifecycle
Native Connectoren Direkte API-Anbindungen für
Quellen, bei denen MCP nicht
notwendig oder verfügbar ist
Policy Engine Berechtigungsprüfung,
Risikobewertung und
Freigabeentscheidungen
Approval Service Freigabeanträge, Entscheidungen,
Ablaufzeiten und erneute
Validierung
Task Engine Mehrstufige Ausführung,
persistierter Zustand, Abbruch und
Wiederaufnahme
PostgreSQL Geschäftsdaten, Nachrichten, Tasks,
Freigaben, Tool-Aufrufe und Audit
AI Gateway Adapter Einheitliche Kommunikation mit dem
OpenAI-kompatiblen Gateway
Secret Store Sichere Verwaltung von Tokens,
Passwörtern und anderen
Zugangsdaten
Dateiablage Uploads und größere Dateien;
PostgreSQL speichert Metadaten und
Referenzen
-----------------------------------------------------------------------
------------------------------------------------------------------------
## 4. Frontend: Jinja2 und HTMX
### 4.1 Architekturentscheidung
Jinja2 + HTMX ist für eine interne Unternehmensanwendung eine passende
und wartbare Wahl. Ein separates SPA-Frontend ist für den ersten Umfang
nicht erforderlich.
- **Jinja2** rendert Seiten und wiederverwendbare HTML-Fragmente
serverseitig.
- **HTMX** übernimmt Formulare, Workspace-Wechsel, Chatverlauf,
Freigabedialoge und Teilaktualisierungen.
- **SSE (Server-Sent Events)** liefert Chat-Tokens, Task-Fortschritt
und Statusereignisse (Mechanismus siehe 4.4).
- Kleine JavaScript-Ergänzungen sind dort zulässig, wo SSE-Handling
oder komplexere Interaktionen sie erfordern.
- **WebSockets** sind zunächst nicht erforderlich; sie können später
ergänzt werden, falls bidirektionale Echtzeitkommunikation nötig
wird.
Der Zustand eines Tasks liegt immer im Backend und in PostgreSQL, nicht
nur in der offenen Browserverbindung. Nach einem Seiten-Reload muss der
Nutzer den aktuellen Zustand erneut laden können.
### 4.2 Seitenstruktur
1. **Workspace-Übersicht**
- Eigene und geteilte Workspaces
- Letzte Aktivitäten
- Verbindungsstatus
- Workspace anlegen und öffnen
2. **Workspace erstellen und konfigurieren**
- Name und Beschreibung
- Mitglieder und Rollen
- Datenquellen hinzufügen
- Quellen testen und Fähigkeiten prüfen
3. **Datenquellenverwaltung**
- Quellentyp auswählen
- MCP-Server oder nativen Connector konfigurieren
- Verbindung testen
- Tools und Ressourcen anzeigen
- Berechtigungen und Policies konfigurieren
4. **Workspace-Chat**
- Sichtbarer aktiver Kontext
- Mehrere Chat-Sessions pro Workspace
- Streaming-Antworten
- Quellenreferenzen und Code-/Tabellenansichten
- Tool-Aufrufe und Run-Status
- Freigaben und Task-Fortschritt
5. **Tasks und Freigaben**
- Laufende, wartende, abgeschlossene und fehlgeschlagene Tasks
- Freigabeanträge
- Abbruch und kontrollierte Wiederaufnahme
- Fehler und Ausführungshistorie
6. **Administration**
- Modellkonfiguration
- MCP-Registrierungen
- Connectoren
- Rollen und Teamverwaltung
- Freigaberichtlinien
- Audit-Ansicht
### 4.3 UX-Leitlinien
- Der aktive Workspace und die aktiven Datenquellen müssen jederzeit
sichtbar sein.
- Die Oberfläche muss zeigen, welche Quellen und Tools für die KI
verfügbar sind.
- Tool-Aufrufe und deren Ergebnisse sollen nachvollziehbar sein.
- Schreibende Aktionen müssen vor ihrer Ausführung verständlich
beschrieben werden.
- Bei langen Aufgaben müssen Status, aktuelle Phase und gegebenenfalls
erforderliche Nutzeraktion sichtbar sein.
- Es muss klar zwischen einer Modellantwort, einem echten
Tool-Ergebnis und einem Fehler unterschieden werden.
- Wartet ein Run auf eine Freigabe, ist der Chat für den Nutzer
asynchron: Status „wartet auf Freigabe durch Workspace-Admin“ wird
angezeigt, das Ergebnis erscheint nach der Entscheidung.
- Abgelaufene Freigabeanträge werden als „abgelaufen“ angezeigt. Der
Nutzer kann denselben Vorschlag mit einem Klick erneut beantragen;
dabei werden Basis-Commit und Diff gegen den aktuellen Stand neu
geprüft und ein neuer Antrag angelegt. Abgelehnte Anträge bieten
diese Option nicht.
- Offene Freigaben werden Workspace-Admins in der App angezeigt
(Badge, Liste, SSE-Aktualisierung). E-Mail oder Chat-Benachrichtigung
sind nicht Teil des MVP.
- Blockierungen durch Gateway-Guardrails werden als eigener,
verständlicher Zustand dargestellt, nicht als allgemeiner Fehler.
### 4.4 Streaming über PostgreSQL
Ohne Redis und bei mehreren Web- und Worker-Pods wird das Streaming wie
folgt umgesetzt:
1. Der Worker schreibt Ereignisse in die Tabelle `run_events` mit
fortlaufender Sequenznummer pro Run (Tokens, Tool-Status,
Statuswechsel). Tokens werden gebündelt geschrieben, etwa alle
100–200 ms, nicht einzeln.
2. Nach dem Schreiben sendet der Worker `NOTIFY` auf einem Kanal pro
Run oder einem gemeinsamen Kanal mit Run-ID.
3. Der Web-Prozess hält pro Prozess eine `LISTEN`-Verbindung und liest
bei Signal neue Events per `SELECT … WHERE run_id = ? AND seq > ?`.
4. Clients verbinden sich mit `Last-Event-ID` erneut und erhalten alle
fehlenden Events. Nach einem Reload wird der Zustand vollständig aus
der Datenbank aufgebaut.
5. Fallback: Kurzes Polling, falls `NOTIFY` ausfällt.
`LISTEN` benötigt eine dauerhafte Datenbankverbindung und funktioniert
nicht hinter PgBouncer im Transaction-Modus. Alte `run_events` werden
nach Abschluss eines Runs verdichtet oder gelöscht; die finale Antwort
liegt in `messages`.
### 4.5 Darstellung von Modellausgaben
Modellausgaben und Tool-Ergebnisse sind nicht vertrauenswürdig und
werden vor der Darstellung bereinigt:
- Markdown wird serverseitig gerendert und mit einer Allowlist
bereinigt (z. B. `nh3`); kein Roh-HTML aus Modellausgaben.
- Keine externen Bilder; Links werden als Text oder mit sichtbarem
Ziel dargestellt, um Datenabfluss über URLs zu verhindern.
- Strikte Content Security Policy.
- Während des Streamings wird Rohtext angezeigt; die gerenderte
Fassung ersetzt ihn nach Abschluss der Nachricht.
Umgesetzt mit `markdown-it-py` (CommonMark, Tabellen, ohne Roh-HTML) und
`nh3` als zweiter Sicherung. Bilder werden als Text mit Ziel-URL
gezeigt, Links nur für http, https und mailto, mit sichtbarem Ziel hinter
dem Linktext. Nutzernachrichten bleiben reiner Text.
------------------------------------------------------------------------
## 5. Identity, Anmeldung und Rollen
### 5.1 Demo und späteres Keycloak
Die erste Demo kann eine vereinfachte Anmeldung verwenden. Die Anwendung
sollte aber von Anfang an ein einheitliches internes
User-Principal-Modell verwenden und nicht fachliche Berechtigungen an
die Demo-Authentifizierung koppeln.
**Übergangslösung (umgesetzt):** Eigene Passwörter mit Argon2id. Der
Plattform-Admin legt Nutzer mit einem Einmal-Passwort an, das nur einmal
angezeigt wird; beim ersten Login setzt der Nutzer ein eigenes
(mindestens 12 Zeichen, ohne Nutzernamen). Nach fünf Fehlversuchen ist
das Konto 15 Minuten gesperrt; Zurücksetzen durch den Admin entsperrt
und beendet alle Sitzungen. Ein Passwortwechsel beendet die übrigen
Sitzungen. Das gemeinsame Demo-Passwort gilt nur noch für Nutzer ohne
eigenes Passwort und nur, solange es konfiguriert ist. Den ersten Admin
einer leeren Installation legt `aiw create-admin` an.
Später kann die Authentifizierung über **OIDC mit Keycloak** integriert
werden; die eigenen Passwörter entfallen dann. Die interne Anwendung arbeitet dann weiterhin mit einer stabilen
Benutzer-ID, Identitätsattributen, Teams und Rollen.
``` mermaid
flowchart LR
LOGIN["Login"] --> ID["Identity Provider Adapter"]
ID --> DEMO["Demo Identity"]
ID --> OIDC["OIDC / Keycloak"]
DEMO --> PRINCIPAL["Einheitliches User Principal"]
OIDC --> PRINCIPAL
PRINCIPAL --> RBAC["Rollen und Teamrechte"]
RBAC --> WS["Workspace-Zugriff"]
WS --> POLICY["Tool- und Quellenberechtigungen"]
```
### 5.2 Rollen für das MVP
-----------------------------------------------------------------------
Rolle Aufgaben und Rechte
----------------------------------- -----------------------------------
User Eigene oder freigegebene Workspaces
nutzen und Freigaben beantragen
Workspace Admin (Owner) Quellen verwalten, Tools einstufen,
Mitglieder zuordnen,
Workspace-Einstellungen ändern und
Freigaben im eigenen Workspace
erteilen oder ablehnen
Globaler Approver (später) Freigaben für Risikoklassen, die
über die Befugnis von
Workspace-Admins hinausgehen
Administrator Globale Modellkonfiguration,
Connector-Registrierungen,
Team-Zugänge zum Gateway und
Policies verwalten
-----------------------------------------------------------------------
Die Rollen können später feiner aufgeteilt werden.
Workspace-Administration bedeutet nicht automatisch, dass jemand jede
sicherheitskritische Aktion freigeben darf. Dafür hat jede Policy ein
Feld für die erforderliche Freigabestufe (`workspace_admin` oder
`global_approver`); im MVP wird nur `workspace_admin` genutzt.
### 5.4 Teams und Workspaces
- Jeder Workspace gehört genau einem Team. Nutzer in mehreren Teams
wählen das Team beim Anlegen.
- Aus dem Team ergeben sich der Gateway-API-Key, Kosten- und
Rate-Limits sowie der Munin-Workspace.
- Ein Workspace kann mehrere Admins haben, damit Freigaben nicht an
einer Person hängen.
### 5.5 Identität gegenüber Quellsystemen
Im MVP greifen Connectoren mit einem technischen Account oder Token pro
Quelle zu, nicht mit der Identität des einzelnen Nutzers. Daraus folgt:
- Alle Mitglieder eines Workspace können über die KI alle Daten der
verbundenen Quellen lesen, auch wenn sie im Quellsystem selbst keinen
Zugriff hätten.
- Der Workspace-Admin bestätigt beim Verbinden einer Quelle
ausdrücklich, dass alle Mitglieder diese Daten sehen dürfen. Die
Bestätigung wird auditiert.
- Technische Accounts erhalten nur minimale Rechte (z. B.
Repo-bezogene Tokens, lesende DB-User).
- Nutzer-Delegation über Keycloak Token Exchange oder OAuth gegenüber
MCP-Servern ist als spätere Erweiterung vorgesehen; das
Connector-Interface erhält dafür bereits den Nutzerkontext.
### 5.3 Sicherheitsgrenze der Demo
Eine öffentlich erreichbare Anwendung mit Zugriff auf interne MCP-Server
darf nicht als offene Registrierung mit beliebigem Zugriff auf das
Firmennetz umgesetzt werden.
Für die erste Demo sind mindestens erforderlich:
- Beschränkung auf eine dedizierte Testumgebung und kontrollierte
Nutzergruppe
- Ausschließlich explizit freigegebene Quellen und Tools
- Keine Zugangsdaten im Browser oder im Chatverlauf
- Serverseitige Autorisierung für jeden Zugriff
- Begrenzung der erreichbaren Netzwerkziele und lokalen Prozesse
Die spätere Keycloak-Integration ersetzt diese fachlichen
Autorisierungs- und Netzwerkschutzmaßnahmen nicht.
------------------------------------------------------------------------
## 6. Workspace- und Datenquellenmodell
Der Workspace ist die oberste fachliche Einheit. Jede Unterhaltung, jede
Quelle und jede Aktion wird einem klaren Kontext zugeordnet.
### 6.1 Zentrale Entitäten
-----------------------------------------------------------------------
Entität Zweck und mögliche Attribute
----------------------------------- -----------------------------------
`users` Externe Identität, Anzeigename,
Status
`teams` Unternehmensbereiche und Gruppen;
Referenz auf Gateway-API-Key und
Munin-Workspace, Limits
`team_memberships` Benutzer, Team, Rolle
`workspaces` Name, Beschreibung, genau ein Team,
Referenz auf den Munin-Key,
Hugin-Projekt, Einstellungen
`models` Modellname, Endpunkt, Fähigkeiten,
Zuordnung zu Modellklassen
`hugin_subscriptions` Workspace, Paket, Kanal oder
Versionsbereich
`hugin_versions` Workspace, Paket, festgeschriebene
Version, Prüfsumme, Art, Risiko,
Inhalt im Quellformat
`workspace_memberships` Zugriff und Rolle pro Workspace
`data_sources` Typ, Konfiguration, Status,
Workspace-Zuordnung
`source_credentials` Referenz auf extern verwaltete
Zugangsdaten
`tool_definitions` Tool-Name, Beschreibung, Schema,
Hash der Definition und
Einstufungsstatus
`tool_policies` Erlaubnis, Risikoklasse,
Freigaberegeln und erforderliche
Freigabestufe
`chat_sessions` Workspace, Titel,
Modellkonfiguration
`messages` Rolle, Inhalt, Reihenfolge und
Metadaten
`task_runs` Status, Ausführungszustand,
Fortschritt, Fehler, Lease,
Heartbeat, `parent_run_id` (für
Subagenten) und verwendete
Hugin-Versionen
`run_events` Streaming-Ereignisse pro Run mit
fortlaufender Sequenznummer
`task_steps` Einzelne Schritte eines Tasks,
Reihenfolge und Status
`tool_invocations` Tool, Parameterreferenz, Ergebnis
und Ausführungsstatus
`approval_requests` Aktion, Antragsteller, Entscheider
und Entscheidung
`audit_events` Sicherheitsrelevante und fachlich
wichtige Ereignisse
-----------------------------------------------------------------------
Dies ist ein logisches Modell, noch kein vollständiges SQL-Schema. Die
Umsetzung sollte PostgreSQL und versionierte Alembic-Migrationen
verwenden.
### 6.2 Modellierungsregeln
- Jede Workspace-abhängige Entität hat einen nachvollziehbaren
Workspace-Bezug.
- Quellenzugriffe werden serverseitig gegen Benutzer, Workspace und
Policy geprüft.
- IDs allein sind keine Berechtigung; fremde IDs dürfen nicht zum
Zugriff auf fremde Daten führen.
- Zugangsdaten werden in einem geeigneten Secret Store verwaltet.
Umgesetzt: API-Keys und Tokens der Quellen werden im UI eingegeben
und verschlüsselt (Fernet, Master-Key aus `AIW_SECRET_KEY`) in
PostgreSQL gespeichert; angezeigt werden nur die letzten vier
Zeichen. Der Master-Key selbst gehört in den Secret Store der
Plattform (z. B. OpenShift Secret).
PostgreSQL hält möglichst nur Referenzen und erforderliche
Metadaten.
- Nachrichten, Tool-Ausführungen, Tasks und Freigaben besitzen
eindeutige IDs.
- Zeitstempel, Statusübergänge und relevante Audit-Ereignisse werden
persistent gespeichert.
- Sensible Tool-Parameter und Ergebnisse werden nicht unkontrolliert
in Logs kopiert.
- Größere Uploads werden in einer Dateiablage/Object Storage gehalten;
PostgreSQL speichert Metadaten und Referenzen.
- Aufbewahrungs- und Löschregeln für Nachrichten, Dateien, Ergebnisse
und Audit-Daten müssen konfigurierbar sein.
- Als zusätzliche Absicherung der Mandantentrennung kann PostgreSQL
Row-Level Security auf Workspace-Ebene eingesetzt werden; die
primäre Prüfung bleibt in der Anwendung.
### 6.3 Workspace-Regeln
- Ein Workspace gehört genau einem Team.
- Ein Workspace kann mehrere Datenquellen und Chat-Sessions besitzen.
- Eine Session gehört genau zu einem Workspace.
- Tool-Aufrufe gehören zu einem Run und einer konkreten Quelle.
- Berechtigungen werden für jede Operation erneut geprüft.
- Der Orchestrator erhält nur die Quellen und Tools, die für den
konkreten Nutzer und Workspace freigegeben sind.
- Ein Wechsel des Workspace muss den vorherigen Kontext vollständig
ablösen.
------------------------------------------------------------------------
## 7. MCP-Architektur und Connectoren
MCP wird nicht direkt in Chat-Routen eingebaut, sondern über einen
eigenen **MCP Client Manager** angesprochen.
Dieser verwaltet Verbindungen, entdeckt Tools und Ressourcen, ordnet sie
einer Datenquelle zu und führt freigegebene Aufrufe aus.
### 7.1 Unterstützte Betriebsarten
#### A. Zentrale MCP-Server im Firmennetz
Der MCP-Server läuft als zentraler Dienst. Die Anwendung verbindet sich
über ein vom Server unterstütztes MCP-Transportprotokoll, beispielsweise
Streamable HTTP.
Ablauf:
`FastAPI/Worker → MCP Client → MCP Server → Unternehmenssystem`
#### B. Lokal gestartete MCP-Prozesse (nicht im MVP)
Ein MCP-Server läuft als kontrollierter Prozess innerhalb der Server-
oder Worker-Laufzeit und wird typischerweise über stdin/stdout
angebunden.
**Entscheidung:** Im MVP nicht unterstützt. Gründe: Prozesse halten
Zustand und binden sich an einen Pod, gemeinsam genutzte Prozesse teilen
Zugangsdaten über Workspaces hinweg, und Laufzeit-Installationen über
`npx`/`uvx` sind ein Supply-Chain-Risiko und benötigen Internetzugang.
Werden stdio-Server benötigt, werden sie als eigenes Deployment mit
Streamable-HTTP-Transport betrieben und wie Betriebsart A angebunden.
Ablauf:
`FastAPI/Worker → MCP Client → erlaubter lokaler Prozess → Unternehmenssystem`
**Begriffsabgrenzung:** „Lokal" bedeutet in diesem Konzept zunächst
lokal zur kontrollierten Server-/Worker-Laufzeit, nicht auf dem
Arbeitsplatzrechner des Nutzers. MCP-Prozesse auf Nutzergeräten würden
eine separate Agenten- oder Verbindungsarchitektur erfordern.
### 7.2 Anforderungen an den MCP Client Manager
- Verbindungstest und Lifecycle-Management
- Discovery von Tools und Ressourcen
- Zuordnung zu Quellen und Workspaces
- Einheitliche Fehlerbehandlung und Timeouts
- Begrenzung paralleler Aufrufe
- Überwachung von Verbindungsabbrüchen
- Sichere Authentifizierung und Secret-Verwaltung
- Prüfung jeder Aktion vor Ausführung
- Protokollierung von Aufrufen, Ergebnissen und Fehlern
- Validierung von Tool-Argumenten anhand des deklarierten Schemas
- Begrenzung von Antwortgrößen und Laufzeiten
- Pinning von Tool-Definitionen per Hash über Name, Beschreibung und
Schema; eine geänderte Definition setzt das Tool auf „nicht
eingestuft“ zurück
- Nicht eingestufte Tools werden dem Modell nicht angeboten (`DENY`)
- MCP-Annotations wie `readOnlyHint` werden höchstens als Vorschlag
für die Einstufung angezeigt, nie automatisch übernommen
- Serverseitig gesetzte Argumente, die im Tool-Schema für das Modell
ausgeblendet und bei jedem Aufruf von der Anwendung überschrieben
werden, falls ein MCP-Server den Kontext über Parameter statt über
den Zugang bestimmt (bei Munin nicht nötig, dort bestimmt der Key
das Projekt)
- Auswahl der für einen Workspace aktiven Tools, damit das Modell nicht
mit zu vielen Tools arbeitet
**Umsetzung:** Plattform-Admins registrieren Server unter
*Administration → MCP-Server* (Kurzname, URL, optional Bearer-Token,
verschlüsselt). Erlaubt sind nur `https` zu Hosts aus
`AIW_MCP_ALLOWED_HOSTS`; `http://localhost` nur mit
`AIW_MCP_ALLOW_LOCAL` für die Entwicklung. *Tools abrufen* speichert die
Tools als `<kurzname>__<tool>` mit Schema und Annotations; Schemas, die
oben kein einfaches Objekt sind, werden übersprungen. Ein Run nutzt den
gespeicherten Stand und ruft den Server erst beim Tool-Aufruf an; jeder
Aufruf öffnet eine eigene Verbindung (offizielles SDK `mcp`) mit
Timeout. Argumente werden vorher gegen das Schema geprüft. Fehler des
Servers oder Verbindungsabbrüche werden zu einem Tool-Ergebnis, der Run
läuft weiter. Workspace-Admins schalten Server frei und können ein
eigenes Token setzen (z. B. Munin-Key je Workspace). Annotations zeigt
die Admin-Seite nur als Vorschlag; *Vorschläge übernehmen* lässt
MCP-Tools aus. MCP-Tools mit „Freigabe nötig“ laufen über einen Antrag,
der die geprüften Argumente zeigt; weil MCP-Aufrufe nicht idempotent
sind, wird ein abgebrochener Aufruf nie automatisch wiederholt. Noch
offen: serverseitig gesetzte Argumente, Begrenzung paralleler Aufrufe
und Ressourcen.
Tools, bei denen das Risiko vom Argument abhängt (z. B. `query(sql)`
oder `run_command`), werden im MVP nicht freigegeben oder nur mit einem
technischen Account angebunden, der im Zielsystem ausschließlich lesen
darf.
### 7.3 Sicherheitsanforderungen
Die Anwendung darf nicht beliebige MCP-Endpunkte oder Prozesse starten,
die Nutzer frei eingeben.
Erforderlich sind:
- Vertrauenswürdige Serverregistrierungen
- Allowlist für erlaubte Hosts, Ports und Netzwerkziele
- Schutz vor SSRF und unzulässigem Zugriff auf interne oder
administrative Netze
- Allowlist für ausführbare Programme und zulässige Argumente bei
lokalen Prozessen
- Kontrollierte Umgebungsvariablen und Prozessrechte
- Begrenzung von CPU, Speicher, Laufzeit und parallelen Prozessen
- Keine Shell-Ausführung durch unkontrolliertes Zusammensetzen von
Strings
- Saubere Trennung von Konfiguration und Secrets
- Sichere Behandlung von nicht vertrauenswürdigen Tool-Ausgaben
### 7.4 Einheitliches Connector-Modell
Die UI und der Orchestrator sollen nicht wissen müssen, ob eine Quelle
über MCP oder eine native API angebunden ist.
Beispiel eines internen Architekturinterfaces:
``` python
from typing import Any, Protocol
class Connector(Protocol):
async def test_connection(self) -> dict[str, Any]:
...
async def discover_capabilities(self) -> list[dict[str, Any]]:
...
async def execute(
self,
tool_name: str,
arguments: dict[str, Any],
context: dict[str, Any],
) -> dict[str, Any]:
...
```
Dies ist ein internes Beispielinterface, kein offizielles
MCP-SDK-Interface.
Der `context` enthält mindestens Nutzer, Workspace, Team und Run. So
kann später eine Nutzer-Delegation ergänzt werden, ohne das Interface
zu ändern.
Implementierungen im MVP:
- `RemoteMCPConnector` für zentrale MCP-Server
- `MuninMemoryConnector` (auf Basis von `RemoteMCPConnector`)
- `GitConnector` für lesenden Zugriff auf beliebige Git-Server
- `PullRequestProvider` mit `BitbucketDataCenterProvider`
- `UploadConnector` mit DuckDB
Hugin wird nicht als Connector angebunden, sondern über einen eigenen
`HuginClient` abgeglichen (siehe 7.9).
Später möglich: `DatabaseConnector`, weitere `PullRequestProvider`
(GitLab, GitHub, Gitea), `LocalProcessMCPConnector`.
Umgesetzt (Phase 4, Testdatenbank): `PostgresConnector` als Quellenart
`postgres`. Hosts nur aus `AIW_DB_ALLOWED_HOSTS`, außerhalb von
localhost nur mit TLS. Abfragen laufen mit
`default_transaction_read_only`, in einer schreibgeschützten Transaktion,
die immer zurückgerollt wird, über einen serverseitigen Cursor (genau
eine Anweisung, beginnend mit SELECT, WITH, TABLE oder VALUES), mit
`statement_timeout`, Abbruch vom Client als zweiter Sicherung und
Zeilenlimit. Empfohlen ist eine Rolle nur mit SELECT; der
Verbindungstest weist auf Schreibrechte hin. Tools `db_list_tables`,
`db_describe_table`, `db_query` (Risikoklasse read).
Ein nativer Connector kann eine REST-/SDK-API verwenden; ein
MCP-Connector verwendet einen MCP-Client. Beide müssen dieselben
übergeordneten Sicherheits- und Auditregeln einhalten.
### 7.5 Git-Connector und Pull Requests
Lesen und Schreiben werden getrennt, damit jeder Git-Server unterstützt
werden kann.
**Lesen (alle Git-Server):**
- Der Worker klont das Repository per HTTPS oder SSH mit dem
technischen Account in ein temporäres Arbeitsverzeichnis und hält
einen Cache pro Repository.
- Tools: `list_dir`, `read_file`, `search`, `find_files`, `log`,
`blame`, `diff`, `show_commit` (Details zu `search` siehe 7.8).
- Limits für Repository-Größe, Dateigröße, Suchergebnisse und
Speicherplatz.
- **Umsetzung:** Der Cache ist ein Bare-Klon pro Quelle; gelesen wird
ausschließlich mit Git-Plumbing (`ls-tree`, `cat-file`, `grep`,
`log`, `blame`, `show`), ohne Arbeitsverzeichnis. Damit laufen keine
Hooks, Filter oder Checkout-Mechanismen aus dem Repository. Zu
Beginn eines Runs wird einmal aktualisiert; alle Tools des Runs
lesen denselben festgehaltenen Commit, der am Run gespeichert wird.
Die Tools heißen `git_list_dir`, `git_read_file` usw.; Commits nimmt
das Modell nur als SHA entgegen, Pfade nur relativ und ohne `..`.
**Schreiben (Branch und Pull Request):**
- Das Modell reicht Änderungen über das Tool `propose_change` ein
(siehe 10.7). Sie entstehen als Commit auf einem Branch
`ai/<task-id>` relativ zu einem festen Basis-Commit.
- Der Freigabeantrag enthält den echten Diff und den Basis-Commit.
Hat sich der Zielbranch seitdem so verändert, dass der Patch nicht
mehr sauber anwendbar ist, wird die Freigabe ungültig.
- Nach Freigabe wird der Branch gepusht und, sofern der Anbieter es
unterstützt, ein Pull Request erstellt. Der Merge erfolgt im
normalen Review-Prozess des Teams.
- Bei Git-Servern ohne Pull-Request-Funktion wird nur der Branch
gepusht.
- **Umsetzung:** `propose_change` nimmt je Datei den vollständigen
Inhalt, gezielte Ersetzungen (Text muss genau einmal vorkommen)
oder eine Löschung. Der Commit entsteht über einen temporären Index
im Bare-Klon, ohne Arbeitsverzeichnis und ohne Branch; Autor ist
der technische Account, der Zeitpunkt ist fest, damit sich derselbe
Commit nach einem Cache-Verlust exakt nachbauen lässt. Der Branch
heißt `ai/<task>-<commit>` (eindeutig je Vorschlag). Vor dem Push
wird geprüft, ob der Basis-Commit noch im Zielbranch enthalten ist
und sich die Änderung konfliktfrei auf dessen aktuellen Stand
anwenden lässt (`git merge-tree`); ein vorhandener Branch wird nie
überschrieben (`--force-with-lease` mit leerem Erwartungswert).
Existiert der Branch bereits mit genau diesem Commit oder der Pull
Request bereits, wird nichts doppelt angelegt. Der Pull-Request-
Anbieter wird je Quelle eingestellt.
**Überarbeitet (Oktober 2026): Chat = Branch.** Freigaben je Änderung
waren für echte Coding-Aufgaben zu kleinteilig. Der Ablauf folgt jetzt
der üblichen Arbeitsweise der Teams: in einer Session arbeiten und am
Ende einen Pull Request stellen. `propose_change` entfällt.
- Jeder Chat hat je Git-Quelle einen Branch `ai/c<chat>-<titel>`, der
beim ersten Commit auf dem aktuellen Stand des Ziel-Branches
entsteht. Die KI committet mit `commit_change` frei darauf
(`write_internal`: die Commits liegen nur im Klon der Plattform,
festgehalten über eine lokale Referenz). Die lesenden Tools sehen
danach den Stand des Branches.
- Nach außen wirkt nur ein Klick eines Workspace-Mitglieds: *Branch
pushen*, *Pull Request erstellen* (standardmäßig als Entwurf) bzw.
*Änderungen übertragen* in einen offenen Pull Request. Die KI kann
weder pushen noch Pull Requests anlegen. Die eigentliche Prüfung ist
das Review im Git-Server.
- Gepusht wird ohne Überschreiben: neuer Branch nur, wenn es ihn noch
nicht gibt, sonst nur bei unverändertem Stand auf dem Server (Lease
mit dem zuletzt übertragenen Commit).
- Je Commit speichert die Plattform die geprüften Änderungen und den
Zeitpunkt. Geht der Klon verloren, holt sie gepushte Branches vom
Server oder baut die Commits exakt nach.
- Rückkanal: Der Worker fragt offene Pull Requests regelmäßig ab
(Status, Entwurf, Reviewer, Kommentare) und benachrichtigt bei neuen
Kommentaren, Merge und Ablehnung. Kommentare liest die KI mit
`git_pr_comments` (`read`); antworten kann sie in Bitbucket nicht.
Nach Merge oder Ablehnung ist der Branch geschlossen, der nächste
Commit beginnt einen neuen.
- Freigaben bleiben für Tools, die sie brauchen (z. B. Abfragen mit
Freigabe-Regel, MCP-Tools). Entscheiden dürfen Workspace-Admins und
die Rolle *Freigeber*.
**Übersicht „Repository“ (umgesetzt 25.10.2026):**
- Eigener Bereich in der Seitenleiste, sobald ein Workspace eine
Git-Quelle hat; bei mehreren Quellen Auswahl oben. Nur lesend, keine
neuen Rechte: sehen dürfen alle Mitglieder des Workspace.
- *Neu*: Commits des Ziel-Branches (first-parent) nach Tagen, mit
Autor und geänderten Dateien; Filter nach Zeitraum, Autor und Pfad.
„Seit deinem letzten Besuch“ je Person und Quelle (`repo_visits`:
zuletzt gesehener Commit). Commit-Ansicht mit Diff in der
Darstellung von *Änderungen*.
- *Branches*: alle Branches des Servers mit Vorsprung/Rückstand
gegenüber dem Ziel-Branch; Chat-Branches verweisen auf Chat und
PR-Status.
- Chats mit Bezug: neue Commits zusammenfassen (Commit-Bereich als
Auftrag), Commit oder Datei erklären, auf einem bestehenden Branch
arbeiten. Im letzten Fall merkt sich der Chat den Ausgangs-Branch
(`chat_sessions.git_base`); die Tools lesen ihn, der Chat-Branch
zweigt davon ab und hat ihn als Ziel für Abgleich und Pull Request.
- Daten aus dem Klon der Plattform; beim Öffnen höchstens einmal pro
Minute aktualisiert (alle Branches nach `refs/remotes/origin/*`),
*Aktualisieren* sofort. CI-Status wird bewusst nicht angezeigt.
- *Pull Requests*: offene PRs aus Bitbucket Data Center (Autor,
Branches, Reviewer, Kommentaranzahl), Diff gegenüber dem
gemeinsamen Stand aus dem Klon; *Im Chat reviewen* startet einen
Chat auf dem PR-Branch mit dem Commit-Bereich als Auftrag (Review
nach Schwere, ohne Änderungen). *Dateien*: Baum und Dateien eines
beliebigen Branches mit Zeilennummern und Verlauf.
**Andere Git-Server (umgesetzt 25.10.2026):**
- Lesen, Commits und Push gehen mit jedem Git-Server über HTTPS.
Anmeldung je Quelle: ohne Nutzername Bearer (Bitbucket Data
Center), mit Nutzername Basic mit dem Token als Passwort (Gitea,
Forgejo, GitLab, GitHub, `git-http-backend`). Der Header wird per
Umgebung übergeben, nie in der URL oder in einer Datei.
- Pull Requests aus der Plattform nur mit Bitbucket Data Center;
sonst *Branch pushen*, und den PR legt ein Mensch im Git-Server an.
- Nicht unterstützt: SSH. Ausbau (vorgemerkt): PR-Anbieter
Gitea/Forgejo (gemeinsame API), SSH mit festem `known_hosts`.
**Bitbucket Data Center:**
- Pull Requests über REST API 1.0
(`/rest/api/1.0/projects/{key}/repos/{slug}/pull-requests`).
- Authentifizierung über HTTP Access Tokens auf Repository- oder
Projektebene.
- Branch Permissions in Bitbucket erlauben dem Token nur Pushes auf
`ai/*`. Damit setzt das Quellsystem selbst durch, dass nie direkt
auf Zielbranches geschrieben wird.
- CI-Pipelines starten für `ai/*` nicht automatisch mit Secrets (siehe
7.8).
- Die interne CA muss im Container-Image hinterlegt sein; der
Netzwerkzugang von OpenShift zu Bitbucket (HTTPS, gegebenenfalls
SSH) muss freigeschaltet sein.
### 7.6 Agentic Memory mit Munin
Munin wird als zentraler MCP-Server angebunden und dient der KI als
Gedächtnis über Sessions hinweg.
- **Zuordnung:** Team → Munin-Workspace, AI-Workspace → Munin-Projekt.
- **Trennung über den Key:** In Munin bestimmt der API-Key Workspace
und Projekt; es gibt keinen Projekt-Parameter. Alle Projekte nutzen
denselben Endpunkt `…/mcp` (Streamable HTTP). Jeder AI-Workspace hat
daher einen eigenen Munin-Key, der im Secret Store liegt; das Modell
sieht ihn nie. Die Abschottung der Projekte setzt Munin strukturell
durch (eigene Datenbank je Workspace, Zugriffe auf die Projekt-ID
beschränkt, fremde Projekte antworten mit 404).
- **Key und Autorschaft:** Der Key erhält die Rolle `write` und einen
Namen wie `ai-workspace/<workspace>`. Munin vermerkt diesen Namen
als Autor an jedem Eintrag; welcher Nutzer den Run ausgelöst hat,
steht im Audit der Plattform. Workspaces, deren Einträge niemand
durchsieht, erhalten einen Key mit Rolle `read`.
- **Einrichtung:** Munin bietet Projekte und Keys bisher nur über die
Weboberfläche an, nicht per API. Im MVP legt ein Admin des
Munin-Workspace das Projekt und den Key an; der Workspace-Admin
hinterlegt den Key in der Plattform. Eine Admin-API in Munin zur
automatischen Einrichtung ist eine spätere Option.
- **Werkzeuge:** `recall`, `get`, `list`, `related` (lesend) und
`remember` (schreibend). `forget` wird der KI nicht angeboten, obwohl
die Rolle `write` es erlauben würde.
- **Anleitung:** Munin liefert beim Verbindungsaufbau eine Anleitung
(`instructions`), die viele Clients kaum beachten. Die Plattform
übernimmt sie in den System-Prompt, ergänzt um den Skill
`pub-munin-nutzen` aus Hugin. Die Anbindung `pub-munin-anbindung`
aus Hugin wird auf diesen Connector abgebildet.
- **Antworten von Munin, die weitergereicht werden:**
`judgment_required` mit `candidates` (ähnlicher Eintrag vorhanden)
oder bei kuratierten Einträgen, Konflikte bei `expected_version`,
Einträge mit `stale: true` und die Meldung bei erschöpftem
Schreibbudget (1.000 Schreibvorgänge pro Stunde und Projekt). Sie
gehen als Tool-Ergebnis an das Modell, nicht als Fehler.
- **Prompt Injection:** Persistierte Inhalte können Anweisungen über
Sessions hinweg weitertragen. Munin setzt dagegen auf
Nachvollziehbarkeit (Herkunft `agent`/`human`, Autor, Protokoll,
Kennzeichnung „kuratiert“). Überschreibt die KI einen kuratierten
Eintrag (`override_curated` mit Begründung), markiert Munin ihn zur
Prüfung durch einen Menschen.
- **Transparenz und Löschen:** Einträge sind für Workspace-Mitglieder
in der Plattform sichtbar. Gelöscht wird nur durch Menschen, über die
Plattform-UI (ruft `forget` auf) oder direkt in Munin. Gelöschte
Einträge liegen 30 Tage im Munin-Papierkorb und können dort
wiederhergestellt werden.
- **Workspace löschen:** Der Munin-Key wird aus dem Secret Store
entfernt, und die Plattform weist den Admin darauf hin, Projekt und
Key in Munin zu löschen oder zu widerrufen.
Umgesetzt: MCP-Server haben eine Art (allgemein oder Gedächtnis). Die
`instructions` des Servers werden bei der Discovery gespeichert und in
den System-Prompt übernommen, solange seine Tools angeboten werden.
Für Gedächtnis-Server gibt es eine Einstufungsempfehlung (`forget`
destructive, also nie für die KI) und im Workspace die Ansicht
*Gedächtnis* (list, recall, get; forget nur für Workspace-Admins,
auditiert). Argumentnamen werden aus dem entdeckten Schema abgeleitet.
Offen: Abgleich mit dem echten Munin, Skill `pub-munin-nutzen` aus Hugin
(mit der Hugin-Anbindung), Hinweis beim Löschen eines Workspace (das
Löschen von Workspaces gibt es noch nicht).
### 7.7 Uploads und Datenanalyse mit DuckDB
- Uploads (CSV, JSON, Parquet, Logs in strukturierbarer Form) liegen
in der Dateiablage und werden pro Workspace als DuckDB-Tabellen
bereitgestellt.
- Die KI erhält Tools wie `list_tables`, `describe_table` und
`query(sql)`.
- `query` ist ausschließlich lesend: Die Verbindung wird schreibgeschützt
geöffnet, Erweiterungen und Dateizugriffe außerhalb des Workspace
sind deaktiviert (`enable_external_access = false`), dazu kommen
Limits für Laufzeit, Speicher und Ergebniszeilen.
- Damit sind Analysen großer Dateien möglich, ohne freie
Code-Ausführung einzuführen.
Umgesetzt: Jede hochgeladene Datei wird beim Upload in eine eigene
DuckDB-Datei (`upload_dir/<workspace>/<upload>.duckdb`) umgewandelt; die
Originaldatei wird verworfen. Abfragen laufen in einer
In-Memory-Datenbank, an die nur die Dateien des Workspace
schreibgeschützt angehängt sind, danach `enable_external_access = false`
und `lock_configuration = true`; Erweiterungen werden weder installiert
noch geladen. Zugelassen ist genau eine SELECT-Anweisung; Zeitlimit per
Interrupt, Speicher- und Zeilenlimit über Einstellungen. Hochladen dürfen
alle Mitglieder, löschen die hochladende Person oder Workspace-Admins.
### 7.7a Abgeglichene Ordner (lokale Dokumente)
Ziel: Dokumente vom Rechner einer Person, die sich regelmäßig ändern
(Office, PDF, Bilder, Textformate), ohne Agent auf dem Rechner.
- **Abgleich im Browser:** Die Seite des Ordners liest den lokalen
Ordner (File System Access API mit gemerktem Handle, sonst
`webkitdirectory`), vergleicht Größe und Änderungszeit mit dem Stand
der Plattform und lädt nur Neues und Geändertes hoch; fehlende
Dateien werden entfernt. Ohne offene Seite gibt es keinen Abgleich.
- **Auslese:** Textformate dekodiert die Plattform selbst. Office, PDF
und Bilder schickt der Worker als Base64 an einen zentralen
MCP-Server der Rolle `documents` (Streamable HTTP; lokale
stdio-Server sind vom Server aus nicht erreichbar, → 7.1).
Tool und Parameter legt der Plattform-Admin fest. Die Rohdatei liegt
nur bis zur Auslese in der Dateiablage; gespeichert wird der Text
(begrenzt), mit Volltextindex (`german`). Gleicher Inhalt
(SHA-256) wird nicht erneut ausgelesen.
- **Sichtbarkeit je Ordner:** *nur ich* oder *ganzer Workspace*
(mit Bestätigung). Weil Chats für alle Mitglieder sichtbar sind,
nutzt ein Run private Ordner nur, wenn die Person ihn in ihrem
eigenen Chat auslöst; die Antwort bleibt für Mitglieder sichtbar,
darauf weist die Oberfläche hin. Private Chats sind Ausbau.
- **Tools:** `docs_list`, `docs_search`, `docs_read`, lesend und als
Fremdinhalt markiert (→ 8.5). Der Text zählt aufs
Speicherkontingent des Workspace.
### 7.8 Skripte und Code-Ausführung
Die Plattform führt im MVP keinen vom Modell erzeugten Code aus. Das
Modell kann ausschließlich registrierte und eingestufte Tools aufrufen;
ein Ausführungs-Tool existiert nicht.
**Verhalten bei Ausführungswünschen:**
-----------------------------------------------------------------------
Das Modell will … Ergebnis
----------------------------------- -----------------------------------
ein Skript schreiben, um etwas zu Das Skript erscheint nur als Text
finden oder auszuwerten im Chat; es wird nichts ausgeführt
ein nicht vorhandenes Tool aufrufen Die Anwendung weist den Aufruf ab,
(z. B. `run_python`, `bash`) gibt eine Fehlermeldung als
Tool-Ergebnis zurück und
protokolliert den Versuch im Audit
ein Skript ins Repository legen Nur über `propose_change` mit
Freigabe und Pull Request; das
Skript wird Code im Repository,
nicht von der Plattform ausgeführt
-----------------------------------------------------------------------
Der System-Prompt weist das Modell darauf hin, dass keine
Code-Ausführung verfügbar ist, und nennt die stattdessen nutzbaren Tools.
**Sichere Alternativen statt Skripten:** Der typische Grund für Skripte
ist Effizienz beim Suchen, Zählen und Auswerten. Dafür werden
ausdrucksstarke, aber eingeschränkte Tools bereitgestellt:
- `search` mit Regex, Pfad-Glob, Dateityp-Filter, Kontextzeilen und
Ergebnislimit (serverseitig über `git grep` auf dem festgehaltenen
Commit, ohne Shell; kein zusätzliches Werkzeug nötig)
- `find_files` mit Glob und Größenfilter
- `log` und `blame` mit Filtern nach Pfad, Autor und Zeitraum
- DuckDB-SQL für Aggregation und Analyse (siehe 7.7)
Grundsatz: eingeschränkte Abfragesprachen (Regex, Glob, SQL) statt
freiem Code.
**Ausführung über CI-Pipelines:** Ein gepushter Branch `ai/*` kann
automatisch eine CI-Pipeline auslösen und damit vom Modell geschriebenen
Code ausführen, häufig mit Zugriff auf CI-Secrets. Für `ai/*`-Branches
werden daher keine Pipelines mit Secrets automatisch gestartet; sie
laufen ohne Secrets oder nur nach manueller Auslösung. Dies ist in
Bitbucket bzw. der CI zu konfigurieren.
**Ausbaustufen nach dem MVP:**
1. **Vorhandene CI nutzen (bevorzugt):** Nach Freigabe wird ein
`ai/*`-Branch gepusht, die CI führt Tests in ihrer bestehenden
Umgebung ohne Secrets aus, und die KI liest das Ergebnis über die
Build-Status-API von Bitbucket. Es entsteht keine neue
Ausführungsumgebung.
2. **Eigene Sandbox:** Kurzlebiger Container pro Ausführung, z. B. mit
OpenShift Sandboxed Containers (Kata); kein Netzwerk, nur lesbare
Kopie des Repositorys, keine Secrets, Limits für CPU, Speicher und
Laufzeit, Ergebnis nur als Text. Abhängigkeiten ausschließlich über
einen internen Mirror. Dafür wird eine eigene Risikoklasse `execute`
eingeführt.
### 7.9 Hugin: Regeln, Skills, Befehle, Subagenten und MCP-Anbindungen
Hugin ist das zentrale Register für alles, was das Verhalten von
KI-Agenten steuert (siehe Hugin-Konzept). Für diese Plattform ist Hugin
eine **Konfigurationsquelle**, keine Datenquelle: Hugin-Inhalte stehen
als Anweisungen mit hohem Vertrauen im Kontext oder bestimmen, welche
Fähigkeiten angeboten werden.
**Was Hugin bereits leistet:** Prüfung im Vier-Augen-Prinzip nach
Risiko (`text`, `tools`, `scripts`, `permissions`), unveränderliche
Versionen mit Prüfsummen, Audit mit Namen sowie einen Linter unter
anderem für Prompt Injection, unsichtbare Unicode-Zeichen und
Geheimnisse. Die Plattform verlässt sich für die Prüfung der Inhalte
auf Hugin und stellt selbst sicher, dass nur geprüfte, festgeschriebene
Versionen verwendet werden und dass sie keine Rechte verleihen.
#### Zuordnung
-----------------------------------------------------------------------
Hugin Munin AI Workspace
-------------------- -------------------- -----------------------------
Tenant Workspace Team
Projekt Projekt Workspace
-----------------------------------------------------------------------
Die Plattform nutzt eine Hugin-Instanz (Host, vom Plattform-Admin
gepflegt). Jeder Workspace hat einen eigenen Integrations-Key (`hi_…`),
den der Workspace-Admin einträgt; ein Workspace gehört einem Team, und
der Key gilt für den Tenant des Teams (siehe Umsetzungsstand).
#### Anbindung
Die Plattform nutzt den Lieferweg für Integrationen
(`/api/v1/delivery/`). Weil dieser bisher nur für Claude Code und
OpenCode übersetzte Bundles liefert, wird Hugin um zwei Endpunkte
erweitert:
- **Auflösen:** Abos, Pflichtpakete und Kanäle zu konkreten Versionen
mit Prüfsumme, Art und Risiko auflösen, ohne zu übersetzen.
- **Quellformat:** eine freigegebene Version im Quellformat
(`hugin.yaml` und Inhaltsdateien) als ZIP für Integrations-Keys.
Die Plattform liest das Quellformat mit `hugin_core` (reines
Python-Paket ohne FastAPI- oder DB-Abhängigkeit, in fester Version
eingebunden). Die Erweiterung erfolgt im Hugin-Projekt; dort wird die
Plattform als neue Art von Abnehmer neben Claude Code und OpenCode
aufgenommen.
#### Auswahl, Festschreiben und Aktualisierung
- Der Workspace-Admin wählt in den Workspace-Einstellungen Pakete aus
dem Hugin-Katalog (Kanal oder Versionsbereich). Eine `.hugin.yaml`
aus dem verbundenen Repository kann als Vorschlag importiert werden.
- Pflichtpakete aus Hugin gelten immer und können nicht abgewählt
werden.
- Die aufgelösten Versionen werden mit Prüfsumme im Workspace
festgeschrieben (wie `hugin.lock`). Beim Laden wird die Prüfsumme
geprüft.
- Neue Versionen werden nicht automatisch übernommen. Die UI zeigt
„Update verfügbar“; ein Workspace-Admin übernimmt sie. Pflichtpakete
folgen den Vorgaben aus Hugin.
- Jeder Run speichert, welche Paketversionen er verwendet hat.
- Nach dem Abgleich meldet die Plattform die Nutzung an Hugin
(`POST /usage`, Client-Name `ai-workspace/<workspace>`).
#### Abbildung der Paketarten
-----------------------------------------------------------------------
Art Abbildung auf der Plattform
----------------------------------- -----------------------------------
`rules` Teil des System-Prompts, nach den
Sicherheitsregeln der Plattform;
sie können diese nicht aufheben
`skill` Nur Name und Beschreibung im
Kontext; Inhalt und Hilfsdateien
über die Tools `load_skill` und
`read_skill_file`. Skills mit
Risiko `scripts` werden im MVP
nicht angeboten (siehe 7.8)
`command` Slash-Befehle im Chat mit
benannten Argumenten (`{{name}}`)
und `$ARGUMENTS`. Befehle mit
Shell-Einbettung (`` !`befehl` ``)
werden nicht angeboten
`subagent` Kind-Run mit `AGENT.md` als
System-Prompt und eigenem Kontext.
`read` → lesende Tools; `write` →
zusätzlich `propose_change` mit
Freigabe; Subagenten mit `shell`
oder `web` werden nicht angeboten.
Die Modellklasse (`fast`,
`standard`, `thorough`, `inherit`)
wird über eine Admin-Konfiguration
auf Gateway-Modelle abgebildet
`mcp` Eintrag im Katalog; ein
Administrator aktiviert ihn. Die
URL muss auf der Allowlist stehen,
`{{env:NAME}}` wird aus dem Secret
Store des Teams befüllt, die Tools
sind bis zur Einstufung `DENY`.
`pub-munin-anbindung` wird auf den
eigenen Munin-Connector abgebildet
(7.6)
`hook` Nicht unterstützt
-----------------------------------------------------------------------
#### Sicherheitsregeln
- **Hugin-Inhalte verleihen keine Rechte.** Angaben wie
`allowed-tools`, `permission` oder Werkzeugzusätze in `extra` werden
ignoriert. Welche Tools verfügbar sind, entscheidet ausschließlich
die Policy Engine.
- **Subagenten haben nie mehr Rechte als der Eltern-Run.** Ihre
Tool-Aufrufe durchlaufen dieselbe Policy und dieselben Freigaben.
Tiefe (Standard: 1), Anzahl und Budget von Kind-Runs sind begrenzt.
- **Nur aus Hugin, nur mit Prüfsumme.** Gleichnamige Dateien im
verbundenen Repository (z. B. `.claude/skills/`) werden nie als
Skills oder Regeln verwendet; sie sind nicht vertrauenswürdiger
Repo-Inhalt.
- **Hugin-MCP-Endpunkt:** Im MVP erhält die KI nur `report_feedback`
(Rückmeldung zu einem Paket, z. B. „unklar“), mit Rate-Limit.
`search_packages` und `get_package` (einmalige Nutzung nicht
abonnierter Pakete) sind nicht freigegeben.
#### Umsetzungsstand (25.10.2026)
Umgesetzt: `rules`, `skill`, `command` und die Rückmeldung. Hugin hat
dafür im Lieferweg `POST /resolve`, `GET
/packages/{id}/versions/{version}/source` (ZIP mit Kopfzeile
`X-Hugin-Checksum`) und `POST /feedback` erhalten (Hugin-Konzept 14.7).
- **Host und Zugang:** Den Host pflegt der Plattform-Admin unter
*Administration → Hugin* (`hugin_host`, geprüft gegen
`AIW_MCP_ALLOWED_HOSTS`, Test über `/readyz` ohne Key;
`AIW_HUGIN_URL` füllt nur vor). Den Integrations-Key trägt der
Workspace-Admin in den Workspace-Einstellungen ein (`workspace_hugin`,
verschlüsselt wie die Gateway-Keys, siehe 8.1). Beim Speichern und
*Testen* meldet Hugins `/status` Tenant und Key-Name; ein Wechsel des
Tenants, der die Pflichtpakete bestimmt, kommt ins Audit-Log
(`hugin.tenant_changed`). Der Plattform-Admin sieht je Workspace
Zugang, Tenant und Paketzahl, aber keinen Key.
- **Auswahl und Festschreiben:** Reiter *Hugin* in den
Workspace-Einstellungen mit Katalog, Abgleichen (zeigt neu, „Update
verfügbar“, entfällt; ändert nichts) und Übernehmen. Übernehmen lädt
jede neue Version im Quellformat, vergleicht die Prüfsumme mit der
Auflösung und speichert ZIP, Prüfsumme aus Hugin und SHA-256 der
Kopie (`workspace_hugin_locks`, Größe bis
`AIW_HUGIN_MAX_PACKAGE_KB`). Danach `POST /usage` mit
`ai-workspace/<workspace-id>`.
- **Ablage:** Alles liegt in PostgreSQL (Kopie als `bytea`, nichts im
Dateisystem) und ist damit im Backup; Chats brauchen Hugin nicht.
Ältere Versionen werden beim Übernehmen ersetzt; Zurückgezogenes
zeigt erst der nächste Abgleich.
- **Laden:** Jeder Run lädt nur festgeschriebene Kopien, deren SHA-256
stimmt; eine veränderte Kopie wird übergangen und im Audit-Log
vermerkt (`hugin.checksum_mismatch`). Die Versionen stehen in
`config_versions["hugin"]` des Runs und unter der Antwort.
- **Abbildung:** Regeln nach den Anweisungen der Plattform im
System-Prompt, entschärft wie andere Texte. Skills mit Name und
Beschreibung im Prompt, Inhalt über `load_skill` und
`read_skill_file` (Art `hugin:skill`, Vorschlag `read`). Befehle
werden beim Senden ausgeschrieben: Die Nachricht zeigt die Eingabe,
an das Modell geht der ausgeschriebene Text (`Message.items`).
- **Nicht angeboten**, aber mit Grund festgeschrieben: Risiko
`scripts` oder `permissions`, Befehle mit `` !` ``, alle übrigen
Arten.
- **Rückmeldung:** Tool `hugin_feedback` (Art `hugin`, Vorschlag
`write_external`) über `POST /delivery/feedback` mit dem
Integrations-Key statt über den MCP-Endpunkt, der einen Projekt-Key
verlangt. Höchstens drei je Antwort.
Abweichung: Das Quellformat liest die Plattform mit der
Standardbibliothek (`zipfile`) statt mit `hugin_core`; sie braucht nur
die Inhaltsdateien, Version und Art kommen aus der Auflösung.
Ergänzt (25.10.2026):
- **Abgleich im Hintergrund:** Der Worker gleicht jeden Workspace mit
Hugin-Zugang alle `AIW_HUGIN_CHECK_HOURS` (Standard 24, 0 = aus) ab
und übernimmt nie etwas. Der Befund (Updates, veraltete Pakete, neue
oder entfallene Pflichtpakete, neue Hauptversionen) steht am Zugang
(`workspace_hugin.findings`), im Reiter *Hugin* und in der Übersicht
des Plattform-Admins. Ein neuer Befund geht per E-Mail an die
Workspace-Admins und an den Webhook des Workspace (`hugin.findings`);
derselbe Befund wird nicht erneut gemeldet. Die eigene, noch nicht
übernommene Auswahl zählt nicht als Befund.
- **Vorschlag aus `.hugin.yaml`:** *Aus .hugin.yaml* liest die Datei
aus dem Ziel-Branch jeder Git-Quelle (`packages`; `unsubscribed` und
`server` nur als Hinweis) und übernimmt gewählte Einträge in die
Auswahl. Die Datei bleibt unverändert und wirkt nicht von selbst.
- **Befehle im Chat:** Vorschläge beim Tippen von `/` mit Argumenten
und Beschreibung, Hinweis auf noch fehlende Argumente, Ablehnung
beim Senden, wenn Argumente fehlen, und unter der Frage der an die
KI gesendete Text.
#### Ausbau (vorgemerkt)
- `mcp`-Pakete aus Hugin auf MCP-Verbindungen des Workspace abbilden
(URL auf der Freigabeliste, `{{env:NAME}}` aus dem Workspace, Tools
bis zur Einstufung gesperrt); damit greift `pub-munin-anbindung`.
- `subagent` als Kind-Runs (Phase 5): `AGENT.md` als System-Prompt,
höchstens die Rechte des Eltern-Runs, begrenzte Tiefe und Budgets.
- Team-Admin-Rolle für Aufgaben über Workspaces hinweg (Mitglieder,
Kontingente), falls nötig.
------------------------------------------------------------------------
## 8. KI-Orchestrierung und OpenAI-kompatibles AI Gateway
### 8.1 Grundsatz
Das AI Gateway ist der zentrale Modellzugang. Die Anwendung kennt den
Gateway-Endpunkt, die freigegebenen Modelle und die unterstützten
Fähigkeiten, aber nicht zwingend die internen Anbieter hinter dem
Gateway.
Die Anwendung sollte einen internen Provider-Adapter besitzen, um
spätere Änderungen am Gateway oder die Unterstützung weiterer Provider
nicht über alle Module verteilen zu müssen.
**Zugang pro Team:** Jedes Team hat einen eigenen API-Key für das
Gateway. Der Adapter wählt den Key anhand des Teams, dem der Workspace
gehört. Der Team-Key hat Vorrang vor einem Key für alle Teams (z. B.
OpenAI in der Entwicklung).
**Verwaltung im UI:** Endpunkte, Modelle und API-Keys pflegt der
Plattform-Admin unter `/admin/models`. Abweichend vom allgemeinen
Secret-Store-Ansatz werden diese Keys im UI eingegeben und verschlüsselt
(Fernet) in PostgreSQL gespeichert; der Master-Key kommt aus
`AIW_SECRET_KEY` (mehrere kommagetrennt für einen Wechsel). Ein Key wird
nach dem Speichern nie wieder angezeigt, nur die letzten vier Zeichen;
er lässt sich ersetzen oder löschen, jede Änderung steht im Audit. Der
Workspace-Admin wählt das Modell seines Workspace aus den aktiven
Modellen; ohne Wahl gilt das Standardmodell der Plattform.
Kosten und Rate Limits werden damit vom Gateway pro Team erfasst.
- Der Worker begrenzt die Zahl gleichzeitiger Runs pro Team, damit
Agentenschleifen nicht das gesamte Gateway-Limit eines Teams
verbrauchen.
- Das Gateway erkennt Anfragen per Bearer Token (Team-Key) als Team
und leitet sie weiter; einzelne Nutzer sind dort nicht sichtbar. Die
Zuordnung zum Nutzer erfolgt ausschließlich im Audit der Anwendung.
**Schnittstelle:** Das Gateway unterstützt Tool Calling im
OpenAI-kompatiblen Format, Streaming und die Responses API.
**API-Format:** Die Plattform nutzt die **Responses API**, zustandslos:
- `store: false`; der vollständige Verlauf kommt bei jedem Aufruf aus
PostgreSQL. Kein `previous_response_id`, damit Wiederaufnahme nach
Freigaben und Worker-Neustarts nicht von Zustand beim Anbieter
abhängt.
- Reasoning-Elemente der Modellantwort werden mit dem Verlauf
gespeichert und unverändert zurückgegeben (verschlüsselt, sofern
unterstützt), damit das Modell über mehrere Tool-Schritte hinweg
folgerichtig weiterarbeitet.
- Ausschließlich eigene Function Tools. **Eingebaute Tools des
Anbieters** (z. B. Websuche, Code-Ausführung, Dateisuche, entfernte
MCP-Server) werden nicht aktiviert: Sie liefen außerhalb von Policy
Engine, Freigaben und Audit.
- Der Provider-Adapter kapselt das Format, sodass ein Wechsel auf Chat
Completions möglich bleibt, falls ein Modell die Responses API nicht
unterstützt.
**Entwicklung mit der OpenAI-API:** Solange das Gateway für die
Entwicklung nicht bereitsteht, spricht der Provider-Adapter direkt die
OpenAI-API an, zunächst mit dem Modell `gpt-6-luna`. Der Wechsel zum
Gateway ist reine Konfiguration (Basis-URL, Key, Modellliste). Damit das
gelingt:
- Es werden nur Funktionen genutzt, die auch das Gateway bietet
(Responses API wie oben beschrieben).
- Modelle werden in einer Tabelle `models` gepflegt (Name, Endpunkt,
Fähigkeiten wie Tool Calling, Streaming und Kontextgröße, Zuordnung
zu den Modellklassen). Zunächst zeigen alle Klassen auf
`gpt-6-luna`. Später werden die Modelle aus dem Gateway übernommen,
z. B. über `GET /v1/models`.
- Guardrail-Fehler gibt es dabei nicht. Für Tests wird das Verhalten
des Gateways mit einem Testdouble nachgebildet, das die
Guardrail-Fehlercodes liefert.
- Die Nutzung der OpenAI-API ist freigegeben. In der Entwicklung
werden trotzdem bevorzugt Test-Repositories und Testdaten verwendet,
damit Tests reproduzierbar sind und Fehlverhalten (z. B. unerwünschte
Pull Requests) keinen Schaden anrichtet. Ein eigenes OpenAI-Projekt
mit Ausgabenlimit wird empfohlen.
**Guardrails:** Das Gateway prüft Anfragen und Tool Calls mit eigenen
Guardrails, unter anderem auf Prompt Injection, und meldet Treffer als
Fehler mit einem spezifischen Code. Die Anwendung:
- bildet diese Codes auf den Run-Zustand `blocked_by_guardrail` ab,
- zeigt dem Nutzer den Grund verständlich an und protokolliert ihn im
Audit,
- wiederholt den Aufruf nicht automatisch.
Ob und wie das Gateway auch Tool-Ergebnisse prüft, liegt in der
Verantwortung des Gateways und ist nicht Teil dieses Konzepts. Die
Anwendung verlässt sich für ihre Sicherheitsgarantien nicht auf die
Guardrails (siehe 8.5).
### 8.2 Fähigkeiten der Provider-Abstraktion
- Chat Completions oder das vom Gateway unterstützte Chat-API-Format
- Streaming
- Tool-Calling und strukturierte Tool-Ergebnisse
- Modellkonfiguration, Tokenlimits und Timeouts
- Fehlerbehandlung, Rate Limits und Wiederholungslogik
- Erfassung von Modell- und Tokenmetadaten, soweit verfügbar
OpenAI-Kompatibilität garantiert nicht, dass jedes Modell Tool-Calling
oder Streaming identisch unterstützt. Die tatsächlich bereitgestellten
Modelle und deren Fähigkeiten müssen getestet werden.
### 8.3 Ablauf einer Chat-Anfrage
``` mermaid
sequenceDiagram
participant U as Nutzer
participant A as FastAPI
participant D as PostgreSQL
participant W as Worker
participant P as Policy Engine
participant L as AI Gateway
participant M as Connector / MCP Client
U->>A: Nachricht senden
A->>A: Workspace, Nutzer und Rechte prüfen
A->>D: Nachricht, Run und Job persistieren
A-->>U: SSE-Verbindung für Run öffnen
W->>D: Job beanspruchen (FOR UPDATE SKIP LOCKED)
W->>P: Erlaubte Quellen und Tools ermitteln
W->>L: Nachricht, Verlauf und erlaubte Tool-Schemas (Team-Key)
alt Guardrail-Treffer
L-->>W: Fehler mit Guardrail-Code
W->>D: Run blocked_by_guardrail
else Antwort
L-->>W: Finale Antwort oder Tool-Call
W->>P: Tool-Aufruf und Parameter prüfen
alt Freigabe erforderlich
P-->>W: REQUIRE_APPROVAL
W->>D: Freigabeantrag speichern, Run waiting_approval
else Ausführung erlaubt
P-->>W: ALLOW
W->>M: Tool ausführen
M-->>W: Tool-Ergebnis
W->>D: Tool-Aufruf und Ergebnis persistieren
W->>L: Tool-Ergebnis und Verlauf
L-->>W: Finale Antwort oder weiterer Tool-Call
end
end
W->>D: run_events schreiben und NOTIFY
A->>D: Neue run_events lesen
A-->>U: Antwort und Status streamen
```
Die tatsächliche Implementierung muss mehrere Tool-Aufrufe pro Run
unterstützen. Die Schleife endet, wenn eine finale Antwort vorliegt, ein
Abbruch erfolgt oder ein definiertes Limit erreicht wird. Für die
Wiederaufnahme nach einer Freigabe wird der vollständige Verlauf
inklusive Tool-Call-IDs persistiert.
**Sicherheitsregel:** Der Orchestrator entscheidet nicht anhand des
Modelltexts über die Berechtigung. Jeder einzelne Tool-Aufruf wird
serverseitig gegen die aktuelle Policy geprüft.
**Umgesetzt (Oktober 2026): lange Sessions.** Mit dem Git-Workflow wird
ein Chat zur Arbeits-Session; der Kontext ist darauf ausgelegt:
- Der Verlauf geht nach Token-Budget mit (`AIW_HISTORY_MAX_TOKENS`,
höchstens 60 % des Kontextfensters), nicht nach Nachrichtenzahl.
Tool-Ausgaben älterer Antworten werden gekürzt; die letzten zwei
Antworten behalten sie vollständig.
- Was nicht mehr passt, fasst das Modell in einer **Arbeitsnotiz** je
Chat zusammen (Ziel, Entscheidungen, Commits, offene Punkte). Sie
wird fortgeschrieben, geht im System-Prompt mit und ist im Chat
einsehbar. Scheitert die Zusammenfassung, läuft der Run trotzdem.
- Tool-Schritte je Antwort stellt der Workspace-Admin ein (Standard
`AIW_MAX_TOOL_ROUNDS`, höchstens `AIW_MAX_TOOL_ROUNDS_LIMIT`). Ist
das Limit erreicht, fasst die KI den Stand zusammen; *Weiterarbeiten*
setzt fort.
- Anzeige je Antwort: Füllstand des Kontexts; je Chat: Tokens und
Kosten bisher.
**Umgesetzt (Oktober 2026): Projektregeln.** Liegt im Repository eine
`AGENTS.md`, geht sie (höchstens 8 KB) als Projektkonvention in den
System-Prompt, vom selben Stand, den die Tools lesen. Sie steht nach den
Regeln der Plattform, ist als Daten aus dem Repository markiert und
erweitert keine Rechte. Die Antwort zeigt, welche Regeldatei galt.
**Umgesetzt (Oktober 2026): Plan und Planungsmodus.** Die KI pflegt mit
`update_plan` (`write_internal`) eine Todo-Liste je Chat; sie geht in jeden
Prompt, in die Arbeitsnotiz und in die PR-Beschreibung ein. Der
Planungsmodus wird je Chat per Schalter aktiviert: Angeboten werden nur
Tools der Klasse `read` und `update_plan`. Aufrufe anderer Tools weist
der Run ab, auch wenn die Policy sie erlauben würde. *Plan umsetzen*
beendet den Modus und startet die Umsetzung als neue Nachricht.
**Umgesetzt (Oktober 2026): Patches und statische Prüfung.**
`commit_change` nimmt auch einen Unified Diff; er wird mit
`git apply --cached` in einem temporären Index angewendet und als volle
Inhalte gespeichert, damit der Commit nachbaubar bleibt. Beim Commit
prüfen Parser (Standardbibliothek, für YAML PyYAML) Python, JSON, TOML,
XML und YAML, ohne
Code auszuführen. Befunde sind Warnungen am Commit; der Commit entsteht
trotzdem.
**Umgesetzt (Oktober 2026): Abgleich mit dem Ziel-Branch.** Ein
Merge-Commit (kein Rebase) übernimmt den aktuellen Stand des
Ziel-Branches, gebaut mit `git merge-tree` ohne Arbeitsverzeichnis und mit
festem Zeitpunkt. Gespeichert werden der zweite Elternteil und die
Konfliktlösungen, damit der Commit nachbaubar bleibt. Konfliktfrei reicht
ein Klick; Konflikte löst die KI mit `merge_target`. Sie bekommt die
Dateien mit Konfliktmarkern und gibt je Datei den aufgelösten Inhalt an.
Ergebnisse mit Markern lehnt die Plattform ab. Der Diff der Ansicht
beginnt am gemeinsamen Stand mit dem Ziel-Branch.
### 8.4 Kontextaufbau
Der Orchestrator sendet nicht pauschal sämtliche Dateien oder
Datenbankinhalte an das Modell. Der Kontext besteht aus:
- Sicherheitsregeln der Plattform, danach Hugin-Regeln des Workspace
- Namen und Beschreibungen der Hugin-Skills (Inhalt erst bei Bedarf)
- aktivem Workspace und konkreten Datenquellen
- relevanter Chat-Historie
- freigegebenen Tool-Beschreibungen
- gezielt abgerufenen, relevanten Quellinformationen
- Ergebnissen ausgeführter Tool-Aufrufe
- bei langen Aufgaben kompakten Zusammenfassungen früherer Schritte
Das reduziert unnötige Datenübertragung, hält den Kontext kontrollierbar
und erleichtert die Nachvollziehbarkeit.
**Retrieval-Strategie:** Relevante Inhalte werden agentisch über
Such- und Lese-Tools gefunden (z. B. `search`, `read_file`,
`describe_table`). Es gibt im MVP keinen eigenen Embedding-Index.
Ergänzend nutzt die KI Munin als Gedächtnis für Erkenntnisse über
Repositories und frühere Aufgaben im selben Workspace. Ein
Embedding-Index (z. B. pgvector) bleibt eine spätere Option, etwa für
große Dokumentbestände.
### 8.5 Prompt Injection
Repository-Dateien, Dokumente, Datenbankinhalte und Tool-Ausgaben sind
nicht vertrauenswürdige Daten. Darin enthaltene Anweisungen dürfen weder
Berechtigungen ändern noch Freigaben umgehen oder die erlaubten Tools
erweitern.
Prompts können diese Grenze erklären, aber die eigentliche Durchsetzung
erfolgt über serverseitige Policies, Tool-Allowlisting und Validierung.
Die Erkennung von Prompt Injection ist Aufgabe der Gateway-Guardrails
(siehe 8.1). Die Anwendung behandelt sie als zusätzliche Schicht und
stellt unabhängig davon sicher:
- **DENY-by-default:** Nur eingestufte, freigegebene Tools sind für das
Modell sichtbar.
- **Freigaben aus echten Parametern:** Der Freigabedialog zeigt die
tatsächlichen Argumente bzw. den Diff. Eine vom Modell formulierte
Zusammenfassung ist höchstens ein Zusatz und als solche markiert.
- **Durchsetzung im Quellsystem:** Minimal berechtigte technische
Accounts und Bitbucket Branch Permissions begrenzen den Schaden
auch bei erfolgreicher Manipulation des Modells.
- **Feste Kontextgrenzen:** Munin-Projekt (über den Key je Workspace)
und Quellen werden serverseitig festgelegt, nicht vom Modell gewählt.
- **Keine Datenabflusskanäle in der UI:** Bereinigte Darstellung ohne
externe Bilder (siehe 4.5).
- **Bewusste Quellkombination:** Workspaces, die vertrauliche Daten,
nicht vertrauenswürdige Inhalte und ein Tool mit Zugriff nach außen
kombinieren, sind besonders riskant. Solche Tools werden im MVP
nicht angebunden.
------------------------------------------------------------------------
## 9. Mehrstufige Tasks und persistente Ausführung
Ein einfacher HTTP-Request reicht nicht aus, um längere Agentenaufgaben
zuverlässig auszuführen. Deshalb wird eine Task Engine mit persistiertem
Zustand vorgesehen.
### 9.1 Beispiel
Eine Aufgabe könnte lauten: „Untersuche einen Fehler im Repository,
analysiere die betroffenen Module, schlage eine Änderung vor und führe
sie nach Freigabe aus."
Möglicher Ablauf:
1. Task und initialer Kontext werden angelegt.
2. Der Orchestrator plant beziehungsweise beginnt den nächsten Schritt.
3. Er liest Dateien und führt freigegebene Analysen aus.
4. Zwischenergebnisse und Tool-Aufrufe werden gespeichert.
5. Für eine schreibende Aktion wird eine Freigabe beantragt.
6. Der Task pausiert, bis eine gültige Entscheidung vorliegt.
7. Nach Freigabe werden die Parameter erneut validiert und die Aktion
ausgeführt.
8. Das Ergebnis wird überprüft und persistiert.
9. Der Task wird abgeschlossen und das Ergebnis dem Nutzer angezeigt.
### 9.2 Task-Lebenszyklus
``` mermaid
stateDiagram-v2
[*] --> queued
queued --> running
queued --> cancelled
running --> waiting_approval
running --> waiting_input: Rückfrage an Nutzer
waiting_approval --> queued: entschieden (genehmigt, abgelehnt, abgelaufen)
waiting_approval --> cancelled
waiting_input --> queued: Nutzer antwortet
waiting_input --> cancelled
running --> completed
running --> failed
running --> cancelled
running --> blocked_by_guardrail
running --> needs_reconciliation: Ausgang einer Schreibaktion unklar
needs_reconciliation --> queued: Abgleich mit Zielsystem erfolgt
needs_reconciliation --> failed
failed --> queued: kontrollierte Wiederaufnahme
blocked_by_guardrail --> [*]
completed --> [*]
cancelled --> [*]
```
Die Statusübergänge müssen verbindlich definiert und serverseitig
validiert werden.
**Ablehnung betrifft den Schritt, nicht den Task:** Wird eine Aktion
abgelehnt oder läuft die Freigabe ab, wird der Freigabeantrag und der
betroffene Schritt entsprechend markiert. Der Task wird wieder
eingereiht; das Modell erhält die Ablehnung als Tool-Ergebnis und kann
einen sicheren Alternativweg vorschlagen oder den Task beenden. Eine
abgelehnte Aktion darf nicht automatisch erneut mit denselben Parametern
beantragt oder ausgeführt werden.
**Schrittzustände** (`task_steps`, `approval_requests`): `pending`,
`approved`, `rejected`, `expired`, `executed`, `failed`, `unknown`.
**`needs_reconciliation`:** Ist unklar, ob eine Schreibaktion im
Zielsystem wirksam wurde (z. B. Absturz nach Push, vor Persistierung),
prüft der Worker den Zielzustand (etwa: existiert Branch `ai/<task-id>`
mit erwartetem Commit, existiert der Pull Request?), bevor er fortfährt.
Ist das nicht automatisch möglich, entscheidet ein Nutzer.
**Umsetzung:** Schreibtools sind idempotent und prüfen den Zielzustand
selbst. Fällt der Worker während einer Ausführung aus (abgelaufene
Lease) oder endet sie mit unerwartetem Fehler, wird der Antrag
`unknown` und der Run `needs_reconciliation`. Ein Workspace-Admin
startet dann den Abgleich (das Tool erkennt einen schon gepushten
Branch bzw. vorhandenen Pull Request) oder beendet den Run. Der Zustand
eines pausierten Runs (bisherige Modellausgaben, offene Tool-Aufrufe,
Snapshot-Commits) liegt in `task_runs.state`.
### 9.3 PostgreSQL statt Redis
Für das MVP sind PostgreSQL und ein separater Worker-Prozess
grundsätzlich ausreichend.
Mögliches Ausführungsmodell:
1. FastAPI legt Task und Job in PostgreSQL an.
2. Ein Worker beansprucht fällige Jobs mit einer transaktionssicheren
Queue-Strategie, beispielsweise `FOR UPDATE SKIP LOCKED`.
3. Der Worker speichert Fortschritt und Ergebnisse fortlaufend.
4. Bei einer erforderlichen Freigabe wechselt der Task in einen
wartenden Zustand.
5. Nach der Entscheidung wird ein neuer Job freigegeben.
6. Nach einem Neustart können abgelaufene oder unterbrochene Jobs
kontrolliert wiederaufgenommen werden.
Konkretisierung:
- Ein beanspruchter Job erhält eine Lease mit Ablaufzeit
(`locked_until`). Der Worker verlängert sie per Heartbeat.
- Läuft die Lease ab, gilt der Job als unterbrochen. Steckte er in
einer Schreibaktion, wechselt der Run nach `needs_reconciliation`,
sonst wird er neu eingereiht.
- Beim Beanspruchen wird die maximale Zahl gleichzeitiger Runs pro Team
berücksichtigt.
- Wartende Runs belegen keinen Worker; nach einer Entscheidung oder
Nutzerantwort entsteht ein neuer Job.
Redis und eine separate Workflow-Plattform sind damit keine
Voraussetzung für das MVP.
### 9.4 Fehler und Idempotenz
Eine Datenbank allein löst nicht alle Fehlerfälle. Beispielsweise kann
ein externes Schreibtool erfolgreich sein, obwohl der Worker vor dem
Speichern des Ergebnisses abstürzt.
Daher sind vorzusehen:
- Idempotenzschlüssel, sofern die Ziel-API diese unterstützt
- Persistierte Zustände für jeden relevanten Schritt
- Erkennung unklarer Ausführungsergebnisse
- Abgleich mit dem Zielsystem vor Wiederholung nicht-idempotenter
Aktionen
- Begrenzte und kontrollierte Wiederholungslogik
- Kein blindes Wiederholen von Schreiboperationen
- Abbruch- und Wiederaufnahmebedingungen
- Limits für Laufzeit, Tool-Aufrufe und Modellaufrufe
### 9.5 Grenzen der Autonomie
- Keine unbeschränkten Tool-Schleifen
- Keine unkontrollierte Erzeugung weiterer Tasks; Subagenten laufen
als Kind-Runs mit begrenzter Tiefe, Anzahl und begrenztem Budget und
nie mit mehr Rechten als der Eltern-Run
- Keine Umgehung von Freigaben durch alternative Tool-Sequenzen
- Keine dauerhaften Berechtigungen aus einer einmaligen Freigabe
ableiten
- Jeder relevante Schritt ist nachvollziehbar
- Abbruch und Wiederaufnahme müssen kontrolliert erfolgen
------------------------------------------------------------------------
## 10. Risikobasierte Freigaben und Governance
Die Policy Engine ist eine eigenständige Komponente. Sicherheitsregeln
sollen geändert werden können, ohne den Orchestrator umzubauen.
### 10.1 Entscheidungstypen
-----------------------------------------------------------------------
Policy-Ergebnis Verhalten
----------------------------------- -----------------------------------
`ALLOW` Aktion darf ohne zusätzliche
Nutzerbestätigung ausgeführt werden
`REQUIRE_APPROVAL` Aktion pausiert bis zur gültigen
Freigabe
`DENY` Aktion wird blockiert; Standard für
nicht eingestufte Tools
-----------------------------------------------------------------------
**Technische Umsetzung im MVP:** Die Policies liegen in der Tabelle
`tool_policies` (Tool → Entscheidung, Risikoklasse, erforderliche
Freigabestufe) und werden in Python ausgewertet. Modus B (siehe 10.3)
wirkt als übergeordnete Regel. Eine Policy-Sprache wie OPA oder Cedar
ist nicht vorgesehen, kann aber hinter derselben Schnittstelle ergänzt
werden. Die Gateway-Guardrails sind eine zusätzliche Schicht und ersetzen
die Policy Engine nicht.
**Einstufung von Tools:** Neu entdeckte oder geänderte Tools sind
„nicht eingestuft“ und damit `DENY`. Administratoren legen pro Tool
global Risikoklasse und Standardentscheidung fest. Workspace-Admins
dürfen diese Vorgaben für ihren Workspace nur verschärfen (z. B. `ALLOW`
→ `REQUIRE_APPROVAL` oder `DENY`), nie lockern. Jede Einstufung wird
auditiert. Risikoklassen und MVP-Zuordnung siehe 10.7.
### 10.2 Kriterien für die Risikobewertung
Eine Policy kann unter anderem berücksichtigen:
- Aktionstyp: Lesen, Schreiben, Löschen oder Ausführen
- betroffene Datenquelle und Umgebung
- konkretes Tool und konkrete Operation
- Rolle des aufrufenden Nutzers
- Risikoklasse und mögliche Auswirkungen
- Workspace- und Unternehmensvorgaben
- Sensitivität der betroffenen Daten
### 10.3 Konfigurierbare Modi
**Modus A -- Risikobasiert**
Policies entscheiden anhand von Aktion, Kontext und Risiko, ob eine
Bestätigung nötig ist.
**Modus B -- Jede schreibende Aktion benötigt eine Freigabe**
Alle schreibenden Aktionen in Fremdsysteme (Risikoklasse
`write_external`) müssen explizit bestätigt werden, auch wenn die
Einstufung sonst `ALLOW` erlauben würde. Schreibzugriffe auf interne,
wiederherstellbare Ablagen (`write_internal`, z. B. Munin) sind davon
ausgenommen. Dieser Modus kann pro Workspace oder nach zentraler Vorgabe
aktiviert werden.
Auch im strengeren Modus sind lesende Aktionen nicht automatisch
unbedenklich. Quellenberechtigungen, Datenschutz und
Zugriffsbeschränkungen gelten unabhängig von der Freigabepolicy.
### 10.4 Inhalt einer Freigabe
Ein Freigabeantrag muss sich auf eine konkrete Aktion beziehen. Er
sollte enthalten:
- Nutzer und Workspace
- Zielquelle und konkretes Tool
- Geprüfte Parameter als unveränderlicher Snapshot
- Aus den echten Parametern erzeugte Darstellung der Änderung (z. B.
Diff); eine Modellzusammenfassung nur als gekennzeichneter Zusatz
- Vorbedingungen für den Zustand des Zielsystems (z. B. Basis-Commit)
- Risikoklasse und Begründung
- Ablaufzeitpunkt und Status
- Entscheider, Entscheidungszeitpunkt und optionalen Kommentar
**Umsetzung:** Der Hash umfasst Tool, Quelle, Argumente, Diff,
Vorbedingungen und den Hash der Tool-Definition. Vor der Ausführung
werden Hash, Tool-Definition, Policy (nicht inzwischen gesperrt) und die
Workspace-Rechte von Antragsteller und Entscheider erneut geprüft, im
Tool dann die Vorbedingungen im Zielsystem. Ablehnungen brauchen eine
Begründung, die das Modell als Tool-Ergebnis erhält. Erlaubt die Policy
eine Schreibaktion ohne Freigabe (`ALLOW`, nur Modus A), entsteht
trotzdem ein Antrag, der als „durch Policy erlaubt“ genehmigt ist, damit
Ausführung und Abgleich gleich nachvollziehbar sind. Offene Freigaben
sehen Workspace-Admins unter *Freigaben* mit Badge; Badge und wartende
Chats aktualisieren sich im MVP per Polling (20 bzw. 5 Sekunden) statt
per SSE.
Die Freigabe ist an einen Hash über Tool, Argumente, Quelle und
Policy-Version gebunden. Ausgeführt wird nur exakt der freigegebene
Snapshot. Ändern sich Parameter oder sind die Vorbedingungen nicht mehr
erfüllt, ist eine neue Freigabe erforderlich. Eine Freigabe ist keine
allgemeine dauerhafte Berechtigung für alle späteren Aktionen.
### 10.5 Wer gibt frei?
- Nutzer beantragen Aktionen; Workspace-Admins des betroffenen
Workspace entscheiden.
- Beantragt ein Workspace-Admin selbst eine Aktion, darf er sie im MVP
selbst freigeben. Dies wird im Audit als Selbstfreigabe markiert.
Später kann pro Policy ein zweiter Admin vorgeschrieben werden.
- Für Risikoklassen mit der Freigabestufe `global_approver` reicht ein
Workspace-Admin nicht aus (nach dem MVP).
Umgesetzt (Phase 5): Freigabestufe und Vier-Augen-Prinzip je Tool in
der globalen Einstufung; Workspaces können Vier Augen zusätzlich
verlangen und Regeln je Quelle setzen (nur verschärfend). Globale
Approver sind ein Kennzeichen am Nutzer; sie sehen und entscheiden
Anträge der Stufe `global_approver` in allen Workspaces, auch ohne
Mitgliedschaft. Stufe und Vier-Augen-Pflicht stehen im Antrag und im
Hash; vor der Ausführung wird das Recht des Entscheiders erneut geprüft.
Tools ohne eigenes `prepare` (z. B. lesende) laufen bei „Freigabe nötig“
über einen allgemeinen Antrag mit den Argumenten als Vorschau.
- Anträge laufen nach einer konfigurierbaren Frist ab (Standard: 24
Stunden) und werden dann als `expired` an den Run zurückgegeben.
Im MVP betrifft das Git-Änderungen über `propose_change`; die kurze
Frist hält vorgeschlagene Patches aktuell.
- Benachrichtigung erfolgt im MVP nur in der App.
### 10.6 Ablauf einer Freigabe
``` mermaid
flowchart TD
A["Tool-Aufruf angefordert"] --> B["Identität, Quelle und Parameter validieren"]
B --> C["Policy Engine entscheidet"]
C -->|ALLOW| D["Aktion ausführen"]
C -->|REQUIRE_APPROVAL| E["Freigabeantrag mit Snapshot persistieren"]
E --> F["Task pausieren, Workspace-Admins in der App informieren"]
F --> G{"Entscheidung Workspace-Admin"}
G -->|Genehmigt| H["Berechtigung, Snapshot-Hash und Vorbedingungen erneut prüfen"]
H --> D
G -->|Abgelehnt| I["Aktion nicht ausführen; Ablehnung als Tool-Ergebnis an das Modell"]
G -->|Abgelaufen| J["Freigabe ungültig; neue Entscheidung erforderlich"]
C -->|DENY| K["Aktion blockieren und protokollieren"]
D --> L["Ergebnis und Audit speichern"]
```
### 10.7 Risikoklassen und Tool-Einstufung (MVP)
---------------------------------------------------------------------------------
Klasse Bedeutung Modus A Modus B
------------------ ----------------------------- ------------------- ------------
`read` Liest nur Daten des `ALLOW` `ALLOW`
Workspace
`write_internal` Schreibt nur in interne, `ALLOW` `ALLOW`
wiederherstellbare Ablage
`write_external` Schreibt in ein Fremdsystem, `REQUIRE_APPROVAL` `REQUIRE_APPROVAL`
umkehrbar
`destructive` Löscht oder ist nicht `DENY` `DENY`
umkehrbar
---------------------------------------------------------------------------------
`destructive` bleibt im MVP vollständig gesperrt.
**Zuordnung der MVP-Tools:**
-----------------------------------------------------------------------
Tool Klasse und Begründung
----------------------------------- -----------------------------------
Git: `list_dir`, `read_file`, `read`
`search`, `find_files`, `log`,
`blame`, `diff`, `show_commit`
Git: `propose_change` (Patch, `write_external`; einziges Tool,
Titel, Beschreibung) das nach außen schreibt. Nach
Freigabe anhand des Diffs: Push auf
`ai/<task-id>` und Pull Request
DuckDB: `list_tables`, `read`; Verbindung schreibgeschützt
`describe_table`, `query`
Munin: `recall`, `get`, `list`, `read`
`related`
Munin: `remember` `write_internal`; Einträge in der
UI sichtbar, Verlauf in Munin
Munin: `forget` Kein Tool für die KI; nur Menschen
löschen über die UI. Schützt vor
Massenlöschung durch Prompt
Injection
Hugin: `load_skill`, `read`; nur abonnierte,
`read_skill_file` festgeschriebene Versionen
Hugin: `report_feedback` `write_internal`; Rückmeldung an
das interne Register ohne Wirkung
auf Daten oder Systeme, mit
Rate-Limit
Tools zentraler MCP-Server Nicht eingestuft und damit `DENY`,
bis ein Administrator sie einstuft
-----------------------------------------------------------------------
Für Git gibt es bewusst genau ein schreibendes Tool. Das Modell stellt
den Patch über lesende Tools zusammen; erst `propose_change` löst
Freigabe, Push und Pull Request aus. Damit gibt es genau eine
Freigabestelle.
------------------------------------------------------------------------
## 11. API- und Routenstruktur
HTML-Routen bedienen Jinja2/HTMX. JSON-Endpunkte unterstützen asynchrone
Interaktionen und mögliche interne Integrationen.
-----------------------------------------------------------------------
Bereich Beispielhafte Routen
----------------------------------- -----------------------------------
Authentifizierung `GET /login`, `POST /login`,
`POST /logout`
Workspaces `GET /workspaces`,
`POST /workspaces`,
`GET /workspaces/{id}`
Datenquellen `POST /workspaces/{id}/sources`,
`POST /sources/{id}/test`,
`GET /sources/{id}/tools`,
`POST /tools/{id}/classification`
Memory `GET /workspaces/{id}/memory`,
`DELETE /memory/{entry_id}`
Chat `POST /workspaces/{id}/chats`,
`POST /chats/{id}/messages`
Streaming `GET /runs/{id}/events` (SSE,
unterstützt `Last-Event-ID`)
Tasks `GET /tasks/{id}`,
`POST /tasks/{id}/cancel`,
`POST /tasks/{id}/resume`
Freigaben `GET /approvals`,
`POST /approvals/{id}/approve`,
`POST /approvals/{id}/reject`
Administration `/admin/models`,
`/admin/connectors`,
`/admin/policies`
-----------------------------------------------------------------------
Dies sind Vorschläge; die endgültigen Routen sollten sich aus den
UI-Flows und dem Domänenmodell ergeben.
### Technische Hinweise
- Schreibende Browser-Endpunkte benötigen geeigneten CSRF-Schutz,
sofern Cookie-basierte Sessions eingesetzt werden.
- Autorisierung wird bei jedem Request geprüft.
- Lange Aufgaben werden nicht an die Lebensdauer eines HTTP-Requests
gebunden.
- SSE-Clients können sich erneut verbinden und den Run-Zustand wieder
laden.
- Fehlerantworten enthalten keine Secrets oder internen Stacktraces.
- API-Versionierung wird ergänzt, falls externe Clients oder
unabhängige Integrationen entstehen.
------------------------------------------------------------------------
## 12. Vorschlag für die Code-Struktur
``` text
app/
├── main.py
├── core/
│ ├── config.py
│ ├── security.py
│ ├── database.py
│ └── logging.py
├── identity/
├── teams/
├── workspaces/
├── data_sources/
│ ├── service.py
│ ├── registry.py
│ └── connectors/
│ ├── remote_mcp.py
│ ├── munin.py
│ ├── git/
│ │ ├── connector.py
│ │ └── pull_requests/
│ │ └── bitbucket_dc.py
│ └── uploads_duckdb.py
├── hugin/
│ ├── client.py
│ ├── sync.py
│ └── mapping.py
├── chat/
├── ai/
│ ├── gateway.py
│ ├── guardrails.py
│ ├── orchestrator.py
│ └── context.py
├── mcp/
│ ├── client_manager.py
│ └── transports.py
├── tasks/
│ ├── engine.py
│ ├── worker.py
│ ├── events.py
│ └── repository.py
├── approvals/
├── policies/
├── audit/
├── templates/
├── static/
└── tests/
```
Diese Struktur ist eine logische Modulaufteilung innerhalb eines
modularen Monolithen. Die Module müssen nicht getrennt deployed werden.
Ein eigener Worker-Prozess kann dieselbe Codebasis und dieselben
internen Services nutzen.
------------------------------------------------------------------------
## 13. Security- und Governance-Anforderungen
-----------------------------------------------------------------------
Bereich Anforderung
----------------------------------- -----------------------------------
Identität Demo-Identität hinter einer
austauschbaren Schnittstelle;
später OIDC/Keycloak
Autorisierung Serverseitige Prüfung bei jedem
Zugriff auf Workspace, Quelle, Task
und Freigabe
MCP-Netzwerk Nur registrierte Server und
erlaubte Netzwerkziele
Lokale Prozesse Nicht im MVP; später Allowlist für
Executables, Argumente und
Laufzeitumgebung
Secrets Serverseitig verwalten; keine
Zugangsdaten in HTML, Prompts oder
Logs
Tool-Calling Schema-Validierung,
Parameterprüfung, Timeouts und
Policy-Prüfung
Schreiboperationen Policy-Prüfung und bei Bedarf
explizite Freigabe
Audit Nachvollziehbare Aktionen,
Entscheidungen, Ergebnisse und
Fehler
Datenschutz Datenminimierung,
Aufbewahrungsregeln und
kontrollierter Modellkontext;
DSFA und Betriebsvereinbarung
werden separat behandelt
Ausgabe im Browser Bereinigtes Markdown, keine
externen Bilder, strikte CSP
Quellsysteme Minimal berechtigte technische
Accounts; Bitbucket Branch
Permissions nur für `ai/*`
Agentic Memory Munin-Key je Workspace im Secret
Store; kein Lösch-Tool für die KI
Fehlerbehandlung Keine unsicheren Wiederholungen
externer Schreiboperationen
Prompt Injection Inhalte aus Quellen als nicht
vertrauenswürdige Daten behandeln;
Erkennung durch Gateway-Guardrails,
Durchsetzung durch die Anwendung
Mandantentrennung Workspace- und Teamgrenzen
serverseitig konsequent durchsetzen;
optional Row-Level Security
Dateiuploads Dateityp- und Größenlimits, sichere
Ablage und Schutz vor unsicherer
Verarbeitung
Ressourcenlimits Begrenzung von Laufzeit,
Parallelität, Antwortgröße und
Modell-/Tool-Aufrufen
-----------------------------------------------------------------------
### Audit-Ereignisse
Mindestens folgende Ereignisse sollten protokolliert werden:
- Workspace und Datenquelle angelegt, geändert oder entfernt
- Verbindung getestet und Ergebnis
- Chat-Run gestartet, abgeschlossen, abgebrochen oder fehlgeschlagen
- Tool-Aufruf angefordert, erlaubt, blockiert oder ausgeführt
- Tool eingestuft oder durch geänderte Definition zurückgesetzt
- Bestätigung des Workspace-Admins beim Verbinden einer Quelle
- Freigabe beantragt, erteilt (inklusive Selbstfreigabe), abgelehnt
oder abgelaufen
- Blockierung durch Gateway-Guardrail mit Code
- Task wiederaufgenommen oder abgebrochen
- Konfiguration und Policy geändert
- Authentifizierungs- und Autorisierungsfehler, soweit sicher
protokollierbar
Audit-Daten sollen keine unkontrollierte Kopie aller vertraulichen
Inhalte darstellen. Sensible Parameter und Ergebnisse benötigen eigene
Aufbewahrungs- und Zugriffsvorgaben.
------------------------------------------------------------------------
## 14. MVP-Plan
### Phase 1 -- Grundgerüst und Workspace
- FastAPI, Jinja2, HTMX und PostgreSQL
- Datenmodell und Migrationen
- Demo-Identität mit späterem OIDC-Erweiterungspunkt
- Teams (einfach gepflegt) und Workspace-Verwaltung mit
Team-Zuordnung
- Datenquellenregistrierung und Verbindungstest
- Basisrollen und Autorisierung
- Worker-Prozess mit Job-Queue, `run_events` und SSE (zunächst mit
einem Dummy-Run)
- Datenmodell bereits mit `parent_run_id` und Feld für verwendete
Hugin-Versionen
**Ergebnis:** Nutzer können einen Workspace anlegen und eine
kontrollierte Datenquelle konfigurieren; der Ausführungspfad über den
Worker steht.
### Phase 2 -- Chat und lesende Git-Integration
- OpenAI-kompatibles Gateway mit Team-Key anbinden, inklusive
Behandlung der Guardrail-Fehlercodes
- Jede Chat-Nachricht als Run im Worker, Streaming über SSE
- Persistierter Chatverlauf und bereinigte Darstellung
- `GitConnector` mit lesenden Tools
- Tool-Einstufung (DENY-by-default) und einfache `tool_policies`
- Kontextbezogene Quellen und Tool-Status
**Ergebnis:** Die KI kann ein Git-Repository lesen und analysieren.
### Phase 3 -- Freigaben und Pull Requests
- Mehrstufige Runs mit Pausen, Wiederaufnahme und Abbruch
- Policy Engine und Freigabeoberfläche für Workspace-Admins
- Branch `ai/<task-id>` und Pull Request über Bitbucket Data Center
- Freigabe anhand des echten Diffs und Basis-Commits
- `needs_reconciliation` und Schutz vor doppelten Schreiboperationen
- Audit-Protokoll
**Ergebnis:** Eine Aufgabe kann eine Änderung vorschlagen, auf die
Freigabe eines Workspace-Admins warten und danach einen Pull Request
erstellen.
### Phase 4 -- Erweiterung
- Munin als Agentic Memory mit festem Projekt pro Workspace
- Hugin-Anbindung: Abgleich, Festschreiben, `rules`, `skill`,
`command` (umgesetzt, siehe 7.9)
- MCP-Katalog aus Hugin mit Tool-Einstufung
- Uploads mit DuckDB-Analyse
- Optional: Testdatenbank mit lesendem Zugriff
**Ergebnis:** Weitere Quellen, Gedächtnis über Sessions hinweg und
zentral gepflegtes Agentenverhalten aus Hugin.
### Phase 5 -- Härtung
- OIDC-/Keycloak-Integration
- Teamverwaltung über Keycloak-Gruppen
- Subagenten aus Hugin als Kind-Runs
- Feingranulare Policies und globale Approver
- Nutzer-Delegation gegenüber Quellsystemen prüfen
- Weitere `PullRequestProvider`
- Sicherheits-, Last- und Wiederanlauftests
- Verbesserte Ergebnisansichten und Administration
**Ergebnis:** Grundlage für einen kontrollierten Einsatz im
Unternehmensumfeld.
OpenShift-Deployment, Infrastruktur und Plattformbetrieb werden separat
behandelt.
------------------------------------------------------------------------
## 15. Abnahmekriterien für die erste Demo
- [ ] Ein Nutzer erstellt einen Workspace und verbindet eine
freigegebene Datenquelle.
- [ ] Das reguläre Chatinterface ist erst nach erfolgreicher
Quellenkonfiguration zugänglich.
- [ ] Die KI kann ein freigegebenes Tool aufrufen und das Ergebnis
nachvollziehbar darstellen.
- [ ] Unterhaltung und Tool-Aufrufe bleiben nach einem Seiten-Reload
erhalten.
- [ ] Ein mehrstufiger Task läuft unabhängig vom ursprünglichen
HTTP-Request.
- [ ] Ein Task kann auf eine Freigabe warten und danach fortgesetzt
werden.
- [ ] Eine verweigerte oder abgelaufene Freigabe führt nicht zur
Ausführung der Aktion.
- [ ] Ein Worker-Neustart führt nicht zu unkontrollierten doppelten
Schreiboperationen.
- [ ] Nicht berechtigte Nutzer können weder fremde Workspaces noch
fremde Freigaben oder Task-Ergebnisse abrufen.
- [ ] Der Modus „jede schreibende Aktion bestätigen" kann aktiviert
werden, ohne den Orchestrator umzubauen.
- [ ] Nicht vertrauenswürdige Inhalte können keine Berechtigungen
erweitern oder Policies überschreiben.
- [ ] Fehlerhafte oder nicht erreichbare MCP-Server führen zu
kontrollierten Fehlerzuständen.
- [ ] Modell- und Tool-Aufruflimits verhindern unbeschränkte
Ausführungsschleifen.
- [ ] Ein abgebrochener SSE-Stream wird nach erneutem Verbinden ohne
Lücken fortgesetzt.
- [ ] Nicht eingestufte oder geänderte Tools sind für das Modell
nicht sichtbar.
- [ ] Nur Workspace-Admins des betroffenen Workspace können Freigaben
erteilen; Selbstfreigaben sind im Audit erkennbar.
- [ ] Der Freigabedialog zeigt den echten Diff, nicht nur eine
Modellzusammenfassung.
- [ ] Der technische Bitbucket-Account kann nur auf `ai/*` pushen; ein
Pull Request wird nach Freigabe erstellt.
- [ ] Ein Guardrail-Fehler des Gateways führt zu einem verständlichen
Zustand `blocked_by_guardrail` ohne automatische Wiederholung.
- [ ] Modellausgaben mit HTML oder externen Bildern werden bereinigt
dargestellt.
- [ ] Ein Aufruf nicht vorhandener Tools (z. B. `bash`) wird
abgewiesen, dem Modell als Fehler zurückgemeldet und auditiert.
- [ ] Ein gepushter `ai/*`-Branch löst keine CI-Pipeline mit Secrets
automatisch aus.
------------------------------------------------------------------------
## 16. Entschiedene und offene Punkte
### 16.1 Im Review v0.2 entschieden
-----------------------------------------------------------------------
Punkt aus v0.1 Ergebnis
----------------------------------- -----------------------------------
Erste Datenquelle Git allgemein, Pull Requests über
Bitbucket Data Center; Ersatz:
Testdatenbank (7.5)
Betriebsmodell lokaler Nicht im MVP; bei Bedarf als
MCP-Prozesse eigenes Deployment mit HTTP (7.1)
AI Gateway: Zugang und API-Key pro Team; Guardrails melden
Guardrails Fehler mit Code (8.1)
Freigabeberechtigung Workspace-Admins (10.5)
Agentic Memory Munin mit Projekt pro Workspace,
Papierkorb 30 Tage (7.6)
Agentenverhalten Hugin: Auswahl in den
Workspace-Einstellungen, Anbindung
über erweiterten Lieferweg (7.9)
-----------------------------------------------------------------------
Alle weiteren Entscheidungen stehen in Abschnitt 2.1.
### 16.2 AI Gateway
Geklärt: Tool Calling im OpenAI-kompatiblen Format, Streaming und die
Responses API werden unterstützt; die Plattform nutzt die Responses API
zustandslos (8.1). Authentifizierung per Bearer Token (Team-Key); das Gateway
erkennt das Team, nicht den einzelnen Nutzer. Für die Entwicklung wird
zunächst die OpenAI-API mit `gpt-6-luna` genutzt (8.1).
Im Rahmen der Implementierung noch zu ermitteln:
- Verfügbare Modelle und deren Tool-Calling-Qualität
- Liste der Guardrail-Fehlercodes und deren Verhalten mitten im Stream
- Timeouts und Rate Limits pro Team-Key
- Umgang mit Modellmetadaten und Tokenverbrauch
Nicht Aufgabe dieses Projekts: ob die Guardrails auch Tool-Ergebnisse
prüfen. Das liegt beim Gateway.
### 16.3 Datenaufbewahrung (zurückgestellt)
Aufbewahrungsfristen für Nachrichten, `run_events`, Tool-Ergebnisse,
Uploads und Audit-Daten werden vorerst nicht festgelegt. Das Datenmodell
sieht trotzdem Zeitstempel und Löschbarkeit vor, damit Fristen später
ergänzt werden können. Für Munin gilt: gelöschte Einträge werden nach
30 Tagen im Papierkorb endgültig entfernt. Datenschutz-Folgenabschätzung
und Betriebsvereinbarung werden separat behandelt.
### 16.4 Freigaberichtlinien
Geklärt: Risikoklassen, Zuordnung der MVP-Tools und Einstufungsrechte
(10.1, 10.7). Freigabeanträge laufen standardmäßig nach 24 Stunden ab
(10.5).
### 16.5 Hugin
Im Hugin-Projekt umgesetzt (25.10.2026):
- Endpunkte im Lieferweg für Integrationen: Auflösen ohne Übersetzung,
Download im Quellformat und Rückmeldung für Integrations-Keys (7.9)
- Aufnahme der Plattform als Abnehmer im Hugin-Konzept (14.7,
„Plattformen als Abnehmer“)
Zuordnung der Modellklassen (`fast`, `standard`, `thorough`) zu
Gateway-Modellen: zunächst alle auf `gpt-6-luna`; die endgültige
Zuordnung folgt, sobald die Modelle aus dem Gateway verfügbar sind.
### 16.6 Munin
Geklärt: Der Key bestimmt das Projekt; ein Key je AI-Workspace genügt
für die Trennung (7.6). Projekte und Keys werden im MVP von Hand in der
Munin-Weboberfläche angelegt. Eine Admin-API in Munin zur automatischen
Einrichtung und zum Aufräumen beim Löschen eines Workspace ist eine
spätere Option.
------------------------------------------------------------------------
## 17. Zusammenfassung und zentrale Architekturentscheidung
Die Plattform wird als **modularer Monolith auf FastAPI mit Jinja2 und
HTMX** konzipiert. Jeder Chat-Run wird in einem Worker ausgeführt;
PostgreSQL bildet die zentrale persistente Grundlage und trägt auch
Job-Queue und Streaming-Ereignisse. Redis ist für das MVP nicht
vorgesehen. Ein OpenAI-kompatibles AI Gateway mit API-Key pro Team und
eigenen Guardrails stellt die Modellanbindung bereit. Datenquellen
werden über eine einheitliche Connector-Schicht integriert: zentrale
MCP-Server (darunter Munin als Agentic Memory) sowie native Connectoren
für Git, Bitbucket Data Center und DuckDB-Uploads. Lokal gestartete
MCP-Prozesse sind nicht Teil des MVP. Regeln, Skills, Befehle,
Subagenten und MCP-Anbindungen kommen geprüft und versioniert aus Hugin;
sie steuern das Verhalten, verleihen aber keine Rechte.
Die beiden zentralen fachlichen Komponenten sind:
1. **Task Engine:** Sie ermöglicht mehrstufige, persistente und
wiederaufnehmbare Aufgaben.
2. **Policy und Approval Engine:** Sie kontrolliert jeden Tool-Aufruf,
blockiert nicht eingestufte Tools, setzt Berechtigungen durch und
leitet Freigaben an die Workspace-Admins.
Schreibende Änderungen an Code erfolgen ausschließlich als Branch und
Pull Request; das Quellsystem setzt dies über Branch Permissions
zusätzlich durch.
Die Demo verwendet zunächst eine vereinfachte Anmeldung, während die
Architektur die spätere Keycloak-/OIDC-Integration vorsieht. OpenShift
und die Infrastrukturdetails sind nicht Bestandteil dieses Konzepts.
**Wichtigste Leitlinie:** Der Chat ist nicht der Einstiegspunkt, sondern
die Arbeitsoberfläche eines eingerichteten und autorisierten Workspaces.
Die Anwendung hält die Kontrolle über Kontext, Datenzugriff,
Tool-Ausführung, Freigaben und den Lebenszyklus jeder Aufgabe.