# 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 `__` 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/` 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/-` (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-`, 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/`. 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//.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/`). #### 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/`. - **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/` 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/` 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/` 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.