- board.html: replace the collapsible "Agent profiles" <details> panel
(which re-collapsed on every 5s refresh) with a fixed, always-visible
Agents column on the left, plus a bulk "apply to all" runtime dropdown
and per-phase links to view each role's agents/*.md prompt in the
existing Intent-dialog mechanism.
- board-agent.nix/trigger.py: fix the "Smoke-Tests entfernen" 502 --
board-agent-trigger's sandbox only had docs/intent writable, not
docs/review/research(-intent); widened ReadWritePaths and made the
delete loop tolerate a per-file OSError instead of dying mid-request.
- board.html: pause the periodic 5s render() while any board input/
select/textarea has focus, instead of unconditionally rebuilding the
DOM and stealing keystrokes out of whatever the operator was typing.
- New job_type="draft" (worker.py/trigger.py): an interactive,
multi-turn Planner intake dialogue ("+ Karte (interaktiv)") that
starts a card from a topic instead of a hand-written intent document.
Each turn resends the conversation so far to a read-only, repo-less
Planner call and gets back either a follow-up question (with
quick-reply options) or a finished intent, which the wrapper -- never
the model -- writes to docs/intent/<slug>.md before replacing the
draft card with a normal "geplant" one. See
docs/intent/board-interactive-planner-intake.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016w25covboHfcYuLXBAvX3g
120 lines
6.6 KiB
Markdown
120 lines
6.6 KiB
Markdown
# Intent: Interaktive Intent-Erstellung über eine Planner-Konversation im Board
|
||
|
||
## Ziel
|
||
|
||
Eine dritte Art, eine Karte auf dem Intent-Board anzulegen, neben dem
|
||
manuellen Schreiben eines `docs/intent/<slug>.md`-Dokuments von Hand und
|
||
dem einfachen "+ Karte"-Backlog-Eintrag: ein Button auf dem Backlog
|
||
("+ Karte (interaktiv)"), der ein Thema entgegennimmt und daraus eine
|
||
mehrrundige Rückfrage-Konversation mit der Planner-Rolle startet, bis
|
||
genug Kontext für einen vollständigen, eigenständigen Intent vorliegt.
|
||
Motivation aus einer Live-Diskussion auf dem Board selbst (10.09.2026):
|
||
die Operator-typische Vorarbeit ("mit einem Planner reden, bis der
|
||
Auftrag klar ist") sollte auch ohne separate Chat-Session möglich sein,
|
||
direkt im Board, mit Buttons statt Freitext wo sinnvoll.
|
||
|
||
## Umfang
|
||
|
||
- Neue Karten-Quelle `"draft"` (parallel zu `"idea"`): lebt ausschließlich
|
||
in `state.json`, keine Backing-Datei, bis die Konversation
|
||
abgeschlossen ist. `create_draft(topic)` legt sie an (`draft-<uuid>`)
|
||
und queued sofort die erste Planner-Runde mit dem Thema als einziger
|
||
Nachricht.
|
||
- Neuer `job_type="draft"` in `worker.py`: `run_draft()` ruft die
|
||
Planner-Rolle **ohne jeden Repo-Zugriff** auf (kein `-C` in den
|
||
Checkout, kein `--add-dir`) — ein Entwurf hat noch keine existierenden
|
||
Dateien zu lesen, und Lesezugriff auf einen noch unfertigen,
|
||
ungescopten Intent hätte hier keinen Nutzen. Jede Runde bekommt die
|
||
vollständige bisherige Konversation als Text mitgegeben; es gibt keine
|
||
persistente Modell-Session, Kontinuität lebt ausschließlich in
|
||
`state.json`s `draft_conversation`.
|
||
- Antwortformat: pro Runde **genau ein** Marker-Block, nie beide, nie
|
||
keiner:
|
||
- `===DRAFT-QUESTION===` / `===END-DRAFT-QUESTION===`: eine konkrete
|
||
Rückfrage plus optional bis zu vier kurze Antwortvorschläge
|
||
(`optionen: a | b | c | d` oder `optionen: keine`) — das Frontend
|
||
rendert sie als Buttons, zusätzlich zu einem freien Textfeld.
|
||
- `===DRAFT-INTENT===` / `===END-DRAFT-INTENT===`: `slug:`-Kopfzeile
|
||
plus vollständiger Intent-Dokumentinhalt, exakt das
|
||
`slug: ... / --- / Inhalt`-Format, das `run_split()` für seine
|
||
`===CHILD===`-Unterblöcke bereits verwendet.
|
||
- Eine Rückfrage aktualisiert nur `draft_conversation` und setzt die
|
||
Karte auf `entwurf_frage` — kein Repo-Zugriff, kein Lock, läuft neben
|
||
Builder/Review/Research/Split her.
|
||
- Ein fertiger Intent wird **vom Wrapper**, nie vom Modell, als
|
||
`docs/intent/<slug>.md` geschrieben — derselbe "Rolle schlägt vor,
|
||
Wrapper wendet an"-Grundsatz wie bei Review/Research/Split. Dieser eine
|
||
Schreibmoment läuft unter demselben `acquire_repo_lock()` wie
|
||
`run_split()`, nicht die ganze Konversation. Ein Slug-Kollision
|
||
(Zieldatei existiert schon) verwirft den Vorschlag vollständig, die
|
||
Karte bleibt in `entwurf_fehlgeschlagen` für einen manuellen erneuten
|
||
Versuch.
|
||
- Nach erfolgreichem Schreiben ersetzt `record_draft_intent()` den
|
||
`draft-<uuid>`-State-Eintrag durch eine normale Karte unter dem neuen
|
||
Slug, Phase **"Geplant"** — kein Auto-Trigger, derselbe manuelle
|
||
"Geplant → In Umsetzung"-Weg wie jede andere Karte. `draft_origin`
|
||
verlinkt zurück auf die ursprüngliche Dialog-ID, `draft_conversation`
|
||
bleibt als Audit-Trail erhalten.
|
||
- Antworten/erneute Versuche: `answer_draft(card_id, answer)` (nur bei
|
||
Phase `entwurf_frage`, max. 4000 Zeichen, max. 40 Konversationsrunden)
|
||
und `retry_draft(card_id)` (nur bei Phase `entwurf_fehlgeschlagen`,
|
||
sendet die letzte Runde unverändert erneut). Beide über eigene
|
||
`POST /api/board/cards/<id>/draft-answer` bzw. `.../draft-retry`.
|
||
- `delete_manual_card()` (vormals `delete_idea()`) akzeptiert jetzt
|
||
`"idea"` **und** `"draft"` als löschbare Quellen — ein abgebrochener
|
||
Entwurf verschwindet über denselben "×"-Button wie eine Idee-Karte.
|
||
- Frontend: eigene Spalten-Zuordnung (`entwurf_laeuft` → "Running",
|
||
`entwurf_frage`/`entwurf_fehlgeschlagen` → "Needs attention"), eigenes
|
||
Transkript-Rendering (`appendDraftDialogue()`), Options-Buttons plus
|
||
Freitextfeld für eine offene Rückfrage, "Erneut versuchen" bei einem
|
||
Fehlschlag.
|
||
- Nebenbefund aus derselben Diskussion, unabhängig vom Rest dieses
|
||
Intents: der periodische 5-Sekunden-Refresh (`setInterval(render, ...)`)
|
||
pausiert jetzt, solange ein Formularelement innerhalb des Boards
|
||
fokussiert ist (`boardEditInProgress()`), statt bei jedem Tick
|
||
bedingungslos die gesamte DOM neu aufzubauen und damit Fokus/Eingabe zu
|
||
zerstören — betrifft auch dieses Feature direkt (ein offenes
|
||
Antwortfeld im laufenden Dialog).
|
||
|
||
## Explizit ausgeschlossen
|
||
|
||
- Datei-Anhänge (Bild, Audio) an einen Entwurf — keiner der Runtimes
|
||
bekommt über diesen CLI-Wrapper-Pfad heute nicht-textuelle Eingaben;
|
||
Audio bräuchte zusätzlich einen eigenen Transkriptionsschritt. Separater
|
||
Folgeintent, falls gewünscht.
|
||
- Eine strukturierte Formular-Alternative (feste Felder statt freier
|
||
Konversation) — als schnellerer, modellfreier Weg diskutiert, aber
|
||
bewusst nicht Teil dieses Intents.
|
||
- Eine "Telefonat"-artige Sprachschnittstelle — als Fernziel genannt,
|
||
explizit als zu früh eingestuft.
|
||
- Column-Config-UI (Runtime/Modell-Dropdown) für die Draft-Spalte — nutzt
|
||
wie `run_split()` feste `BOARD_PLANNER_*`-Defaults ohne eigenes
|
||
UI-Override.
|
||
- Automatische Qualitätsprüfung des fertigen Intent-Vorschlags — wie
|
||
überall sonst in diesem Repo liest ein Mensch das Ergebnis, bevor es
|
||
über "Geplant → In Umsetzung" weiterläuft.
|
||
- `known_card_ids()`/Fan-out-Verlinkung für Entwürfe — ein Entwurf ist
|
||
erst nach Fertigstellung eine "echte" Karte.
|
||
|
||
## Annahmen
|
||
|
||
- Die Planner-Rolle liefert ohne Repo-Kontext trotzdem sinnvolle
|
||
Rückfragen, solange die Konversation selbst genug Substanz enthält —
|
||
ungetestete Annahme, zu beobachten im echten Einsatz.
|
||
- Ein Operator bricht eine ausufernde Konversation eher selbst ab
|
||
(Löschen, neu beginnen) als bis zum harten 40-Runden-Limit zu gehen;
|
||
das Limit ist eine Notbremse, kein erwarteter Normalfall.
|
||
|
||
## Offene Risiken
|
||
|
||
- Kein Locking zwischen `answer_draft()`/`retry_draft()` und einem
|
||
bereits laufenden `draft`-Job für dieselbe Karte — zwei schnell
|
||
aufeinanderfolgende Klicks könnten zwei Runden gleichzeitig queuen.
|
||
Geringes Risiko bei einem einzelnen Operator, nicht ausgeschlossen bei
|
||
mehreren gleichzeitigen Nutzern.
|
||
- Ein Slug-Kollision bei der Finalisierung lässt den Entwurf in
|
||
`entwurf_fehlgeschlagen` liegen; ein bloßer "Erneut versuchen" sendet
|
||
dieselbe Konversation erneut und bekommt mit realistischer
|
||
Wahrscheinlichkeit wieder denselben Slug vorgeschlagen. Für den ersten
|
||
Wurf akzeptiert; falls das in der Praxis stört, bräuchte es eine
|
||
eigene "anderen Slug vorschlagen"-Rückmeldung an den Planner.
|