This repository has been archived on 2026-09-17. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
nixos-config/docs/intent/git-intent-board-feedback.md
pijukka ff024def02 feat(board-agent): job-typed queue with Builder/Reviewer auto-trigger
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
2026-09-06 17:54:32 +02:00

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-proxy ist 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 stash im geteilten Checkout) statt über neue Worktree-Infrastruktur — bewusste Entscheidung, siehe "Offene Risiken" unten.
  • Zusätzlicher Fund: Reviewer läuft --sandbox read-only, nicht workspace-write --add-dir docs/review — Letzteres scoped Schreibrechte in diesem codex-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>.md bleibt der fachliche Auftrag; pro Intent eine versionierte docs/board/<slug>.yaml mit Phase, Job-ID, Modellprofil + Begründung, Iterationslimit/verbrauchte Iterationen (aus docs/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 in builder-iterationslimit.md bereits 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, siehe builder-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" (builder oder review) 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:
    1. 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 Start xmpp-worker deckt 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.
    2. Erfolgreicher Builder-Prüf-Commit → Review: vollautomatisch, legt einen review-Job in dieselbe Queue.
  • 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.md bekommt einen zusätzlichen, klar markierten Absatz: bei Auslösung durch den Board-Trigger mit festem Commit-Scope schreibt sie zusätzlich einen Bericht nach docs/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 statt herdr-visible laufen (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) oder zurü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 auf Deployed.

Explizit ausgeschlossen

  • Ersetzt docs/intent/kanban-board-admin-trigger.md und docs/intent/builder-pipeline-git-intent-board-feedback.md fachlich; 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 zu agent-codex reine NixOS-Dienste ohne eigenen Agent-Rolleneintrag.

Annahmen

  • Primärer Ausführungspunkt bleibt blunix; Git ist der dauerhafte Audit-Trail.
  • docs/intent/builder-iterationslimit.md ist umgesetzt und deployed (2026-09-06, Commit e8983e4) — 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.json und agents/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 gegen codex-cli verifiziert). Ebenso bereits gelöst: der board-getriggerte Reviewer-Absatz existiert schon in agents/reviewer.md (Commit 3909cbf), 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 Planung mit 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.md und docs/intent/builder-pipeline-git-intent-board-feedback.md gelten als durch diesen Intent abgelöst.