Agent-Cockpit — Implementations-Plan

Overview

Marvin springt parallel zwischen 5-6 Coding-Chats und verliert beim Switch den Kontext. Aktuelle Antworten sind zu lang, zu tech-zentriert. Lösung: pro aktivem Projekt eine state.md die der Agent nach jeder Phase pflegt. Das bestehende projekt-dashboard (Next.js 16, av-cockpit-Repo) rendert sie als Cockpit-Karte auf /projekte/[slug] plus /cockpit-Übersichtsseite mit allen aktiven Projekten gleichzeitig. CLAUDE.md-Rules zwingen Antworten auf 3 Zeilen + Link und Agent in Tech-Lead-Persona. Live-Sync via S3-JSON-Push + SWR-Polling (Sub-10s-Frische, quasi-Kostenfrei auf bestehender Infra). Optional: project-diagram Skill als Schwester von SKILL für visuelle Architektur-Snapshots.

Pivot-These: Chat-Output ist flüchtig. Source of Truth lebt im Vault, sichtbar via Dashboard. Der Chat wird zur Steuer-Schicht, nicht zum Status-Speicher.

Live-These: state.md im Vault bleibt Source of Truth. Push-Script spiegelt sie als JSON nach S3 (bestehender av-dashboard-data-Bucket). Frontend pollt mit SWR. Keine neue Infra, keine WebSockets, keine SSR-Umstellung.

Problem Frame

Heute:                          Ziel:

┌─────────────┐                ┌─────────────────────────┐
│ Chat 1 ████ │  ← scrollen    │  Cockpit (Dashboard)    │
│ Chat 2 ████ │  ← scrollen    │  ┌───────────────────┐  │
│ Chat 3 ████ │  ← scrollen    │  │ Phase ●→●→○→○→○   │  │
│ Chat 4 ████ │  ← scrollen    │  │ Letzte: ...       │  │
│ Chat 5 ████ │  ← suchen      │  │ Nächste: ...      │  │
└─────────────┘                │  └───────────────────┘  │
                               └─────────────────────────┘
Status = im Chat verstreut     Status = ein Ort, immer aktuell
Antwort lang + tech-tief       Antwort 3 Zeilen + Link

Requirements Trace

  • R1 Pro aktivem Projekt eine state.md mit Phasenpfeil, letzter Entscheidung, nächster Frage, Decisions-Log
  • R2 Agent updated state.md nach jeder Coding-Pipeline-Phase (Rule 21 erweitert)
  • R3 Bestehendes Dashboard rendert state.md als Cockpit-Karte auf /projekte/[slug]
  • R4 Chat-Antworten in Coding-Sessions standardmäßig auf 3 Zeilen + Link begrenzt
  • R5 Persona-Switch: Agent reportet als Tech-Lead an Marvin (Direktor), nicht Pair-Programmer
  • R6 Modi-Override: „geh tief” deaktiviert die Kürze für nächste Antwort
  • R7 state.md ist human-readable Markdown — Marvin liest sie direkt auch ohne Dashboard
  • R8 Architektur-Snapshot pro Projekt visuell verfügbar (Schwester-Skill project-diagram)
  • R9 /cockpit-Übersichtsseite zeigt alle aktiven Projekte mit Cockpit-Karten gleichzeitig, sortiert nach updated_at DESC
  • R10 Live-Sicht: state.md-Änderung erscheint im Dashboard innerhalb ≤10s (Polling-Intervall) ohne Marvin-Aktion
  • R11 Live-Push läuft auf bestehender Infra ohne neue AWS-Ressource zu provisionieren — Ziel-Kosten <$1/Monat zusätzlich

Scope Boundaries

Im Scope:

  • Schema-Definition state.md + Pilot in 2 aktiven Projekten
  • Dashboard-Detail-Route /projekte/[slug] mit Cockpit-Karte (war eh schon offen, siehe _index Offene Baustelle #2)
  • /cockpit-Übersichtsseite mit allen aktiven Projekten gleichzeitig
  • CLAUDE.md Rule 23 + 24 + neuer wissen/prozesse/chat-output-disziplin.md
  • Push-Script push-state.mjs (lokal, AWS SDK) → S3-JSON-Sync
  • <LiveCockpit /> Client-Component mit SWR-Polling + Page-Visibility + ETag-Conditional-Requests
  • CloudFront-Cache-Config für /api/states/* Pfad
  • Schwester-Skill project-diagram von SKILL abgeleitet

Out of Scope:

  • Echte Sub-Sekunde-Live-Updates via SSE/WebSocket (SWR mit 5s Polling reicht)
  • Automatische state.md-Generierung aus Git-History (manuell vom Agent gepflegt, nicht via Cron)
  • Replacement von bestehenden phase-N.md-Files (z.B. bedrock-cost-optimize) — state.md ist Aggregator, nicht Ersatz, verlinkt auf Detail-Files
  • Drag-and-Drop für Cockpit-Karten
  • Dedizierter dashboard-mcp Server (Script reicht; MCP wenn Pattern reift, Welle 2)
  • File-Watcher Daemon — Behavior-Rule 23 + Script-Aufruf nach jedem state.md-Write reicht

Phasen-Overview

flowchart LR
    P1[P1<br/>Schema +<br/>2 Piloten] --> P2[P2<br/>CLAUDE.md<br/>Rules 23+24]
    P2 --> P3[P3<br/>vault.ts<br/>erweitern]
    P3 --> P4[P4<br/>Detail-Route<br/>+ Cockpit-Karte]
    P4 --> P6[P6<br/>/cockpit<br/>Übersicht]
    P6 --> P7[P7<br/>push-state.mjs<br/>+ Rule-Update]
    P7 --> P8[P8<br/>LiveCockpit<br/>SWR Client]
    P8 --> P9[P9<br/>CloudFront<br/>Cache-Config]
    P9 --> P5[P5<br/>project-diagram<br/>optional]

Reihenfolge-Begründung:

  1. P1-P2: Schema + Rules zuerst — damit erste state.md-Files entstehen
  2. P3-P4: Reader + Detail-Karte — statisches Rendering läuft, validiert Schema
  3. P6: Übersichtsseite — alle Karten gestapelt, immer noch statisch (Build-Time)
  4. P7-P9: Live-Schicht obendrauf — Push-Script, Client-Polling, Cache-Config. Genau am Ende, wie Marvin gesagt hat: „step by step und dann ganz am Ende das API Root”.
  5. P5: project-diagram Bonus, parallel oder später

Zeit grob:

  • P1+P2 = ~1.5h (Schema + Rules)
  • P3+P4 = ~3-4h (Code in av-cockpit, Detail-Route)
  • P6 = ~2h (Übersichtsseite)
  • P7 = ~1h (Push-Script + AWS SDK)
  • P8 = ~2h (SWR Client mit Page-Visibility + ETag)
  • P9 = ~30min (CloudFront-Behavior + Cache-Headers)
  • P5 = ~1-2h (Skill-Fork, optional)

Total ~10-13h (ohne P5 ~9-11h).

Context & Research

Relevant Code

  • vault.ts — Vault-Bridge im av-cockpit Repo. loadProjects() liest intern/projekte/*/_index.md via gray-matter. Erweitern um loadProjectState(slug).
  • page.tsx — Kanban-Übersicht mit PipelineCard. Karten verlinken auf /projekte/[slug] (neu).
  • schemas.md §5.5 — bestehendes Project-Schema. Ergänzen um Abschnitt 5.X State.
  • SKILL.md — Blaupause für project-diagram. 4 feste Sektionen, Excalidraw + SVG + HTML, inkrementelles Update bei Re-Run.
  • render.mjs — Render-Pipeline wiederverwendbar.
  • CLAUDE.md Rule 9 + 15 + 21 — Bestehende Format-/Phasen-Rules. Neue Rules ordnen sich daneben ein.

Existing State-Pattern (heute)

  • bas-twin/_index.md Frontmatter: phase: sprint-1, kanban_phase: vertrag, ball_bei: kunde, next_step: "..." — gut für Übersichts-Liste, zu flach für Cockpit-Tiefe.
  • bedrock-cost-optimize/ hat 6 phase-N-*.md-Files plus plan.mdzu granular für Schnellblick, kein einheitlicher Status-Anker.
  • openwebui-vf/ hat 20+ Files (Sprint-Spec, Session-Prompts, Welle-1-4-Docs) — schwer zu navigieren ohne Cockpit.

Lücke: Es gibt keinen einheitlichen „wo stehen wir gerade”-File. state.md schließt sie.

Institutional Learnings

  • ADHS-Pattern (siehe marvin-profile): visueller Typ, lange Listen erzeugen Paralysis. Cockpit zeigt nur 5 Felder, nicht 20.
  • Rule 9 (Ein-Schritt-Prinzip): „nächste Frage” auf der Karte ist genau dieser eine Schritt.
  • Rule 21 (phasenbewusst): jede Coding-Phase bekommt ein Update.
  • Reference, don’t duplicate (Rule 3): state.md verlinkt auf plan.md und phase-N.md, repliziert nicht.

Key Technical Decisions

EntscheidungBegründung
state.md separates File, nicht im _index.md_index.md-Frontmatter ist stabil (Schema 5.5, dashboard-managed Felder). State ist flüchtig und dürftig zu mergen. Trennung verhindert Frontmatter-Bloat.
Markdown-Body mit ## Sektionen, nicht reines YAMLMarvin liest direkt ohne Dashboard. Sektion-Splitter im Parser ist trivial.
Phasenpfeil als Frontmatter-Liste + Marker-MappingYAML-Array phases: [{name, status}] ist trivial zu rendern. Markdown-Body kann Phasen-Detail haben.
loadProjectState(slug) erweitert vault.ts, kein neues PackageBestehender Pattern, kein neuer Loader-Layer.
Behavior-Rule 23+24 statt 1 große RulePflege (23) und Output-Format (24) sind orthogonal. Override-Switch klarer pro Rule.
project-diagram als eigener Skill, nicht customer-diagram-ErweiterungAndere 4 Sektionen, andere Trigger-Phrasen. Cleaner als Mode-Parameter.
Detail-Route nutzt bestehende av-cockpit-Komponenten + RechartsKein neues UI-Framework. Phasenpfeil = horizontaler SVG-Component (~30 Zeilen).

High-Level Technical Design

Directional guidance, nicht Implementation-Spec.

state.md Struktur (Vorschlag)

---
id: state-<projekt-slug>
type: project_state
project: "[[_index]]"
updated_at: 2026-05-21T16:30:00+02:00
mode: coding-pipeline    # coding-pipeline | research | sales | maintenance
phases:
  - { name: "Schema + Piloten", status: done }
  - { name: "CLAUDE.md Rules",  status: active }
  - { name: "vault.ts",         status: todo }
  - { name: "Detail-Route",     status: todo }
  - { name: "project-diagram",  status: todo }
---
 
## Letzte Entscheidung
state.md wird als separates File geführt, nicht in _index.md gemerged. (2026-05-21)
 
## Nächste Frage
Brauchen wir Modi-Switch ("geh tief") als CLAUDE.md-Anweisung oder als
explizites Marvin-Wort?
 
## Decisions-Log
- 2026-05-21 — Markdown-Body statt reines YAML (human-readable)
- 2026-05-21 — Eigener Skill project-diagram statt customer-diagram-Mode
 
## Offene Baustellen
- [[plan-agent-cockpit#open-questions|Open Questions]]

Phasenpfeil-Rendering (Dashboard)

Phase ●━━━●━━━●━━━○━━━○
      Schema  Rules  Reader  Karte  Diagramm
      done   active  todo    todo   todo

Marker-Mapping: done=● active=◐ todo=○. Verbindungen= für abgeschlossene Übergänge, für offene. Horizontal SVG, scrollbar bei >7 Phasen.

Cockpit-Karten-Layout

┌──────────────────────────────────────────────────┐
│ <projekt-name>                       updated 2h  │
│ ●━━━●━━━◐━━━○━━━○                                │
├──────────────────────────────────────────────────┤
│ Letzte Entscheidung:                             │
│   state.md separat, nicht gemerged               │
├──────────────────────────────────────────────────┤
│ Nächste Frage:                                   │
│   Modi-Switch via CLAUDE.md oder Marvin-Wort?    │
├──────────────────────────────────────────────────┤
│ [ Decisions ▾ ]  [ Open Items ▾ ]                │
└──────────────────────────────────────────────────┘

Implementation Units

Unit 1: state.md Schema definieren + 2 Piloten

  • Goal: Stabiles Schema in _meta/schemas.md + 2 reale state.md-Files als Lebendprobe.

Requirements: R1, R7

Files:

  • Modify: _meta/schemas.md (neuer Abschnitt 5.13 oder hinter 5.5)
  • Create: intern/projekte/projekt-dashboard/state.md (Pilot 1, dieses Projekt)
  • Create: intern/projekte/bas-twin/state.md (Pilot 2, aktivstes Kunden-Projekt)

Approach:

  • Schema-Felder: id, type: project_state, project (Wikilink auf _index), updated_at (ISO-8601), mode (enum), phases (Array {name, status})
  • Status-Enum: done | active | todo | blocked
  • Body-Sektionen Pflicht: ## Letzte Entscheidung, ## Nächste Frage, ## Decisions-Log, ## Offene Baustellen
  • Pflege-Regel: updated_at MUSS bei jeder Änderung neu gesetzt werden (von Agent automatisch, von Mensch optional)

Patterns to follow: schemas.md §5.5 Project Frontmatter-Stil.

Verification: gray-matter parsed beide Pilot-Files ohne Fehler. Schema-Dokumentation hat Beispiel.


Unit 2: CLAUDE.md Rules 23+24 + wissen-Eintrag

  • Goal: Pflege-Pflicht + Chat-Format formal verankern.

Requirements: R2, R4, R5, R6

Files:

  • Modify: CLAUDE.md (neue Rules 23 + 24, eingefügt nach Rule 22)
  • Create: intern/wissen/prozesse/chat-output-disziplin.md

Approach:

Rule 23 — state.md pflegen. Bei jeder Coding-Pipeline-Phase (Rule 21) am Ende der Phase die zugehörige intern/projekte/<slug>/state.md aktualisieren: updated_at, betroffene Phase auf nächsten Status, neue Entscheidung in Letzte Entscheidung (alte wandert in Decisions-Log), neue offene Frage in Nächste Frage. Wenn keine state.md existiert und das Projekt aktiv ist: anlegen.

Rule 24 — Chat-Output-Disziplin. Default-Antwort in Coding-Sessions: max 3 Zeilen Text + Link auf state.md oder Cockpit-URL. Persona: Tech-Lead reportet an Direktor (Marvin), nicht Pair-Programmer. Verboten: Pre-Tool-Narration („jetzt mache ich X”), Tool-Output-Echo („gelesen eine Datei”), Code-Snippets ohne Anforderung. Erlaubt: Resultat + Entscheidungsfrage. Override: Wenn Marvin „geh tief”, „erklär”, „zeig Details” sagt → nächste Antwort darf lang + technisch sein, danach zurück auf Default.

chat-output-disziplin.md ergänzt mit:

  • Konkrete Anti-Patterns (Beispiele aus aktuellem Chat-Stil)
  • Beispiel-Antworten: gutes Format vs schlechtes Format side-by-side
  • Wann Rule 24 NICHT gilt (Debug-Session, Brainstorm, Explain-Anfrage)

Verification: Marvin liest die neuen Rules und kann sich darin erkennen. Ein Test-Coding-Chat zeigt deutlich kürzere Antworten.


Unit 3: vault.ts erweitern um loadProjectState

  • Goal: av-cockpit kann state.md lesen.

Requirements: R3

Dependencies: Unit 1 (Schema muss stehen)

Files:

  • Modify: ~/source/av-cockpit/src/lib/vault.ts

Approach:

  • Neue Types: ProjectState, Phase, PhaseStatus
  • Neue Funktion loadProjectState(slug: string): ProjectState | null
    • Liest <VAULT_ROOT>/intern/projekte/<slug>/state.md
    • gray-matter für Frontmatter (phases, updated_at, mode)
    • Body-Parser splittet auf ## -Headings: Letzte Entscheidung, Nächste Frage, Decisions-Log (Liste), Offene Baustellen (Liste)
  • loadProjects() UNVERÄNDERT lassen — state.md ist separat geladen, nicht gemerged
  • Fehlerfall: File existiert nicht → null zurück, kein Throw

Patterns to follow:

  • loadProjects() und loadCustomers() in derselben Datei — selber Style (gray-matter, fs.readFileSync, defensive parsing)
  • toDate, toStringOrUndefined Helpers wiederverwenden

Test scenarios:

  • Happy path: loadProjectState("projekt-dashboard") gibt ProjectState mit 5 Phasen, korrektem updated_at, gefüllten Body-Sektionen
  • Edge case: File existiert nicht → null
  • Edge case: Frontmatter ohne phases → leeres Array, kein Crash
  • Edge case: Body ohne erwartete ##-Headings → leere Strings/Arrays in den Feldern

Verification: Manueller Aufruf im Node-REPL via tsx gibt erwartete Shape für beide Piloten zurück.


Unit 4: /projekte/[slug] Detail-Route + Cockpit-Karte

  • Goal: Dashboard rendert state.md visuell.

Requirements: R3

Dependencies: Unit 3 (vault.ts), Unit 1 (Piloten)

Files:

  • Create: ~/source/av-cockpit/src/app/projekte/[slug]/page.tsx
  • Create: ~/source/av-cockpit/src/components/cockpit-card.tsx
  • Create: ~/source/av-cockpit/src/components/phase-arrow.tsx

Approach:

  • Server Component page.tsx lädt Projekt-Card (über bestehendes loadProjects() + slug-Filter) plus loadProjectState(slug)
  • Layout: Header (Projekt-Name + Frontmatter-Quickdata) → <CockpitCard state={state} /> → Tasks-Liste (aus _index.md) → Decisions-Log einklappbar → Footer mit Links zu plan.md, runbook.md
  • <PhaseArrow phases={state.phases} /> — eigene SVG-Komponente, ~50 Zeilen, kein Recharts (overkill)
  • Markup-Style: konsistent zu bestehender PipelineCard in projekte/page.tsx
  • Wenn state.md fehlt: Empty-State-Karte „Noch kein Cockpit. Anlegen via Agent in der nächsten Coding-Session.”

Patterns to follow:

  • src/app/cloud/page.tsx für Server-Component + Daten-Loading-Pattern
  • src/app/projekte/page.tsx für Card-Styling
  • Vorhandener Prototyp bas-twin-overview.html als visuelles Vorbild

Test scenarios:

  • Happy path: /projekte/projekt-dashboard rendert Cockpit-Karte mit Phasenpfeil, Letzter Entscheidung, Nächster Frage, Decisions-Liste
  • Edge case: /projekte/<slug-ohne-state> zeigt Empty-State, kein Crash
  • Edge case: state.md mit nur 2 Phasen → Pfeil rendert korrekt schmal
  • Edge case: state.md mit 12 Phasen → Pfeil scrolled horizontal, bricht nicht das Layout
  • Mobile: 375px-Viewport zeigt Karte stacked, Pfeil scrolled

Verification: Beide Pilot-Projekte unter localhost:3000/projekte/<slug> zeigen vollständige Cockpit-Karte. Build (next build) wirft keinen Fehler.


Unit 6: /cockpit Übersichtsseite

  • Goal: Eine Seite die alle aktiven Projekte mit Cockpit-Karten gleichzeitig zeigt.

Requirements: R9

Dependencies: Unit 3 (vault.ts mit loadProjectState), Unit 4 (Cockpit-Karte-Komponente existiert)

Files:

  • Create: ~/source/av-cockpit/src/app/cockpit/page.tsx
  • Modify: ~/source/av-cockpit/src/components/sidebar.tsx (Eintrag „Cockpit” oben)

Approach:

  • Server Component lädt alle state.md-Files via neue Helper loadAllProjectStates() in vault.ts
  • Filtert auf Projekte wo _index.md Frontmatter status: active
  • Sortiert nach state.updated_at DESC
  • Rendert vertikal gestapelt <CockpitCard /> Komponenten (Unit 4)
  • Filter-Bar oben: nach mode (coding-pipeline | research | sales | maintenance)
  • Stale-Indikator: wenn updated_at > 7 Tage → grauer Rahmen + Hinweis „letzter Update vor X Tagen”
  • Empty-State: wenn kein Projekt aktiv → „Noch keine aktiven Projekte mit Cockpit”

Patterns to follow:

  • src/app/projekte/page.tsx — Kanban-Layout-Pattern, kann man fast 1:1 adaptieren auf vertikales Stapeln
  • Sidebar-Pattern in src/components/sidebar.tsx

Test scenarios:

  • Happy path: Beide Pilot-Projekte erscheinen auf /cockpit, projekt-dashboard oben (neuester Update)
  • Edge case: Projekt mit status: paused taucht NICHT auf
  • Edge case: Projekt ohne state.md taucht NICHT auf (auch wenn aktiv)
  • Edge case: Alle Projekte stale → Liste zeigt, aber alle mit grauem Rahmen
  • Mobile: Karten stacken sauber auf 375px

Verification: /cockpit lädt unter 1s, zeigt alle Pilot-Karten korrekt sortiert.


Unit 7: push-state.mjs Script + Behavior-Rule-Update

  • Goal: Agent kann state.md-Änderungen 1-Click nach S3 synchronisieren.

Requirements: R10, R11

Dependencies: Unit 1 (Schema), Unit 3 (Parser-Logik kann wiederverwendet werden)

Files:

  • Create: ~/source/av-cockpit/scripts/push-state.mjs
  • Modify: ~/source/av-cockpit/package.json (npm-Skript push-state)
  • Modify: CLAUDE.md (Rule 23 ergänzen um Push-Schritt)
  • Modify: intern/wissen/prozesse/chat-output-disziplin.md (Push-Workflow dokumentieren)

Approach:

  • Script-Signatur: node scripts/push-state.mjs <slug> oder npm run push-state -- <slug>
  • Liest <VAULT_ROOT>/intern/projekte/<slug>/state.md mit gray-matter
  • Parsed Body-Sektionen (gleicher Parser-Code wie in Unit 3, geteilt via src/lib/state-parser.ts)
  • Serialisiert zu JSON-Shape (passt zu <LiveCockpit /> Erwartungen)
  • Diff-Check: lade aktuelle S3-Version (falls existiert), vergleiche Content-Hash → skip wenn identisch
  • AWS SDK v3 (@aws-sdk/client-s3 ist in av-cockpit Repo vermutlich schon drin, sonst install)
  • Auth: AWS-Profile av-production über SSO (Marvin ist sowieso eingeloggt)
  • Target: s3://av-dashboard-data-425924867359/api/states/<slug>.json
  • Content-Type: application/json
  • Cache-Control-Header: public, max-age=10, s-maxage=10 (CloudFront cached 10s)
  • Log: schreibt 1 Zeile in stdout („pushed states/.json (1.2KB)” oder „no change, skipped”)

Behavior-Rule 23 Ergänzung: nach state.md-Write IMMER npm run push-state -- <slug> ausführen. Wenn Push fehlschlägt: Marvin in 1 Zeile informieren, state.md ist trotzdem gespeichert (Vault bleibt SoT).

Patterns to follow:

  • AWS SDK v3 Style in ~/source/agents-platform/lambdas/dashboard-refresh/ (Python, aber gleicher S3-Bucket-Pattern)
  • gray-matter + fs Style in vault.ts

Test scenarios:

  • Happy path: Script läuft mit projekt-dashboard-Slug, pusht JSON nach S3, aws s3 ls zeigt File
  • Happy path: Zweiter Lauf ohne Änderung skipped korrekt
  • Edge case: state.md fehlt → klare Fehlermeldung, Exit 1
  • Edge case: AWS-Profile nicht eingeloggt → klare Fehlermeldung mit Hinweis aws sso login --profile av-production
  • Edge case: Slug existiert nicht in intern/projekte/ → Fehler mit verfügbaren Slugs
  • Edge case: state.md mit Schema-Fehler (z.B. ungültige Phase) → Validierungs-Fehler vor Push

Verification: aws s3 cp s3://av-dashboard-data-425924867359/api/states/projekt-dashboard.json - zeigt valide JSON-Struktur. CloudFront-URL https://dashboard.agenticventures.de/api/states/projekt-dashboard.json antwortet 200 mit korrekten Cache-Headers.


Unit 8: <LiveCockpit /> Client-Component mit SWR

  • Goal: Dashboard zeigt state-Änderungen ohne Page-Reload.

Requirements: R10

Dependencies: Unit 4 (<CockpitCard /> existiert), Unit 7 (S3-JSON-Endpoints existieren)

Files:

  • Create: ~/source/av-cockpit/src/components/live-cockpit.tsx ("use client")
  • Modify: ~/source/av-cockpit/src/app/projekte/[slug]/page.tsx (Server Component lädt initialen state, übergibt an <LiveCockpit initial={...} />)
  • Modify: ~/source/av-cockpit/src/app/cockpit/page.tsx (gleiche Hydration für Übersichtsseite)

Approach:

  • Server Component lädt state aus Vault (Build-Time, statisch)
  • Übergibt als initial-Prop an <LiveCockpit slug={slug} initial={state} />
  • Client Component mit SWR:
    useSWR(`/api/states/${slug}.json`, fetcher, {
      refreshInterval: 5000,
      revalidateOnFocus: true,
      fallbackData: initial,
    })
    
  • Fetcher mit ETag-Conditional: sendet If-None-Match mit letztem ETag, behandelt 304 als „kein Update”
  • Page-Visibility-API: document.hidden → SWR refreshInterval auf 0 (pausieren), bei Visibility-Change zurück auf 5000
  • Visual Indicator: kleiner grüner Pulse-Dot wenn frisch (<10s), grauer Dot wenn stale (>5min)
  • Fallback wenn fetch fehlschlägt: zeigt initial-Daten + Hinweis „letzter Sync:

Patterns to follow:

  • SWR-Setup wie in ~/source/av-cockpit/src/app/cloud/page.tsx (existing SWR-Usage)
  • Page-Visibility-Pattern: useEffect mit visibilitychange-Listener

Test scenarios:

  • Happy path: state.md auf Maschine ändern + push-state.mjs laufen → Dashboard updated innerhalb 10s ohne Page-Reload
  • Edge case: Browser-Tab nicht sichtbar → keine Network-Requests (Page-Visibility)
  • Edge case: S3 offline / 503 → Dashboard zeigt letzten Stand + „Sync-Fehler”
  • Edge case: ETag-304 → SWR behandelt als „kein Update”, kein Re-Render
  • Edge case: Initial-State leer (null) → Empty-State angezeigt, kein Crash

Verification: Marvin ändert eine state.md in Coding-Session, push-state.mjs läuft, Dashboard zeigt innerhalb 10s den neuen Stand ohne F5.


Unit 9: CloudFront-Cache-Config + S3-CORS

  • Goal: Live-Endpoints sind günstig + responsive cached.

Requirements: R11

Dependencies: Unit 7 (Endpoints existieren), Unit 8 (Frontend will sie lesen)

Files:

  • Modify: CloudFront-Distribution E3KFMPWSKO68UU (via AWS Console oder aws cloudfront update-distribution)
  • Modify: S3-Bucket-Policy av-dashboard-data-425924867359 (CORS-Config falls nicht schon korrekt)
  • Document: intern/projekte/projekt-dashboard/runbook.md (neuer Abschnitt „Live-State CloudFront-Behavior”)

Approach:

  • Neue CloudFront-Behavior für Path-Pattern /api/states/*:
    • Origin: S3-Bucket av-dashboard-data-425924867359
    • Allowed Methods: GET, HEAD, OPTIONS
    • Cached Methods: GET, HEAD
    • Cache Policy: Custom „LiveState” mit Min TTL: 0, Default TTL: 10, Max TTL: 30
    • Compress: Yes (gzip JSON)
    • Forward Headers: Origin, Access-Control-Request-Method
  • S3-CORS-Rule auf Bucket (falls noch nicht für /api/data/* gesetzt — vermutlich schon vorhanden):
    { "AllowedOrigins": ["https://dashboard.agenticventures.de"],
      "AllowedMethods": ["GET", "HEAD"],
      "AllowedHeaders": ["If-None-Match"],
      "ExposeHeaders": ["ETag"] }
  • Smoke-Test: curl -I https://dashboard.agenticventures.de/api/states/projekt-dashboard.json zeigt cache-control: public, max-age=10 + ETag

Patterns to follow:

  • Bestehende CloudFront-Behavior für /api/data/* (für aws-costs.json etc.) — neue Behavior wird nach Vorbild dieser angelegt
  • Runbook-Style in ~/source/av-cockpit/RUNBOOK.md (falls existiert) oder intern/projekte/projekt-dashboard/runbook.md

Test scenarios:

  • Happy path: 5x in Folge GET, alle nach erstem aus CloudFront-Cache (Header x-cache: Hit from cloudfront)
  • Happy path: nach 11s GET → CloudFront refetches von S3 (x-cache: Miss from cloudfront)
  • Edge case: CORS-Preflight von dashboard.agenticventures.de → 200, access-control-allow-origin korrekt
  • Edge case: GET von fremder Origin → kein CORS-Header (oder explicit denied)

Verification: Manuelle curl-Tests bestätigen Headers. AWS Cost-Explorer zeigt nach 1 Woche < $0.50 Mehrkosten für den State-Path.


Unit 5: project-diagram Skill (optional, Bonus)

  • Goal: Visueller Architektur-Snapshot pro Projekt, wiederverwendet customer-diagram-Pattern.

Requirements: R8

Dependencies: Keine harten (kann separat von Unit 1-4 laufen)

Files:

  • Create: intern/capabilities/skills/project-diagram/SKILL.md
  • Create: intern/capabilities/skills/project-diagram/render.mjs (oder Symlink/Reuse von customer-diagram)
  • Create: assets/firma/project-diagrams/_schema/sections.json (4 Sektionen)
  • Create: assets/firma/project-diagrams/_schema/components.json (Projekt-Komponenten)
  • Create: assets/firma/project-diagrams/_template/project.html
  • Modify: intern/capabilities/skills/_index.md (Eintrag)

Approach:

  • 4 Sektionen (statt customer-diagram-4): Phasen (Phasenpfeil als Excalidraw) / Architektur (Komponenten + Pfeile) / Decisions (Text-Liste, 3 wichtigste) / Risks (Text-Liste)
  • Quelle: intern/projekte/<slug>/state.md + _index.md + ggf. plan.md
  • Output analog customer-diagram: assets/firma/project-diagrams/<slug>.excalidraw + .svg + .html
  • Re-Run-Verhalten: inkrementell wie customer-diagram

Patterns to follow: SKILL.md eins-zu-eins als Schablone.

Verification: project-diagram projekt-dashboard erzeugt 3 Files. HTML öffnet sauber im Browser.


System-Wide Impact

  • CLAUDE.md: zwei neue Rules ändern Default-Verhalten in allen Coding-Sessions. Nicht-Coding-Sessions (Email, Termine, Wiki-Maintenance) bleiben unverändert
  • Vault-Schema: neuer type: project_state ergänzt das Inventar in _meta/schemas.md. Bestehende Project-Files bleiben unverändert
  • av-cockpit Repo: vault.ts wird erweitert, kein bestehendes Verhalten gebrochen. Neue Routen /projekte/[slug] und /cockpit sind additiv. Neuer scripts/push-state.mjs ergänzt bestehende Scripts (build-finanzen.ts, deploy.sh)
  • AWS-Stack: ZERO neue Ressourcen. Wir nutzen bestehenden av-dashboard-data-425924867359 Bucket + bestehende CloudFront-Distribution E3KFMPWSKO68UU (Marvins Account av-production)
  • CloudFront: eine neue Behavior für /api/states/* neben der bestehenden für /api/data/*. Keine Distribution-Neuanlage
  • Skill-Inventar: ein neuer Skill, klar abgegrenzt von customer-diagram
  • Auth: Cloudflare Access für dashboard.agenticventures.de schützt automatisch auch /api/states/*-Pfad — nur Marvin sieht die States
  • Drift-Risiko: state.md-Files werden stale wenn Pflege nicht passiert. Mitigation in Risiken-Tabelle unten

Open Questions

Resolved during planning

  • Wo lebt state.md?intern/projekte/<slug>/state.md (analog _index.md, gleiche Ebene)
  • Mensch- oder Maschinen-Format? → Markdown-Body + YAML-Frontmatter Mix. Marvin liest direkt, Agent parsed.
  • Wer pflegt state.md? → Agent automatisch nach jeder Coding-Pipeline-Phase. Marvin manuell wenn er will.
  • Override für lange Antworten? → Marvin-Wörter „geh tief”, „erklär”, „zeig Details” deaktivieren Rule 24 für nächste Antwort.
  • Schwester-Skill oder customer-diagram-Erweiterung? → Schwester-Skill. Andere Sektionen, andere Trigger.

Deferred to implementation

  • Recharts oder eigener SVG für Phasenpfeil? Entscheide bei Unit 4 — Vermutung: eigener SVG ist leichter (kein Recharts-Overkill für simple Horizontal-Stepper)
  • mode-Enum-Werte (coding-pipeline | research | sales | maintenance) — kann sich beim Pilot-Anlegen noch ändern
  • Wie genau formuliert man Rule 24 ohne Persona-Overkill? → Iterieren beim Schreiben in Unit 2
  • Stale-Detection im Dashboard: ab wann ist state.md veraltet? 7 Tage? 14 Tage? Visualisierung wie? → Entscheide bei Unit 4
  • Kollision mit phase-N.md (z.B. bedrock-cost-optimize): state.md verlinkt auf Detail-Files, ersetzt sie nicht. Konkrete Verlinkung beim Pilot-Anlegen klären.
  • SWR-Polling-Intervall 5s vs 10s: start bei 5s, falls Kosten überraschend hoch oder Browser-Performance leidet → 10s. Entscheide bei Unit 8.
  • Push-Script: AWS-SDK v3 vs aws s3 cp shell-call? SDK v3 ist sauberer (Error-Handling, ETag-Diff) — Entscheide bei Unit 7, default SDK.
  • CloudFront-Cache-Invalidation bei jedem Push? Standardfall: nein (Cache-TTL 10s reicht). Bei kritischen Updates ggf. manuell. Entscheide bei Unit 9.
  • MCP-Wrapper als Welle 2? Bewertung 3 Monate nach Go-Live: macht der Agent mehr mit dem Dashboard als nur push (query, mark-done, list-stale)? Wenn ja → mcp-eigenbau für dashboard-mcp. Wenn nein → Script reicht.

Risks & Dependencies

RisikoMitigation
state.md wird nicht gepflegt — Files veraltenBehavior-Rule 23 macht es Pflicht. Dashboard zeigt „stale” wenn updated_at > 7 Tage. Bei Wiki-Maintenance-Run prüfen.
Rule 24 zu rigid — Marvin kann nicht mehr deep-divenModi-Switch („geh tief”) explizit in Rule. Plus Trigger wie Brainstorm/Reproduce-Bug deaktivieren Default.
Detail-Route ist viel Frontend-ArbeitBestehendes Card-System wiederverwendet. Phasenpfeil als 50-Zeilen-SVG, kein neues Lib.
Markdown-Parser bricht bei abweichenden state.md-FilesSchema-Validierung beim Pilot-Anlegen. Defensive Parsing in vault.ts (null statt Crash).
project-diagram ist Scope-CreepAls Phase 5 / optional markiert. Ohne Phase 5 funktioniert das Cockpit voll.
state.md dupliziert plan.md / phase-N.mdstate.md ist Aggregator (5 Felder). Detail-Files bleiben Source-of-Truth, state.md verlinkt.
Agent vergisst push-state.mjs aufzurufen → Dashboard wird staleRule 23 Pflicht. Script in einem Aufruf mit state.md-Edit kombinieren („nach jedem write: push”). Stale-Indikator im Frontend macht das Problem sichtbar.
Kosten-Surprise durch SWR-PollingPage-Visibility-API + ETag-304-Pattern + CloudFront-Cache (10s TTL) drücken Real-Cost auf <$1/Monat. Monitoring via Cost-Explorer pro Bucket. Bei Drift → Polling-Intervall auf 10s erhöhen.
AWS-SSO-Token abgelaufen → Push-FailPush-Script gibt klaren Hinweis (aws sso login --profile av-production). Vault-File bleibt geschrieben, nur Sync schlägt fehl. Recoverable.
CloudFront-Cache zeigt veraltete DatenTTL 10s ist Maximum-Drift. Bei kritischen Updates: manuell invalidieren (aws cloudfront create-invalidation). Kostet $0.005 pro Invalidation, in Praxis nie nötig.
/api/states/* ohne Auth zugänglichCloudflare Access vor dashboard.agenticventures.de schützt automatisch. Direct-S3-URL bleibt private (Bucket-Policy). Verify in Smoke-Test.

Kosten

Strategie: Komplett auf bestehendem projekt-dashboard-Stack reiten. Keine neue AWS-Ressource, keine neue Domain, kein neuer Auth-Layer.

Bestehende Infra (zahlst du eh, kein Cockpit-Anteil)

RessourceStatus
S3 av-dashboard-data-425924867359existiert (LiveRefreshStack nutzt ihn schon für routines-status.json etc.)
S3 av-dashboard-frontend-425924867359existiert (Static Export)
CloudFront E3KFMPWSKO68UUexistiert (Distribution für dashboard.agenticventures.de)
Cloudflare Access (Auth)existiert (hello@-only, One-time PIN)
Domain dashboard.agenticventures.deexistiert

Cockpit-spezifische Mehrkosten (pro Monat, in EU)

PostenBerechnungKosten
S3 Storage api/states/*30 Projekte × 20KB = 600KB~$0.00
S3 PUT (Pushes)~10 Phasen-Updates/Tag × 30 = 300 PUTs/Monat × $0.005/1000~$0.00
S3 GET (Origin-Fetches durch CF-Misses)bei 10s-Cache ~10% Miss-Rate × ~7000 Polls/Tag × 30~$0.01
CloudFront Requests~7000 GET/Tag × 30 = 210k/Monat (Free Tier deckt 10M ab)$0.00
CloudFront Egress5KB × 210k = 1.05GB × $0.085/GB (EU)~$0.09
Lambdanicht nötig$0.00
Total~$0.10/Monat

Annahmen:

  • Marvin nutzt Dashboard ~2h/Tag (geöffneter Tab)
  • Page-Visibility pausiert Polling wenn Tab nicht aktiv → ~80% Request-Reduktion
  • 5 aktive Projekte parallel auf /cockpit Übersicht
  • ETag-304-Responses reduzieren Egress um ~70% (nur Header, kein Body)

Worst-Case-Szenario

Dashboard 24/7 offen, alle 30 Projekte aktiv, kein Page-Visibility-Pause, 5s-Polling konstant:

  • ~520k Requests/Monat × 3.90/Monat
  • Egress ~2GB × 0.17/Monat
  • Worst-Case ~$4/Monat

Das ist die Obergrenze. Realistisch landen wir bei <$1/Monat.

Kostenoptimierungen die im Plan eingebaut sind

  1. Page-Visibility-API (Unit 8) — Polling pausiert wenn Tab inaktiv
  2. ETag-Conditional-Requests (Unit 8) — 304-Responses sparen Egress
  3. CloudFront-Cache 10s TTL (Unit 9) — verteilt Last vom S3-Origin auf Edge
  4. Diff-Detection im Push (Unit 7) — keine PUTs bei unverändertem Content
  5. Aggressives Compression (Unit 9) — gzip auf JSON spart ~70% Egress

Was wir bewusst NICHT bauen (zu teuer ohne Mehrwert)

  • AWS API Gateway WebSocket ($1/M Messages + Connection-Minutes)
  • DynamoDB State-Store (redundant zu Vault als SoT)
  • Eigenes Lambda für Push (Cold-Start + Invocation-Kosten ohne Nutzen)
  • Cloudflare R2 + Workers KV (anderer Stack, bricht Auth/CDN-Setup)
  • SSE via Next.js Server (bricht Static Export, müsste SSR oder Edge-Function werden)

Monitoring

  • AWS Cost Explorer Tag-Filter: Bucket=av-dashboard-data mit Pfad-Filter api/states/
  • Bei Drift > $2/Monat: Alert via existierendem av-cockpit /cloud-Dashboard
  • Reality-Check nach 30 Tagen Go-Live, dann nach 90 Tagen

Documentation Plan

  • _meta/schemas.md §5.13 — Schema-Doku
  • intern/wissen/prozesse/chat-output-disziplin.md — Rule-24-Hintergrund + Beispiele
  • intern/wissen/prozesse/state-md-pflege.md — Workflow „nach jeder Phase: state.md + push-state.mjs”
  • intern/capabilities/skills/_index.md — project-diagram-Eintrag
  • intern/projekte/projekt-dashboard/_index.md — Offene Baustelle #2 (Detail-Route) als „erledigt” markieren wenn Unit 4 durch
  • intern/projekte/projekt-dashboard/runbook.md — Live-State CloudFront-Behavior + Troubleshooting (Push-Failure, Stale-State, Cache-Invalidation)

Sources & References