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:

  1. 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.
  2. 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

SprintWasTageVoraussetzungLiefert
2am365 v0.3: delegated OAuth + 6 Write-Tools3Azure-Admin-Consent von AndreMail-Send, File-Upload, List-Items, Calendar — alles unter User-Identitaet
2bvf-context Sub-MCP + Dynamic-Prompt-Building2-42a empfohlen (sonst kein clean Read)Marktdaten + User-Identitaet als Live-Kontext in jeder Conversation
2cmcp-transcribe-hosted2unabhaengigMeeting-Transkripte direkt im Chat (AssemblyAI EU)
2dmcp-replicate-hosted1-2unabhaengigImage-Gen (Flux/SDXL/Recraft) im Chat
2eVF Skills-Library (6+ Skills)3-52a, 2b idealOne-Click-Workflows (/mahnung_pruefen, /event_abrechnung, …)
Summe11-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

AenderungWas konkret
Auth-ModellService-Principal raus, delegated OAuth pro User. Token persistent in mcp-m365 pro User, refresh-fähig.
Azure App-RegistrationPermissions 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 Toolsm365_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-Concurrencym365_open_workbook_session / m365_close_session — VF-Mitarbeiter und Claude konkurrieren nicht ums selbe Excel
Forward-User-HeadersOpen 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:

  1. User tippt eine Aktion die ein delegated-Tool braucht (z.B. „Sende eine Mail an X”)
  2. m365-Sub-MCP erkennt: kein Token fuer diesen User. Wirft Tool-Error mit auth_url im Body
  3. Claude zeigt die URL als Link. User klickt → Microsoft-Login → Consent → Redirect zu mcp-vf.agenticventures.de/m365/oauth/callback?state=<user-email-hash>
  4. Callback speichert Token in mcp-m365-Pro-User-Store (AWS Secrets Manager oder DynamoDB)
  5. 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:

OptionProCon
AWS Secrets Manager (eine Secret pro User)KMS-encrypted, fertigCost: 4/Mo
DynamoDB (PK=user-email-hash)$0.25/Mo bei 10 User, einfachKMS-Encryption muss explizit aktiviert sein
EFS-File pro User$0 zusaetzlichweniger 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:

  1. src/mcp_vf_hosted/m365_oauth.py — neuer Callback-Handler /m365/oauth/callback
  2. src/mcp_vf_hosted/m365_token_store.py — DynamoDB-Adapter mit Encrypt/Decrypt
  3. Sub-MCP-Konfig in main.py: m365 wird jetzt mit M365_TOKEN_STORE_TABLE=mcp-vf-m365-tokens gestartet
  4. 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/:

  1. Neue Auth-Provider-Klasse DelegatedOAuthProvider neben dem bestehenden ServicePrincipalProvider
  2. Token-Refresh-Logik (MSAL-Python erledigt das, aber Persistenz-Hook brauchen wir)
  3. 6 neue Tools wie oben — alle nutzen await get_user_graph_client(user_email) als Helper
  4. 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:

  1. Neue DynamoDB-Tabelle mcp-vf-m365-tokens mit PK=user_email_hash, KMS-CMK
  2. Task-Role bekommt dynamodb:GetItem/PutItem/UpdateItem auf diese Tabelle
  3. Neue ENV in Container: M365_TOKEN_STORE_TABLE=mcp-vf-m365-tokens
  4. Cloudflare-Tunnel-Ingress: zusaetzlich /m365/oauth/callback durchroutet 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

TagWas
1Azure App-Reg + delegated Permissions, MSAL-Python im mcp-m365 implementieren, lokaler Smoke-Test
2DynamoDB-Token-Store + Callback-Handler in mcp-vf-hosted, CDK-Aenderung deploy
3Open 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 body

Pro: 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-bust fuer 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

TagWas
1vf-context Sub-MCP bauen, SharePoint-Read-Logik, 5-Min-Cache
2Custom-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

ProviderProConCost
AssemblyAI EUBest Diarization (multi-speaker), EU-Region verfügbar, AVV-fähigexterne US-Firma trotz EU-Region$0.37/h Audio
Groq Whisper-Large-v3Schon im LiteLLM eingebunden (Sprint 1 STT)KEINE Diarization (Single-Stream-only), USA$0.04/h Audio
OpenAI Whisper APISolide, USAKEINE Diarization$0.36/h Audio
Self-hosted WhisperX + pyannotevolle Kontrolle, EU-im-eigenen-StackGPU-Inferenz teuer (~250 €/Mo Fargate-GPU), WartungsaufwandBauzeit ++

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

TagWas
1Repo + FastMCP-Wrapper + AssemblyAI-SDK + lokaler Smoke
2CDK-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:

SkillWasVoraussetzungen
/mahnung_pruefenpapierkram_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 PDF2a
/monatsabschluss <YYYY-MM>Papierkram+TicketPAY aggregiert → SharePoint-Folder „Buchhaltung/Monatsabschluesse/“2a
/wochenreportAggregat → m365_create_email_draft an Andre2a
/event_planung <name> <datum>SharePoint-Folder anlegen, Templates kopieren, Calendar-Event, TicketPAY-Vorbereitung2a
/kunden_brief <kunde> <thema>papierkram_get_company + m365_search_messages + Brief-Draft2a
/transkript_meeting <date>m365_search_files(audio) → mcp-transcribe → SharePoint-Upload + Mail-Summary2a + 2c
/poster_event <event>mcp-replicate generate → m365_upload_drive_file in Event-Folder2a + 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

TagWas
1Skill-Files schreiben (8 Skills × 30 Min Drafting)
2Skill-Seeding-Skript bauen + lokal testen
3Production-Seed + Smoke pro Skill mit Andre
4-5Iteration: 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_pruefen manual-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

SprintSetup-TageRecurring +€/Mo (Hosting)Cost-Pass-Through-Risk
2a (m365 v0.3)3+1 € (DynamoDB-Tokens)0
2b (vf-context)2-40 €+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-50 €+5-20 €/Mo (mehr Bedrock-Tokens durch Skills-Adoption)
Total11-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:

SprintDSGVO-Anpassung
2aAVV-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.
2bAVV: SharePoint-Files /Marktdaten/* werden in Memory-Cache (5 Min) gehalten. Kein Persistenz-Pfad ausser CloudWatch-Logs.
2cSubprocessor-Liste: AssemblyAI Inc. (EU-Region). AVV mit AssemblyAI einholen. Audio-Files 24h-Lifecycle in S3.
2dSubprocessor-Liste: Replicate Inc.. AVV einholen. Spending-Limit setzen.
2eSkills-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

DecisionOptionenWann gebraucht
Token-Store DynamoDB vs Secrets ManagerDynamoDB (skaliert)vor Sprint 2a Tag 2
Marktdaten-Pfad in SharePointgeklaert: /Workshop/ (Workshop-Artefakte). Format-Check (Word/Excel/MD-Mix) noch offen — via m365_search vor Sprint 2b Tag 1bei Sprint 2b Kickoff
Dynamic-Prompt Tool-First vs InletTool-First default, eskalieren wenn noetigim Sprint 2b
Transcribe-Provider AssemblyAI vs Self-hostAssemblyAI defaultvor Sprint 2c Tag 1
Skills-Auswahl 1.0Marvin + Andre Workshop nach 2a+2bvor 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:

  1. Andre kann eine Mail im VF-Namen senden via Claude (Sprint 2a Smoke)
  2. Claude kennt Andre’s Rolle + VF-Marktdaten ohne dass Andre’s das jedes Mal erklaerent (Sprint 2b)
  3. Andre nutzt mind. 2 Skills regelmaessig (Sprint 2e Real-Use)
  4. 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