# Blueprint: Chat-First Agent-UI

Version 1.0 · denzer.ai · Lizenz: frei nutzbar mit Quellenangabe

Eine UI für deinen Personal Agent, die das Gespräch in den Mittelpunkt stellt. Schwarze Leinwand, kein permanentes Menü, parallele Chats als Slots, ein InfoPane für Detail-Ansichten on demand. Mobile und Desktop gleichermassen, PWA-tauglich.

**Fallbeispiel.** Du willst mehrere Gespräche parallel führen (Workshops, FCH, privat) und schnell zwischen ihnen wechseln. Gleichzeitig willst du Details (Kalender, Mail, Projekte, Memory) nur sehen, wenn du sie brauchst, nicht als ständigen Fries am Rand. Die UI soll auf dem Mac genauso gut funktionieren wie als PWA auf dem iPhone, ohne dass du sie zweimal pflegst.

---

## Teil B — Für dich (Operator)

### Was ist das?

Eine Single-Page-App, die nach drei Gesetzen lebt:

1. **Chat ist das Produkt.** Der gesamte Hintergrund ist eine schwarze Leinwand, der Chat liegt mittig
2. **Slots statt Tabs.** Du hast bis zu sechs Chat-Slots, jeder mit eigenem Gesprächsfaden. Wechseln per Klick oder Tastenkürzel
3. **InfoPane on demand.** Detail-Ansichten (Kalender, Mail, Projekte, Memory, WhatsApp, Daily-Log) öffnest du mit `Ctrl+I`, sie schliessen sich nach Gebrauch wieder

Dazu ein Composer unten, der immer sichtbar ist (auf Mobile besonders wichtig), und eine kleine Statusleiste oben mit Modell, Modus, Voice-Status.

### Warum so und nicht anders?

Die meisten Agent-UIs kopieren ChatGPT: Sidebar links mit Conversations, grosse Chat-Fläche, Settings irgendwo. Funktioniert für gelegentliche Nutzung. Wer den Agent **ständig** offen hat, will das Gegenteil: weniger sichtbares Drumherum, schneller Slot-Wechsel, Detail-Ansichten als Overlay, keine permanente Liste.

Mehr-Chats-parallel statt eines Threads, weil das Leben mehrgleisig ist. Slot-Modell statt frei beliebig vieler Tabs, weil unbegrenzte Tabs ungelesene-Häufung produzieren.

### Was brauchst du dafür?

- React + Vite (oder ähnlicher Framework deiner Wahl)
- Tailwind oder eine schmale CSS-Architektur mit Design-Tokens
- Ein Backend-WebSocket für Live-Updates
- LocalStorage für Slot-Zustand (Persistenz über Reload)

### Wie startest du?

1. Starter laden, in dein React-Projekt extrahieren
2. Design-Tokens (Warmgrau-Palette, Schriftgrößen, Abstände) in deine globale CSS einbinden
3. ChatPane-Komponente und InfoPane-Komponente einbauen
4. Slot-System aktivieren (Tastenkürzel `Ctrl+1` bis `Ctrl+6` für Slots, `Ctrl+I` für InfoPane)
5. Mobile-Variante: ChatPane + Composer immer sichtbar, InfoPane als Overlay

### Wo sind die Grenzen?

- Die UI setzt einen Personal-Agent voraus, kein Multi-User-Produkt
- Sehr lange Konversationen brauchen ein virtualisiertes Scrolling (in der Vorlage angedeutet, nicht ausgebaut)
- WebView-PWAs auf iOS haben Eigenheiten bei Mikrofon und Audio — siehe Voice-Agent-Blueprint

### Was kostet das?

Null. Frontend ist statisches Build, Hosting kostet im einfachsten Fall nichts.

### Wann lohnt es sich, wann nicht?

Lohnt sich, wenn du den Agent als ständig offene Arbeitsumgebung nutzt und mehrere Themen parallel betreibst. Lohnt sich nicht, wenn du den Agent nur sporadisch öffnest und Tabs reichen.

### Stolpersteine

- **Mobile Composer.** Auf iOS Safari kann ein falscher Layout-Zustand den Composer abschneiden. Composer immer auf `position: sticky` mit `safe-area-inset-bottom`
- **PWA-Statusleiste.** Schwarze Status-Bar oben sieht nach App aus, will aber zur restlichen Brand-Palette passen
- **InfoPane vs. Chat-Höhe.** InfoPane soll ChatPane nicht wegschieben, sondern überdecken. Sonst verlierst du Scroll-Position
- **Pillen unter dem Composer.** Während der Agent antwortet, dürfen Pillen (Schnellaktionen) nicht verschwinden, weil du nebenher in andere Chats springst
- **Slot-Sync.** Wenn der Agent auf einer Maschine läuft und du im Browser auf einem anderen Gerät reinschaust: Slots persistent im Backend speichern, nicht nur LocalStorage

---

## Teil A — Für deinen Agent

### Agent-Triggersätze

- "Bau mir die Chat-First UI"
- "Setze ChatPane und InfoPane auf"
- "Aktiviere das Slot-System"

### Ziel

React-Frontend mit ChatPane, InfoPane (mit Sektionen Workspace, Calendar, Jobs, WhatsApp, Mail, Artifacts, Social, Daily-Log, Settings), Composer mit Agent-Selector, Slot-System (max 6 Slots, Tastenkürzel, ephemeraler Slot für Spontan-Chats), Mobile-Layout mit Overlay-InfoPane.

### Erfolgskriterien

- ChatPane immer sichtbar, schwarze Leinwand als Hintergrund
- InfoPane via `Ctrl+I` (Desktop) oder Hamburger im Composer (Mobile)
- Slot-Wechsel via `Ctrl+1..6`
- Persistenz: Slot-Zustand + InfoPane-Sektion über Reload
- Mobile: Composer immer voll sichtbar, Pillen während Busy nicht versteckt
- Streaming-Antworten render-stabil (keine Layout-Sprünge)
- TTS-Output kann während Pane-Wechsel weiterspielen

### Design-Tokens

```yaml
palette:
  bg:              "#1a1815"          # warmes schwarz
  surface:         "#221f1c"
  border:          "#332f2a"
  text-primary:    "#fafaf7"
  text-secondary:  "#a8a39a"
  accent:          "#d97757"          # warmer brand-orange, sparsam
spacing:
  unit:            4                  # 4px-grid
  radius:          8
  pane-padding:    16
typography:
  sans:            "Inter, system-ui"
  serif:           "Lora, Georgia"
  mono:            "ui-monospace, Menlo"
  size-base:       14
  size-chat:       15
breakpoints:
  mobile:          640
  tablet:          1024
```

### Layout-Architektur

```
┌── Statusleiste ─────────────────────────┐
│ Modell  Modus  Voice  Slots             │
├── ChatArea ──────────────┬── InfoPane ──┤
│  Slot 1 (active)         │  (toggle)    │
│  Messages, scrollable    │  Workspace   │
│  ...                     │  Calendar    │
│                          │  Jobs        │
│                          │  ...         │
├── Composer ──────────────┴──────────────┤
│ Agent-Selector  Input  Send  PTT        │
│ Pillen                                  │
└─────────────────────────────────────────┘
```

Mobile:

```
┌── Statusleiste (slim) ─┐
├── ChatArea (full)      │
│  Slot 1                │
│  ...                   │
├── Composer (sticky)    │
└────────────────────────┘
+ InfoPane als Overlay (slide-up) bei Hamburger
```

### Komponenten

| Komponente | Zweck |
|---|---|
| `App.tsx` | Layout-Wurzel, Slot-State |
| `MobileApp.tsx` | Mobile-Variante mit Overlay |
| `ChatPane.tsx` | Aktiver Slot, Messages-Stream |
| `Composer.tsx` | Eingabefeld, Agent-Picker, Pillen, PTT |
| `InfoPane.tsx` | Sektions-Tabs mit Back-Stack |
| `VoiceController.tsx` | TTS-Wiedergabe, PWA-Audio-Workarounds |
| `audioQueue.ts` | URL-basiertes Audio, persistentes Element |
| `prefs.ts` | LocalStorage-Backed Settings |
| `theme.ts` | Design-Tokens als TS-Konstanten |

### Tastenkürzel

| Kürzel | Aktion |
|---|---|
| `Ctrl+I` | InfoPane toggeln |
| `Ctrl+1..6` | Slot wechseln |
| `Ctrl+N` | Neuer Slot |
| `Ctrl+W` | Slot schliessen |
| `Esc` | InfoPane schliessen, Modal schliessen |

### Sicherheit

- LocalStorage nur für UI-State, nie für Tokens
- WebSocket nur auf eigener Origin
- Mikrofon-Permission explizit bei erster Nutzung, nicht beim Page-Load

### Fehler-/Edge-Cases

- WS bricht → Banner mit 10s-Schwelle, kein Geflacker
- Streaming-Antwort abgebrochen → Teil bleibt sichtbar, mit "abgebrochen"-Marker
- Slot voll (6 belegt) → Hinweis statt 7. Slot
- InfoPane mit Composer-Überlapp auf Mobile → Composer immer Z-höher

### Verzeichnisstruktur

```
<root>/frontend/
├── src/
│   ├── App.tsx
│   ├── MobileApp.tsx
│   ├── components/
│   │   ├── ChatPane.tsx
│   │   ├── Composer.tsx
│   │   ├── InfoPane.tsx
│   │   ├── VoiceController.tsx
│   │   └── Chat.tsx
│   ├── audioQueue.ts
│   ├── theme.ts
│   ├── prefs.ts
│   ├── main.tsx
│   └── index.css           # Design-Tokens
└── public/
    └── manifest.json       # PWA-Manifest
```

### Code-Snippets

Im Starter findest du den minimalen ChatPane, InfoPane-Skelett, Composer mit Slot-Switching, Theme-Tokens und ein PWA-Manifest. Genug, um einen Prototyp aufzusetzen, nicht ein fertiges Produkt.

---

## Teil C — Was du als Nächstes tust

1. Starter laden, in `frontend/` extrahieren
2. Design-Tokens in deine CSS-Struktur einbauen
3. ChatPane mit deinem Backend (WebSocket oder REST) verbinden
4. Slot-System aktivieren, Tastenkürzel testen
5. InfoPane mit zwei Sektionen anfangen (z. B. Workspace und Memory)
6. Mobile-Layout prüfen, Composer-Sichtbarkeit testen
7. PWA-Manifest fertigstellen, auf Home-Bildschirm legen

### Lern-Checkliste

- Warum Slot-Modell statt Sidebar mit Conversations?
- Warum InfoPane als Overlay statt als feste Spalte?
- Welche State-Teile liegen lokal, welche im Backend?
- Wie verhält sich der Composer auf Mobile bei Tastatur-Einblendung?
- Wie würde ich eine neue InfoPane-Sektion hinzufügen?

Fragen: christian@denzer.ai
