Sprint 2 — Master-Plan
Alle Sprint-2-Items zusammen geplant. Reihenfolge ist optimiert auf maximalen Nutzen pro Tag: erst der Layer der allem anderen Hebel gibt (Marktdaten-Kontext + m365 delegated), dann Workflow-Automatisierung (Skills + Image/Transcribe). Jedes Teil-Sprint ist isoliert deploybar.
Das eigentliche Ziel
VF will „Claude arbeitet auf den richtigen Daten, immer aktuell, kein veraltetes Wissen” — und Marvin will den dynamic-prompt-building-Pattern beibehalten (siehe Zitat unten). Dafuer braucht es zwei Architektur-Bausteine die heute noch fehlen:
- Marktdaten/Firmen-Kontext als Live-Quelle: VF hat in SharePoint Markdown-Files mit „wichtigsten Informationen zum Unternehmen” (Positionierung, Team, Standard-Kunden, Branchen-Vokabular, Preis-Logiken usw.). Diese muessen im System-Prompt bei JEDER Conversation aktuell sein — nicht als statischer Snapshot, sondern live aus SharePoint gezogen.
- Schreibrechte als 1. Klasse Buerger in m365: Heute kann Claude lesen aber kaum schreiben. Sprint 2a macht volle Write-Paritaet auf SharePoint/Mail/Lists/Calendar mit delegated OAuth — jeder User schreibt unter seiner eigenen Identitaet.
Zitat Marvin (2026-05-13): „wir bauen den Prom dann jedes Mal dynamisch zusammen, und das soll auch weiterhin so sein… die haben aber auch diese Marktdaten… wir muessen es irgendwie so hinbekommen, dass das mal auf diesen Markt und falls ihm irgendwie arbeitet, geht es.”
Was „Dynamic Prompt Building” konkret heisst
Heute (Sprint 1, lebt): Custom Model vf-sonnet hat einen statischen System-Prompt mit {{CURRENT_DATE}} als einzigem dynamischen Platzhalter. Tool-Calls zu mcp-vf-hosted gehen on-demand wenn Claude entscheidet sie zu nutzen.
Soll (Sprint 2b): Bei jeder neuen Conversation wird vor dem ersten LLM-Call ein Kontext-Refresh gemacht — die aktuellen Marktdaten + User-Identitaet + heutiges Datum + ggf. aktuelle Termine-Kalender-Spitze werden in einen gestaffelten System-Prompt kombiniert. Das Ergebnis ist:
[STATIC PRELUDE]
Du bist Claude fuer Vibe Factory. Tools: mcp-vf-hosted (Papierkram, TicketPAY, M365).
Anti-Patterns: Auto-Send Mails, Auto-Cancel Rechnungen.
Heute: 2026-05-13.
[DYNAMIC: VF MARKTDATEN]
<Content aus SharePoint /Marktdaten/firma-overview.md>
<Content aus SharePoint /Marktdaten/positionierung.md>
<Content aus SharePoint /Marktdaten/branchen-vokabular.md>
[DYNAMIC: USER-IDENTITAET]
User: Andre Mertens (andre@vibe-factory.de) — GF, lockerer Ton, kurze Antworten.
(oder Christoph: Buchhaltungs-Backoffice, foermlich, detailliert)
[DYNAMIC: AKTUELLE LAGE — optional]
Heutige Calendar-Highlights: <m365_get_today_events()>
Offene Mahnungen: <papierkram_list_invoices_overdue() | count>
Drei moegliche Implementierungs-Wege — vom einfachsten zum saubersten:
Option A — Tool-First (einfach, sichtbar)
Im vf-sonnet Custom Model System-Prompt steht die Anweisung:
Bevor du dem User antwortest, rufe in der allerersten Nachricht der Conversation
vf_get_context()auf. Das gibt dir Marktdaten + User-Identitaet zurueck. Nutze diese Informationen als Grundlage fuer alle weiteren Antworten in dieser Conversation.
Pro: Null Pipeline-Code, nur ein neuer Tool im Mono-MCP.
Con: User sieht den Tool-Call (kleiner UX-Smell), Claude muss sich an die Anweisung erinnern.
Option B — Inlet-Filter (sauber, unsichtbar)
Open WebUI Pipelines (/api/v1/functions/) erlauben Inlet-Filter — Python-Funktionen die den Request-Body vor dem LLM-Call manipulieren koennen. Die Funktion macht einen HTTP-Call an vf-context-Endpoint, holt die Daten, schreibt sie an die richtige Stelle im System-Prompt.
Pro: Komplett unsichtbar fuer den User, deterministisch (immer ausgefuehrt).
Con: Eigenes Funktions-File, eigene Cache-Logik, eigene Fehler-Behandlung.
Option C — Knowledge + Live-Sync (hybrid)
Open WebUI Knowledge-Collection mit den Markdown-Files. Sync-Skript pollt SharePoint alle 5 Min und reindexiert bei Aenderungen.
Pro: Open WebUI-native, RAG-faehig.
Con: NICHT „live” im strengen Sinne (5-Min-Lag), Embedding-Cost, Risiko dass Claude die Files NICHT zieht weil RAG-Retrieval einen falschen Treffer hat.
Empfehlung: Option A erst (1 Tag, sofort live), Option B als Sprint 2b.2 (3 Tage, wenn Option A in der Praxis hakt). Option C nicht — widerspricht dem „Live-Daten, kein Snapshot”-Prinzip.
Aufteilung in Teil-Sprints
| Sprint | Was | Tage | Voraussetzung | Liefert |
|---|---|---|---|---|
| 2a | m365 v0.3: delegated OAuth + 6 Write-Tools | 3 | Azure-Admin-Consent von Andre | Mail-Send, File-Upload, List-Items, Calendar — alles unter User-Identitaet |
| 2b | vf-context Sub-MCP + Dynamic-Prompt-Building | 2-4 | 2a empfohlen (sonst kein clean Read) | Marktdaten + User-Identitaet als Live-Kontext in jeder Conversation |
| 2c | mcp-transcribe-hosted | 2 | unabhaengig | Meeting-Transkripte direkt im Chat (AssemblyAI EU) |
| 2d | mcp-replicate-hosted | 1-2 | unabhaengig | Image-Gen (Flux/SDXL/Recraft) im Chat |
| 2e | VF Skills-Library (6+ Skills) | 3-5 | 2a, 2b ideal | One-Click-Workflows (/mahnung_pruefen, /event_abrechnung, …) |
| Summe | 11-16 |
Reihenfolge im Build: 2a → 2b → 2e ist die kritische Linie (jeder Sprint baut auf dem vorigen). 2c und 2d sind parallel/optional dazwischen einschiebbar wenn ein Bedarfs-Trigger kommt.
Sprint 2a — m365 v0.3 (delegated OAuth + Write-Tools)
Ziel: Jeder VF-User schreibt unter seiner eigenen Identitaet auf SharePoint/Mail/Lists/Calendar. Audit-History zeigt „Andre hat Datei erstellt”, nicht „mcp-vf-hosted Service-Principal”.
Was gebaut wird
| Aenderung | Was konkret |
|---|---|
| Auth-Modell | Service-Principal raus, delegated OAuth pro User. Token persistent in mcp-m365 pro User, refresh-fähig. |
| Azure App-Registration | Permissions als delegated (nicht App-only): Files.ReadWrite.All, Sites.ReadWrite.All, Mail.ReadWrite, Mail.Send, Calendars.ReadWrite, User.Read. Admin-Consent von Andre (VF-Admin) einmalig. |
| Neue Tools | m365_upload_drive_file (binary + text), m365_create_folder, m365_send_email (von der angemeldeten User-Identitaet), m365_create_list_item, m365_update_list_item, m365_create_calendar_event, m365_update_calendar_event |
| Excel-Concurrency | m365_open_workbook_session / m365_close_session — VF-Mitarbeiter und Claude konkurrieren nicht ums selbe Excel |
| Forward-User-Headers | Open WebUI sendet X-OpenWebUI-User-Email an mcp-vf-hosted. m365-Sub-MCP nutzt das als Pivot fuer Per-User-Token-Lookup. |
OAuth-Flow Pro User (Einmalig)
Im Open WebUI Chat-UI:
- User tippt eine Aktion die ein delegated-Tool braucht (z.B. „Sende eine Mail an X”)
- m365-Sub-MCP erkennt: kein Token fuer diesen User. Wirft Tool-Error mit
auth_urlim Body - Claude zeigt die URL als Link. User klickt → Microsoft-Login → Consent → Redirect zu
mcp-vf.agenticventures.de/m365/oauth/callback?state=<user-email-hash> - Callback speichert Token in
mcp-m365-Pro-User-Store (AWS Secrets Manager oder DynamoDB) - User wiederholt die Aktion → klappt jetzt
Wo geht der Token-Store hin?
Heute: lokale Datei in mcp-m365. Fuer hosted Multi-User braucht es persistenten Per-User-Store:
| Option | Pro | Con |
|---|---|---|
| AWS Secrets Manager (eine Secret pro User) | KMS-encrypted, fertig | Cost: 4/Mo |
| DynamoDB (PK=user-email-hash) | $0.25/Mo bei 10 User, einfach | KMS-Encryption muss explizit aktiviert sein |
| EFS-File pro User | $0 zusaetzlich | weniger sauber, kein KMS by-default, kein Audit-Trail |
Empfehlung: DynamoDB mit KMS-CMK-Encryption. Skaliert sauber auf 100+ User, $1-3/Mo realistisch.
Aenderungen im mcp-vf-hosted
In ~/source/mcps/mcp-vf-hosted/ Repo:
src/mcp_vf_hosted/m365_oauth.py— neuer Callback-Handler/m365/oauth/callbacksrc/mcp_vf_hosted/m365_token_store.py— DynamoDB-Adapter mit Encrypt/Decrypt- Sub-MCP-Konfig in
main.py: m365 wird jetzt mitM365_TOKEN_STORE_TABLE=mcp-vf-m365-tokensgestartet - Pro Tool-Call extrahiert m365-Sub-MCP
X-OpenWebUI-User-Email-Header, hashed → DynamoDB-Lookup → Token in den Graph-Call
Aenderungen im mcp-m365 (Source-Repo)
In ~/source/mcps/mcp-m365/:
- Neue Auth-Provider-Klasse
DelegatedOAuthProviderneben dem bestehendenServicePrincipalProvider - Token-Refresh-Logik (MSAL-Python erledigt das, aber Persistenz-Hook brauchen wir)
- 6 neue Tools wie oben — alle nutzen
await get_user_graph_client(user_email)als Helper - Backward-Compat: wenn kein User-Email-Header → fallback auf Service-Principal (fuer Tests + Agents-Plattform-Cron-Routinen die ohne User laufen)
CDK-Stack-Aenderungen
~/source/mcps/mcp-vf-hosted/infra/lib/mcp-vf-hosted-stack.ts:
- Neue DynamoDB-Tabelle
mcp-vf-m365-tokensmitPK=user_email_hash, KMS-CMK - Task-Role bekommt
dynamodb:GetItem/PutItem/UpdateItemauf diese Tabelle - Neue ENV in Container:
M365_TOKEN_STORE_TABLE=mcp-vf-m365-tokens - Cloudflare-Tunnel-Ingress: zusaetzlich
/m365/oauth/callbackdurchroutet auf 8080 (FastMCP hat dann einen FastAPI-Sub-Router fuer den Callback)
Smoke-Test (nach Deploy)
Andre im Chat: „Sende eine Test-Mail an mich (andre@vibe-factory.de) mit Subject 'Sprint 2a live'"
Claude: ruft m365_send_email → 401 weil kein Token → zeigt OAuth-URL
Andre: klickt → MS-Login → Consent → Callback erfolgreich
Claude: retry m365_send_email → 200, Mail kommt an
Andre: prueft in Outlook „Gesendete Elemente" → Mail ist da, From = andre@vibe-factory.de (nicht Service-Principal)
DSGVO
- Pro-User-Token in DynamoDB ist personenbezogen → DSGVO-Cat-A
- AVV mit VF muss „delegated Access zu M365 unter User-Identitaet” explizit listen
- User kann Consent jederzeit widerrufen → mcp-vf-hosted soll Token-Revoke-Endpoint haben (
POST /m365/oauth/revoke?user=...) - Audit-Log pro Tool-Call: User-Email + Tool-Name + Timestamp + Tool-Args (Args ge-hashed bei PII) → CloudWatch
Aufwand: 3 Tage
| Tag | Was |
|---|---|
| 1 | Azure App-Reg + delegated Permissions, MSAL-Python im mcp-m365 implementieren, lokaler Smoke-Test |
| 2 | DynamoDB-Token-Store + Callback-Handler in mcp-vf-hosted, CDK-Aenderung deploy |
| 3 | Open WebUI Custom Model vf-sonnet System-Prompt um delegated-Hinweis ergaenzen, End-to-End-Smoke mit Andre |
Sprint 2b — vf-context Sub-MCP + Dynamic-Prompt-Building
Ziel: Bei jeder neuen Conversation kennt Claude die aktuellen VF-Marktdaten + User-Identitaet. Aenderungen in SharePoint sind binnen Minuten in den Antworten — kein Snapshot.
Architektur
Neuer Sub-MCP im mcp-vf-hosted (Mono-MCP): vf-context.
mcp-vf-hosted (FastMCP v2)
+--- papierkram (existing)
+--- ticketpay (existing)
+--- m365 v0.3 (existing, Sprint 2a)
+--- vf-context (NEU Sprint 2b)
|
+--- get_marktdaten() → liest /Marktdaten/*.md aus SharePoint
+--- get_user_identity() → resolved Forward-User-Email zu Person+Rolle
+--- get_today_briefing() → optional: heutige Termine + offene Posten
Wo liegen die Marktdaten
VF hat den Firmen-Kontext schon — in SharePoint-Ordner /Workshop/ (aus dem Strategie-Workshop 2024/2025 entstanden). Pflegt Andre dort weiter, Single-Source-of-Truth. Kein Inhalts-Setup noetig in Sprint 2b.
Offen (mit Andre klaeren bzw. via m365_search_files checken):
- Welche Files konkret liegen drin (Anzahl, Naming)?
- Format: Word/Excel/Markdown/Mix?
- Falls Word/Excel: brauchen wir Format-Konvertierung (Word → Plaintext via Graph-API ist trivial, Excel → tabellarisch via
m365_read_excel_used_range) - Pflege-Cadence: aktualisiert Andre die Files regelmaessig, oder sind das stabile Workshop-Artefakte?
Workflow im Sub-MCP:
vf_get_context()
→ m365_list_drive_items(path="/Workshop/") # alle Files im Ordner
→ fuer jedes File:
.md → m365_download_file → str-decode
.docx → m365_download_file → Word-Plaintext-Extract (python-docx)
.xlsx → m365_read_excel_used_range # tabellarisch
→ merge → return dict[filename → content]
Tool-Definitionen
# In ~/source/mcps/mcp-vf-hosted/src/mcp_vf_hosted/vf_context.py
@mcp.tool
async def vf_get_context(user_email: str | None = None) -> dict:
"""
Liefert den aktuellen VF-Kontext fuer den System-Prompt-Build.
Nutze diese Funktion AM ANFANG jeder neuen Conversation.
Returns dict mit:
- marktdaten: dict[filename → content]
- user: {email, name, role, tone_preference}
- today: ISO-Date
- last_refresh: ISO-Timestamp
"""
marktdaten = await _load_marktdaten_from_sharepoint()
user = await _resolve_user(user_email)
return {
"marktdaten": marktdaten,
"user": user,
"today": date.today().isoformat(),
"last_refresh": datetime.utcnow().isoformat() + "Z",
}
async def _load_marktdaten_from_sharepoint() -> dict[str, str]:
"""Liest alle .md-Files aus /Allgemein/Marktdaten/ via m365_list_drive_items + m365_download_file"""
# Cache 5 Min in-memory
...Wie kommt das in den System-Prompt?
Variante 1 — Tool-First (Sprint 2b.1, 1-2 Tage)
Im vf-sonnet Custom Model System-Prompt steht:
Du bist Claude fuer Vibe Factory.
WICHTIG — KONTEXT-LADEN: Bei der ersten Nachricht in einer Conversation rufst du
`vf_get_context()` mit der User-Email auf (extrahiere sie aus X-OpenWebUI-User-Email
falls verfuegbar, sonst frag den User). Das gibt dir alle Firmen-Kontext-Daten
zurueck. Bauen diese als impliziten Hintergrund fuer alle weiteren Antworten ein.
Bei jeder neuen Conversation: Tool-Call zuerst, dann Antwort.
Tools: mcp-vf-hosted (Papierkram, TicketPAY, M365 delegated, vf-context).
Heute: {{CURRENT_DATE}}.
Pro: 1-2 Tage Bauzeit. Null Pipeline-Code. Funktioniert sofort.
Con: Andre sieht den Tool-Call (kleiner Smell, aber transparent). Wenn Claude die Anweisung „vergisst” — ueberspringen → fehlender Kontext.
Variante 2 — Inlet-Filter (Sprint 2b.2, +2-3 Tage)
Open WebUI Function als Inlet-Filter. Wird VOR jedem LLM-Call ausgefuehrt, manipuliert den Body:
# Wird in Open WebUI Admin UI → Functions → Add Function eingefuegt
# Type: Filter, Pipeline: vf-sonnet
from pydantic import BaseModel
import httpx, json
class Filter:
class Valves(BaseModel):
MCP_BASE_URL: str = "https://mcp-vf.agenticventures.de"
CACHE_TTL_SECONDS: int = 300
def __init__(self):
self.valves = self.Valves()
self._cache = {}
async def inlet(self, body: dict, user: dict) -> dict:
"""Vor jedem LLM-Call: System-Prompt um VF-Kontext erweitern"""
# Nur fuer erste Message in Conversation
if len(body.get("messages", [])) > 1:
return body
# Cache pro User
cache_key = user["email"]
ctx = self._cache.get(cache_key)
if not ctx or _expired(ctx):
ctx = await self._fetch_vf_context(user["email"])
self._cache[cache_key] = ctx
# System-Prompt erweitern
sys_addon = self._render_context(ctx)
body.setdefault("messages", [])
if body["messages"] and body["messages"][0]["role"] == "system":
body["messages"][0]["content"] += "\n\n" + sys_addon
else:
body["messages"].insert(0, {"role": "system", "content": sys_addon})
return bodyPro: Komplett unsichtbar, deterministisch, schick.
Con: Eigene Caching-Logik. Funktionen sind in Open WebUI nicht versioniert wie Code-Repo. Bei Bug schwerer zu debuggen.
Empfehlung: Erst Variante 1 (2 Tage live), dann nach 1-2 Wochen Real-Use entscheiden ob Variante 2 noetig ist. Variante 2 ist eine Optimierung, kein Must-Have.
Cache-Logik
Marktdaten aendern sich selten (Wochen-Rhythmus). 5-Minuten-Cache in-memory ist OK. Beim SharePoint-Pull:
- ETag-basierter Check ob File-Liste sich geaendert hat
- Bei Aenderung: nur die geaenderten Files neu pullen
- Cache-Bust-Endpoint
POST /vf-context/cache-bustfuer manuelle Refreshes
Smoke-Test
Andre: „Wer sind unsere Hauptkundensegmente?"
Claude (Sprint 1): kennt's nicht oder rät
Claude (Sprint 2b): kennt's, weil vf_get_context() bei Conversation-Start die marktdaten/kunden-segmente.md gelesen hat
Aufwand: 2-4 Tage
| Tag | Was |
|---|---|
| 1 | vf-context Sub-MCP bauen, SharePoint-Read-Logik, 5-Min-Cache |
| 2 | Custom-Model System-Prompt aktualisieren, Smoke-Test mit echtem Markdown-Set |
| 3 (optional) | Inlet-Filter (Variante 2) wenn Variante 1 in Praxis hakt |
| 4 (optional) | Inlet-Filter Hardening + Per-User-Cache |
Sprint 2c — mcp-transcribe-hosted (Meeting-Transkripte)
Ziel: Andre/Christoph zieht Audio/Video-Datei in den Chat, Claude transkribiert mit Speaker-Diarization, gibt Markdown-Protokoll zurueck.
Architektur
Mirror des mcp-vf-hosted-Patterns:
- Eigenes Repo
mcp-transcribe-hosted - Eigener Sub-MCP wrapped
assemblyai-SDK - Eigene Cloudflare-Tunnel + Domain
transcribe.agenticventures.de - Eigene Scalekit-Resource
Provider-Wahl
| Provider | Pro | Con | Cost |
|---|---|---|---|
| AssemblyAI EU | Best Diarization (multi-speaker), EU-Region verfügbar, AVV-fähig | externe US-Firma trotz EU-Region | $0.37/h Audio |
| Groq Whisper-Large-v3 | Schon im LiteLLM eingebunden (Sprint 1 STT) | KEINE Diarization (Single-Stream-only), USA | $0.04/h Audio |
| OpenAI Whisper API | Solide, USA | KEINE Diarization | $0.36/h Audio |
| Self-hosted WhisperX + pyannote | volle Kontrolle, EU-im-eigenen-Stack | GPU-Inferenz teuer (~250 €/Mo Fargate-GPU), Wartungsaufwand | Bauzeit ++ |
Empfehlung: AssemblyAI EU als Default. Diarization ist der zentrale Mehrwert (Andre + Christoph + Kunde = 3 Sprecher unterscheiden zu koennen ist kritisch). Self-hosted nur wenn Kunde explizit „kein US-Vendor” verlangt (Becker-Klasse).
Tools im mcp-transcribe-hosted
transcribe_from_url(audio_url: str, diarization: bool = True, language: str = "de") → {transcript, speakers, srt}
transcribe_from_drive_item(drive_item_id: str, ...) → ruft m365_download_file intern, dann transcribe_from_url
list_recent_transcripts(limit: int = 10) → cached Recent-List (DynamoDB)
Speziell: transcribe_from_drive_item ist der UX-Hero — Andre tippt „Transkribiere das Meeting von gestern aus SharePoint /Meetings/2026-05-12-team-call.m4a” — Claude orchestriert m365_search + m365_download + transcribe.
DSGVO
- AssemblyAI EU-Region (Frankfurt) → DSGVO-konform, AVV bestellbar
- Audio-Files: nur kurzfristig in S3 (eu-central-1, KMS) zwischengespeichert, gelöscht nach 24h via Lifecycle-Rule
- Transcripts: in DynamoDB pro User-Hash, Lifecycle 30d
- Subprocessor-Liste VF um „AssemblyAI Inc (EU-Region)” erweitern
Aufwand: 2 Tage
| Tag | Was |
|---|---|
| 1 | Repo + FastMCP-Wrapper + AssemblyAI-SDK + lokaler Smoke |
| 2 | CDK-Deploy + Cloudflare-Tunnel + Scalekit-Resource + Open WebUI MCP-Server-Add |
Wann lohnt sich das
Wenn Andre 2+ Meetings/Woche transkribieren will. Sonst zuerst groq-whisper-via-litellm als billige Single-Stream-Loesung im Open WebUI nutzen (kein neuer MCP noetig, nur OpenAI-Compat-Audio-Endpoint im LiteLLM).
Sprint 2d — mcp-replicate-hosted (Image-Gen)
Schon detailliert geplant in sprint-2-replicate-hosted. Pattern identisch zu mcp-vf-hosted, eigene Tunnel/Scalekit-Resource, Bridge zu Replicate REST API.
Trigger: Wenn VF konkret Image-Gen-Bedarf hat (Event-Plakate, Marketing-Visuals, Social-Posts).
Bonus durch Sprint 2a: Nach Image-Gen kann Claude direkt m365_upload_drive_file aufrufen und das generierte Bild als PNG in den richtigen SharePoint-Event-Ordner ablegen. End-to-End: „Erstelle ein Wein-Tasting-Poster und leg’s in den Event-Folder 2026-08-12-wine-event” → Bild generiert, Drive-Upload, Link zurueck.
Aufwand: 1-2 Tage.
Sprint 2e — VF Skills-Library
Ziel: Wiederkehrende Workflows sind One-Click via /-Slash-Commands.
Welche Skills
Aus sprint-roadmap-ai-native-office uebernommen + verfeinert:
| Skill | Was | Voraussetzungen |
|---|---|---|
/mahnung_pruefen | papierkram_list_invoices(overdue) → m365_get_template → m365_create_email_draft pro Rechnung. Kein Auto-Send. | 2a (m365 send_email) + 2b (vf-context fuer Briefing-Templates) |
/event_abrechnung <event_id> | ticketpay_list_tickets+transactions+fees → papierkram_create_invoice → m365_upload_drive_file mit PDF | 2a |
/monatsabschluss <YYYY-MM> | Papierkram+TicketPAY aggregiert → SharePoint-Folder „Buchhaltung/Monatsabschluesse/“ | 2a |
/wochenreport | Aggregat → m365_create_email_draft an Andre | 2a |
/event_planung <name> <datum> | SharePoint-Folder anlegen, Templates kopieren, Calendar-Event, TicketPAY-Vorbereitung | 2a |
/kunden_brief <kunde> <thema> | papierkram_get_company + m365_search_messages + Brief-Draft | 2a |
/transkript_meeting <date> | m365_search_files(audio) → mcp-transcribe → SharePoint-Upload + Mail-Summary | 2a + 2c |
/poster_event <event> | mcp-replicate generate → m365_upload_drive_file in Event-Folder | 2a + 2d |
Wie werden Skills definiert
Open WebUI v0.9.x hat /api/v1/prompts/ (= „Skills”/Slash-Commands). Programmatic-Seeding via:
POST /api/v1/prompts/create
{
"command": "/mahnung_pruefen",
"title": "Mahnungen pruefen",
"content": "Pruefe alle ueberfaelligen Rechnungen aus Papierkram. Fuer jede:\n\n1. papierkram_list_invoices(status=delivered, paid_at=null)\n2. Pro Rechnung: papierkram_get_company(id=invoice.customer_id) → Name\n3. m365_create_email_draft mit Mahnung-Template (siehe /Allgemein/Templates/mahnung.md)\n4. Listen-Ausgabe: Tabelle mit (Kunde, Betrag, Tage-fällig, Draft-erstellt)\n5. KEIN Auto-Send. Andre prüft + sendet manuell.",
"timestamp": 1715587200
}Skill-Library wird in extern/shared/vibe-factory/skills/*.json versioniert committed. Re-Seed bei jeder Onboarding-Refresh moeglich.
Default Prompt Suggestions
Open WebUI hat „Suggestion Tiles” auf dem Leer-Chat-Screen. Per /api/v1/configs/suggestions setzen:
[
{"title": "Mahnungen pruefen", "content": "/mahnung_pruefen"},
{"title": "Event abrechnen", "content": "/event_abrechnung "},
{"title": "Wochenreport erstellen", "content": "/wochenreport"},
{"title": "Meeting transkribieren", "content": "/transkript_meeting "}
]Aufwand: 3-5 Tage
| Tag | Was |
|---|---|
| 1 | Skill-Files schreiben (8 Skills × 30 Min Drafting) |
| 2 | Skill-Seeding-Skript bauen + lokal testen |
| 3 | Production-Seed + Smoke pro Skill mit Andre |
| 4-5 | Iteration: Andre nutzt eine Woche, Marvin pflegt nach + ergaenzt fehlende Bausteine |
Reihenfolge + Timeline-Vorschlag
Woche 1 (12.-18. Mai):
Tag 1-2: Plan + Marvin-Andre-Sync zu Marktdaten-Inhalt (was liegt wo)
Tag 3-5: Sprint 2a (m365 v0.3 delegated OAuth + Write-Tools)
Woche 2 (19.-25. Mai):
Tag 1-2: Sprint 2b (vf-context Sub-MCP + Tool-First Dynamic-Prompt)
Tag 3: Marvin + Andre + Christoph 1h Workshop: was sind die ECHTEN Pain-Skills?
Tag 4-5: Sprint 2e Start (3-4 Top-Skills bauen)
Woche 3 (26.-31. Mai):
Tag 1-2: Sprint 2e Iteration + Restliche Skills
Tag 3-4: Sprint 2c oder 2d (je nach Bedarfs-Trigger von Andre)
Tag 5: Hardening, Doku-Refresh, AVV-Update
Sunset-Review (vor 2026-08-31): wie laueft's?
Pro-Sprint-Pause nach 2a, 2b, 2e: eine Woche Real-Use bevor naechster Sprint startet — sonst bauen wir ins Leere.
Was zuerst NICHT bauen
Aus dem urspruenglichen Sprint-Plan bewusst rausgeschoben:
- Sprint 4 Scheduled Automations (Mahnungs-Cron) — nur sinnvoll wenn
/mahnung_pruefenmanual-mode 2 Wochen problemlos laeuft - Sprint 4 Memories — Open WebUI’s
/api/v1/memories/braucht eigene Onboarding-Logik mit Andre, Risiko von Memory-Bloat - Sprint 4 Channels (Slack-style) — Open WebUI hat das, aber VF hat es nicht angefordert
- Sprint 5 SCIM — erst sinnvoll bei 5+ Usern
Cost-Implikation
| Sprint | Setup-Tage | Recurring +€/Mo (Hosting) | Cost-Pass-Through-Risk |
|---|---|---|---|
| 2a (m365 v0.3) | 3 | +1 € (DynamoDB-Tokens) | 0 |
| 2b (vf-context) | 2-4 | 0 € | +0.5 € (mehr Bedrock-Tokens pro Conv-Start) |
| 2c (mcp-transcribe-hosted) | 2 | +33 € | AssemblyAI: $0.37/h × Andre’s-Stunden |
| 2d (mcp-replicate-hosted) | 1-2 | +33 € | Replicate: $0.04-0.40/Bild |
| 2e (Skills-Library) | 3-5 | 0 € | +5-20 €/Mo (mehr Bedrock-Tokens durch Skills-Adoption) |
| Total | 11-16 | +67 €/Mo fix + Variable |
Bei den Self-Cost-Konditionen fuer VF wird Sprint 2c+2d Recurring (+66 €/Mo) mit Andre besprochen — nicht stillschweigend zum Self-Cost-Pricing dazuaddieren. Wenn Andre Image-Gen + Transcribe will: Konditionen anpassen oder Bedrock-Pass-Through-Klausel erweitern auf alle „neuen MCP-API-Cost”.
Sprint 2a + 2b + 2e (die Kern-Linie) erhoehen das Recurring fast nicht — die kann VF zum heutigen Self-Cost-Tarif bekommen.
DSGVO + AVV-Anpassungen
Pro Teil-Sprint:
| Sprint | DSGVO-Anpassung |
|---|---|
| 2a | AVV-Addendum: „delegated M365-Access pro User mit Token-Persistenz in AWS DynamoDB (KMS-CMK, eu-central-1)“. Microsoft GDPR-Schirm gilt. User kann Consent jederzeit widerrufen. |
| 2b | AVV: SharePoint-Files /Marktdaten/* werden in Memory-Cache (5 Min) gehalten. Kein Persistenz-Pfad ausser CloudWatch-Logs. |
| 2c | Subprocessor-Liste: AssemblyAI Inc. (EU-Region). AVV mit AssemblyAI einholen. Audio-Files 24h-Lifecycle in S3. |
| 2d | Subprocessor-Liste: Replicate Inc.. AVV einholen. Spending-Limit setzen. |
| 2e | Skills-Library im Vault dokumentiert → erfuellt EU-AI-Act-„transparente AI-Systeme”-Anforderung. |
Komplette AVV-Refresh nach 2a + 2c + 2d (= alle neuen Subprozessoren auf einmal) statt drei einzelne Updates.
Open Decisions vor Build-Start
| Decision | Optionen | Wann gebraucht |
|---|---|---|
| Token-Store DynamoDB vs Secrets Manager | DynamoDB (skaliert) | vor Sprint 2a Tag 2 |
| Marktdaten-Pfad in SharePoint | geklaert: /Workshop/ (Workshop-Artefakte). Format-Check (Word/Excel/MD-Mix) noch offen — via m365_search vor Sprint 2b Tag 1 | bei Sprint 2b Kickoff |
| Dynamic-Prompt Tool-First vs Inlet | Tool-First default, eskalieren wenn noetig | im Sprint 2b |
| Transcribe-Provider AssemblyAI vs Self-host | AssemblyAI default | vor Sprint 2c Tag 1 |
| Skills-Auswahl 1.0 | Marvin + Andre Workshop nach 2a+2b | vor Sprint 2e |
| Wer zahlt AssemblyAI/Replicate? | Pass-Through an VF (mit Spending-Limit-Schutz) | wenn 2c/2d ansteht |
Erfolgs-Kriterien
Sprint 2 als Ganzes ist „erfolgreich” wenn:
- Andre kann eine Mail im VF-Namen senden via Claude (Sprint 2a Smoke)
- Claude kennt Andre’s Rolle + VF-Marktdaten ohne dass Andre’s das jedes Mal erklaerent (Sprint 2b)
- Andre nutzt mind. 2 Skills regelmaessig (Sprint 2e Real-Use)
- Sunset-Review-Gespraech (vor 2026-08-31) zeigt: VF will weitermachen, Konditionen tragen
Wenn 1-3 nach 6 Wochen Real-Use erfuellt sind: erfolgreicher Pilot, Migration auf Custom-Tier-Standard kann eingeleitet werden.
Cross-Refs
- _index — Open WebUI VF Projekt
- sprint-roadmap-ai-native-office — ursprueglicher Sprint-Plan (jetzt teilweise hier verfeinert)
- sprint-2-replicate-hosted — detailliertes Replicate-Sprint-Plan
- mcp-vf-hosted — Mono-MCP Repo + Stack
- open-webui-vf — Live-Capability
- open-webui-fargate-bedrock — Pattern
- sonder-konditionen-kunden — VF Self-Cost-Klauseln (gelten weiter, Anpassung bei +2c/+2d Bedarf)
- _index — Sprint 1 Run-Akte