2507 lines
113 KiB
Markdown
2507 lines
113 KiB
Markdown
# 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.
|