Implements Phase 1 of docs/intent/git-intent-board-feedback.md: the kanban board pilot (board-agent) gains a job_type field and now drives the real Builder and Reviewer roles instead of only ever running admin.md. - board-agent/trigger.py: jobs carry job_type (default "builder"). - board-agent/worker.py: "builder" jobs translate and hand off into agent-codex's existing builder-inbox queue (sender=requested_by= Builder owner, so they run immediately) instead of duplicating builder.py's atomic-session/iteration-limit/stash-commit logic here. "review" jobs run `codex exec --sandbox read-only` against agents/reviewer.md and extract a ===REVIEW-REPORT=== marker block to write docs/review/<slug>.md themselves, outside Codex's sandbox -- corrected after live-testing this environment's codex-cli build showed `--sandbox workspace-write --add-dir <dir>` does NOT scope writes to that directory as the intent document assumed (a write outside it still succeeded); `--sandbox read-only` is a real, verified restriction, so the "Codex proposes, wrapper applies" marker pattern (already used for builder.py's ===COMMIT-MESSAGE===) replaces the originally planned sandbox scoping. - board-agent/completion_watcher.py (new): reacts to a finished board-triggered Builder run and auto-queues the follow-up review job, or just records the outcome if nothing was committed. - agent-codex/builder.py: opt-in completion-hook (on_complete_dir) so board-triggered jobs can be observed asynchronously; a no-op for ordinary XMPP-driven jobs, which never set that field. - Nix wiring for the new completion-watcher service/path unit and the cross-service ReadWritePaths it needs. Two of the intent document's assumptions didn't hold and were changed rather than implemented as originally specified (documented in the intent doc's Status note and this repo's READMEs): no reusable oauth2-proxy/Dex mechanism exists for internal routes, so auth stays Traefik BasicAuth for this phase; and board-triggered Builder jobs reuse the existing shared-checkout/stash execution model instead of new isolated git worktrees. 68 agent-codex tests + 15 new board-agent tests pass; blunix toplevel builds clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ANg2L2xUmNJ45t9mcv6HVT
13 KiB
Intent: Git-natives Intent-Board mit Reviewer-Feedback
Ziel
Ein Git-natives Intent-Board ersetzt Vikunja für den Lebenszyklus
Idee/Backlog → Geplant → In Umsetzung → Review → bereit für Deployment → Deployed mit kontrolliertem Rückfluss Review → Planung mit Feedback.
Ein Web-UI auf blunix visualisiert den Zustand und löst zwei Übergänge
aktiv aus. Löst und ersetzt docs/intent/kanban-board-admin-trigger.md.
Konsolidierung (2026-09-06): dieses Dokument ist jetzt auch die
alleinige Fortsetzung von
docs/intent/builder-pipeline-git-intent-board-feedback.md, das
dieselbe Ausbaustufe in einer früheren, allgemeineren Fassung
beschrieben hatte, ohne sie explizit abzulösen. Beide Dokumente
entstanden im selben Planungsschritt (Commit 3909cbf); die
Iterationslimit-Hälfte davon wurde als eigener, engerer Intent
ausgekoppelt (docs/intent/builder-iterationslimit.md, umgesetzt und
deployed 2026-09-06, Commit e8983e4) und ist damit erledigt, nicht mehr
offen. Die verbleibende Board-Hälfte lebt ab jetzt ausschließlich hier;
builder-pipeline-git-intent-board-feedback.md bleibt als historisches
Dokument liegen, wird aber nicht mehr separat umgesetzt (gleiches Muster
wie bei kanban-board-admin-trigger.md oben). Inhalte aus dem
abgelösten Dokument, die hier noch fehlten, sind unten eingearbeitet
(Modellwahl-Abschnitt, zwei zusätzliche offene Risiken).
Status: Phase 1 umgesetzt und deployed (2026-09-06). Kern des
Job-getypten Queue-/Watcher-Mechanismus, Builder-Wiederverwendung über
agent-codexs bestehende builder-inbox/, headless Reviewer-Runner und
automatische Phasenübergänge stehen (hosts/blunix/localServices/agent-codex/builder.py
Completion-Hook, hosts/blunix/localServices/board-agent/worker.py +
completion_watcher.py). Zwei Annahmen unten stimmten nicht mit der
Realität überein und wurden dabei bewusst geändert statt umgesetzt wie
ursprünglich spezifiziert:
- Auth bleibt vorerst Traefik-BasicAuth, nicht OIDC/Dex — es gibt im
Repo keinen wiederverwendbaren
oauth2-proxy/Dex-Mechanismus für interne Routen (verifiziert 06.09.2026:oauth2-proxyist eine Singleton-Instanz vor einem einzigen, aktuell deaktivierten Backend). OIDC-Self-Check (wie Forgejo/GoToSocial/Headscale) bleibt ein eigenständiger Folge-Intent. - Builder-Artefakt: bestehendes Stash-Modell wiederverwendet, keine
isolierten Worktrees. Board-Jobs laufen über den bereits gebauten,
getesteten
agent-codex-Builder (Lock +git stashim geteilten Checkout) statt über neue Worktree-Infrastruktur — bewusste Entscheidung, siehe "Offene Risiken" unten. - Zusätzlicher Fund: Reviewer läuft
--sandbox read-only, nichtworkspace-write --add-dir docs/review— Letzteres scoped Schreibrechte in diesemcodex-cli-Build nachweislich NICHT pfadgenau (live getestet). Reviewer liefert seinen Bericht stattdessen als===REVIEW-REPORT===-Marker-Block, den der Wrapper außerhalb der Sandbox schreibt.
Weiterhin nicht Teil dieser Phase (unverändert offen):
docs/board/<slug>.yaml mit automatischen lokalen Git-Commits (Board
bleibt bei state.json) und die Planner-Modellwahl-Eskalation aus dem
Umfang-Abschnitt unten (kein Planner-Handoff-Mechanismus für
Board-Karten vorhanden, der strukturierte Metadaten liefern könnte).
Umfang
docs/intent/<slug>.mdbleibt der fachliche Auftrag; pro Intent eine versioniertedocs/board/<slug>.yamlmit Phase, Job-ID, Modellprofil + Begründung, Iterationslimit/verbrauchte Iterationen (ausdocs/intent/builder-iterationslimit.md), Worktree-/Branch-Referenz, Prüf-Commit, Reviewer-Bericht(e), Review-Entscheidung, Zeitpunkte, Fehlerstatus.- Modellwahl (aus
builder-pipeline-git-intent-board-feedback.mdübernommen, dort wie inbuilder-iterationslimit.mdbereits spezifiziert): Standard ist ein günstiges Modellprofil. Der Planner darf pro Auftrag ein stärkeres, individuell begründetes Profil anfordern — ausschließlich aus den bekannten, konfigurierten Profilen, niemals aus Freitext innerhalb eines Intent- oder Reviewer-Textes heraus. Modellprofil und Begründung werden als strukturierte Auftragsmetadaten übergeben und landen als eigene Felder in der Board-Metadatei (siehe oben). Das Iterationslimit gilt unabhängig vom gewählten Modell. Der Planner darf zusätzlich ein aufgabenspezifisches Iterationsbudget vorschlagen; die Plattform validiert es gegen die globale Obergrenze (20, siehebuilder-iterationslimit.md) — der genaue Validierungsmechanismus ist Sache der Umsetzung. - Web-UI (Tailnet-only, ausschließlich blunix) hinter der bestehenden
oauth2-proxy/Dex-Grenze für interne Dienste — keine eigene Auth-Implementierung. Nur du (lukas) erfüllst den geforderten OIDC-Gruppenclaim/Identität für die auslösende Aktion. - Ein generischer, parametrisierter Queue-/Watcher-Mechanismus: ein
systemd.paths-Unit beobachtet ein Queue-Verzeichnis, Jobs tragen ein Feld „Job-Art" (builderoderreview) und werden davon abhängig an die passende Rolle headless übergeben. Der zugehörige Dienst verarbeitet Jobs mit Concurrency=1 streng seriell — dadurch strukturell keine parallelen Schreiber auf dieselbe Board-Datei, kein separates Git-Lock-Konzept nötig. - Aktiv steuerbar sind genau zwei Übergänge über denselben Mechanismus:
- Geplant → In Umsetzung: durch dich im Web-UI ausgelöst, legt
einen
builder-Job in die Queue. Dieser ruft die bestehende Builder-Rolle headless auf (ihr bereits vorgesehener Startxmpp-workerdeckt das ab) — nicht den Administrator. Das entspricht dem bestehenden Builder-Vertrag (Schreibzugriff, Commit/Push erlaubt, kein Deploy) und weicht nicht von der „Orchestrator ist einzige Dialogschnittstelle"-Regel für sichtbare Spezialisten ab, weil der Builder ohnehin schon headless/direkt ansprechbar ist. - Erfolgreicher Builder-Prüf-Commit → Review: vollautomatisch,
legt einen
review-Job in dieselbe Queue.
- Geplant → In Umsetzung: durch dich im Web-UI ausgelöst, legt
einen
- Builder-Artefakt: isolierter lokaler Git-Worktree/Job-Branch, bei Erfolg
ein lokaler Prüf-Commit, Board referenziert Commit-Hash/Branch/
Diff-Basis; Haupt-Checkout bleibt frei von halbfertigen Änderungen; bei
Limitüberschreitung (siehe
builder-iterationslimit.md) bleibt Zwischenstand im Worktree, gilt nicht als fertiger Prüfstand. - Reviewer: keine neue Aufgabenart — die bestehende freie Diff-Review
in
reviewer.mdbekommt einen zusätzlichen, klar markierten Absatz: bei Auslösung durch den Board-Trigger mit festem Commit-Scope schreibt sie zusätzlich einen Bericht nachdocs/review/<slug>.md(Intent-Slug, geprüfter Commit, Scope/Prüfmethoden, priorisierte Befunde, Unsicherheiten, Entscheidung, Empfehlungen) und trifft eine der zwei Entscheidungen unten. Dieser Lauf darf headless stattherdr-visiblelaufen (Abweichung vom sonstigen Start-Modus der Reviewer-Rolle, nur für diesen Trigger). - Review-Entscheidungen:
bereit für Deployment(Board → Wartephase, Mensch entscheidet über Push/Merge/Deployment) oderzurück zur Planung(Board → Feedback-/Planungsphase, Bericht bleibt dauerhaft, keine automatische neue Planner-Session — du startest sie bewusst mit Intent+Bericht als Kontext). Nach manuellem Deployment setzt du die Karte selbst aufDeployed.
Explizit ausgeschlossen
- Ersetzt
docs/intent/kanban-board-admin-trigger.mdunddocs/intent/builder-pipeline-git-intent-board-feedback.mdfachlich; beide Dateien bleiben als historische Dokumente liegen, werden aber nicht mehr separat umgesetzt. - Kein automatischer Git-Push, kein automatisches Merge/Deployment/ Aktivierung.
- Keine automatische Planner-Session, keine automatische Builder-Korrektur direkt aus dem Reviewer.
- Keine Verwendung/Integration von Vikunja, keine neue externe Datenbank/SaaS-Abhängigkeit.
- Keine Änderung an
tnix/pinix, keine Änderung am bestehenden Dashboard-Stack. - Kein öffentlicher Zugriff auf das Web-UI, kein roher API-Key für Agentenläufe.
- Keine eigene Identitätsprüfung außerhalb des bestehenden Dex/oauth2-proxy-Musters.
- Kein separates Git-Level-Lock-Konzept (ersetzt durch Concurrency-1-Queue).
- Keine neue, eigenständig dokumentierte Reviewer-Aufgabenart.
- Kein neuer Rollenkatalog-Eintrag für die reine Plattforminfrastruktur
(Web-UI-Dienst, Queue-Verzeichnis,
systemd.paths-Watcher,oauth2-proxy-Route) — analog zuagent-codexreine NixOS-Dienste ohne eigenen Agent-Rolleneintrag.
Annahmen
- Primärer Ausführungspunkt bleibt
blunix; Git ist der dauerhafte Audit-Trail. docs/intent/builder-iterationslimit.mdist umgesetzt und deployed (2026-09-06, Commite8983e4) — dieses Dokument definiert das Limit nicht neu, referenziert dessen Daten (Limit 20, verbrauchte Iterationen) nur im Board.- Reviewer bleibt read-only gegenüber Code/Konfiguration; einzige neue
Schreibausnahme ist der Bericht unter
docs/review/. - „Builder" umfasst auch den Administrator bei technischen
Plattformänderungen; der
builder-Job-Typ aus der Queue ruft aber konkret die Builder-Rolle auf, nicht den Administrator. - Der bestehende
oauth2-proxy/Dex-Mechanismus lässt sich analog zu anderen internen Diensten auf dieses Web-UI anwenden. - Die Umsetzung ändert
agents/reviewer.md(neuer Absatz für board-getriggerten Review),agents/catalog.jsonundagents/claude-settings/reviewer.json(Versionsbump, Klarstellung des headless-Starts für diesen Trigger).
Offene Risiken
- Entschieden und umgesetzt (2026-09-06): Board-Jobs verwenden den
bestehenden, geteilten Builder-Checkout (Lock +
git stash,locked_repos()/stash_foreign_changes()) statt eines isolierten Worktrees/Job-Branches — die "Builder-Artefakt"-Formulierung oben gilt fachlich als entsprechend abgeschwächt für diese Phase. Wiedervorlage, falls echte Parallelität mehrerer gleichzeitiger Board-Jobs mal gebraucht wird. - Neu, aus der Konsolidierung: ein lokaler Commit ohne Push kann auf einem anderen Checkout (z. B. dem Recovery-Checkout auf pinix) unsichtbar bleiben. Der manuelle Veröffentlichungsweg (wer pusht wann, von welchem Checkout aus) muss dokumentiert sein, bevor das Board produktiv genutzt wird.
- Bereits gelöst, nicht mehr offen: zuverlässiges Zählen der
Codex-JSON-Ereignisse für das Iterationslimit — erledigt in
common.run_streaming()/builder.py(item.completed-Events, live gegencodex-cliverifiziert). Ebenso bereits gelöst: der board-getriggerte Reviewer-Absatz existiert schon inagents/reviewer.md(Commit3909cbf), muss also bei der Umsetzung nur noch tatsächlich aufgerufen werden, nicht neu entworfen. - Selbst-Trigger-Vermeidung: auch mit Concurrency-1-Queue muss der Watcher-Mechanismus so gebaut sein, dass er nicht auf eigene Status-Update-Schreibvorgänge in der Board-Datei reagiert (Trigger sollte an neue Job-Dateien in der Queue gebunden sein, nicht an jede Änderung der YAML-Datei selbst) — Detailkonstruktion ist Sache der Umsetzung.
- Abgebrochener Worktree braucht Aufräum-, Wiederaufnahme- und Verwerfungsregeln.
- Exaktes Job-/Queue-Schema für beide Job-Arten, Fehlerbehandlung bei abstürzendem/unterbrochenem Lauf (z. B. durch einen Deploy, der den Worker-Dienst neu lädt).
- Automatische lokale Board-Commits brauchen eine technische Git-Identität.
- Vertagt (2026-09-06): genaue OIDC-Gruppen-/Claim-Anforderung für den Trigger-Endpunkt — Auth bleibt für diese Phase BasicAuth (siehe Status-Notiz oben), wird also erst mit dem OIDC-Folge-Intent relevant.
Erfolgskriterien
- Board aktualisiert Zustand ausschließlich über versionierte Metadateien und lokale Git-Commits, kein automatischer Push/Deploy.
- Eine fertige Intent-Karte lässt sich im Web-UI nur von dir (verifiziert über die bestehende OIDC-Grenze) von „Geplant" nach „In Umsetzung" bewegen und löst nachweisbar einen echten headless Builder-Lauf aus.
- Jeder erfolgreiche Builder-Commit startet automatisch genau einen
Reviewer-Lauf über denselben generischen Mechanismus, der einen
Bericht unter
docs/review/erzeugt. - Zu keinem Zeitpunkt schreiben zwei Prozesse gleichzeitig dieselbe Board-Datei (verifiziert durch Concurrency-1-Queue-Verhalten).
- Positiver Review →
bereit für Deployment; negativer Review →zurück zur Planungmit Bericht im Planner-Kontext verfügbar. - Web-UI läuft ausschließlich Tailnet-erreichbar hinter bestehender OIDC-Grenze, kein öffentlicher Zugriff, kein roher API-Key.
- Ablauf funktioniert ohne Vikunja, ohne neue externe Datenbank, ohne
Änderungen an
tnix/pinix/Dashboard-Stack. docs/intent/kanban-board-admin-trigger.mdunddocs/intent/builder-pipeline-git-intent-board-feedback.mdgelten als durch diesen Intent abgelöst.