Zum Hauptinhalt springen

agents.md — Konventionen für KI-Agenten und Coding-Agenten

Dieses Dokument beschreibt, wie ein KI-Agent (Claude, Codex, Cursor, Continue, etc.) in diesem Repo arbeitet. Es ist verbindlich für jede Session und sollte beim Start jeder neuen Konversation mitgelesen werden — typischerweise zusammen mit HANDOFF.md. Es ist unsere „Way of Working" und wird laufend aktuell gehalten: ändert sich, wie wir zusammenarbeiten, landet es hier (kein paralleles Prozess-Doc — Decision-Sprawl vermeiden, §5.2).


1. Repo-Philosophie: „Everything as Code"

Alle Artefakte des Projekts leben im Repo: Spezifikation, Entscheidungen, Architektur, Code, Diagramme, Konventionen. Nichts Überlebenswertes verbleibt im flüchtigen Konversations-Verlauf oder im Session-Memory einer einzelnen Cowork/Claude-Instanz.

Konsequenzen:

  • GitHub drkv-com/taktano ist die einzige Quelle der Wahrheit.
  • Eine neue Session startet nicht „bei null" — sie liest HANDOFF.md und docs/fachlich/Lastenheft.md und ist sofort im Kontext.
  • Wenn etwas entschieden wird, landet es als Commit im Repo, bevor die Konversation endet.

2. Doku-Format: Markdown + Mermaid (kein .docx, kein .pdf)

Regel: Alle versionierten Dokumente sind .md mit Inline-Mermaid für Diagramme. Keine binären Formate (.docx, .pdf, .pptx, .xlsx) als Master-Quelle. Falls ein externer Stakeholder PDF/Word braucht, kann es bei Bedarf aus dem .md exportiert werden (pandoc, Mermaid-CLI für SVG-Diagramme, etc.).

Begründung:

  • Git-diffbar, reviewable, mergeable.
  • Diagramme als Code (Mermaid) sind genauso versioniert wie der Prosa-Text.
  • Coding-Agenten können .md direkt lesen, ändern und Diffs erzeugen.
  • Keine Tooling-Abhängigkeit (Word, LibreOffice, Adobe).

Mermaid-Typen, die wir im Repo verwenden:

TypWofür
flowchartUse-Cases, Architektur, Ampel-Logik
erDiagramDatenmodell, Entitäts-Beziehungen
stateDiagram-v2Lifecycle (Auftrag, Teilschritt)
sequenceDiagramInteraktionen (Protokoll-Submit, Scheduler-Calls)
ganttZeitliche Abläufe (Teilschritt + Cool-down im Bay)
pienur falls aussagekräftig — selten sinnvoll

2.1 Doku-Navigation: Frontmatter, Kopf-Block, Landkarte

Damit die Doku navigierbar bleibt (nicht nur ist), gelten für jede Datei unter docs/:

  1. YAML-Frontmatter ganz oben (Maschinen-/Sidebar-Belange, minimal halten):

    ---
    sidebar_position: 20 # 10er-Schritte = Lesereihenfolge (nicht alphabetisch)
    sidebar_label: Kurz-Label # nur falls die H1 für die Sidebar zu lang ist
    ---

    Kein title: im Frontmatter — der Titel wird aus der ersten H1 abgeleitet (Single Source). sidebar_position in 10er-Schritten, damit neue Docs ohne Umnummerieren einsortieren.

  2. Sichtbarer Kopf-Block in docs/architektur/*.md direkt nach der H1 (rendert auch auf GitHub, Selbsterklärbarkeit) — kanonischer Standard (seit 07-12, Doku-Review E6; per Warn-Gate in check-doc-consistency.sh erzwungen; für andere schwere docs/-Dokumente empfohlen, dort ohne Gate-Pflicht):

    > **Status:** <ehrlich: Design (kein Code) / in Umsetzung, Slice X ✅ / gebaut (vX) / lebend> ·
    > **Bezug:** <Owning-OP + wichtigste IDs> · **Zielgruppe:** <Rolle(n) der sieben Leserkreise> ·
    > **True North:** <ehrlicher Halbsatz — welche Leitfrage, direkt/indirekt; „nur indirekt" ist ok>

    > **Kernaussage.** <2–5 Sätze, Antwort/Entscheidung zuerst (Minto)>

    Genau eine Kernaussage je Doc, exakt im Format > **Kernaussage.** (keine Varianten wie ## Kernaussage-Headings oder > **Zweck.**). Bewusst zwei getrennte Blockquotes (Metadaten-Box + Kernaussage-Box, Vorbild Doku-UX-Konzept.md) — der markdownlint-Hinweis MD028 („blank line in blockquote") ist hier kein Fehler, sondern Design. Status/Stand ändern sich oft → bewusst sichtbar (Diff = Audit); Gebaut vs. Geplant nie vermischen (Status-Ehrlichkeit).

  3. Landkarte & Sidebar pflegen: neues Doc in den passenden Unterordner legen, in docs/README.md eintragen, und (neuer Ordner) ein _category_.json mit label/position/link: generated-index anlegen.

  4. Begriffe & IDs: neuen Fachbegriff in docs-site/src/glossar/glossar.mjs ergänzen (Single Source → generiertes glossar/Glossar.md + Begriffs-Sprechblasen, npm run glossar); bekommt ein OP ein eigenes Dokument, die Zeile in IDs.md (OP → Owning-Doc) ergänzen.

  5. OP-Listen tragen klickbare OP-ID-Sprünge (verbindlich). In jeder OP-Liste in der Doku ist die OP-ID selbst ein Hyperlink zum direkten Sprung an ihr Zuhause — konkret:

    • Navigations-Indizes Register.md §1 + IDs.md-Reverse-Lookup: OP-ID → Owning-Doc, sonst ops/<ID>.md bzw. per-OP-Anker in Lastenheft §11 (#op-<id>, fachliches Detail); Familien-/Sammelzeilen (OP-R*-*) → passender §11-Sektions-Anker (#11-1-auftraege#11-10-tests-qs).
    • Volle OP-Liste Offene-Punkte.md (generiert aus ops/*.md): jede OP-ID verlinkt ihre ops/-Datei; deren detail: zeigt aufs Owning-Doc bzw. Lastenheft-§11-#op-<id>. (Das frühere HANDOFF-§4-Archiv ist seit 07-12 vollständig migriert.)
    • Fachliche Master-Liste Lastenheft §11: jede führende OP-ID trägt einen expliziten <a id="op-<id>">-Anker (präzises Sprungziel; Sektions-Anker {#11-x-…} zusätzlich).

    Neue/umziehende OPs immer so verlinken + verankern (kein blanker `OP-…`-Code ohne Link/Anker). Anker sind explizite {#…}-Heading-Anker bzw. inline <a id> (stabil, Docusaurus).

Der mechanische Teil (Landkarte-Vollständigkeit, Frontmatter-Präsenz, _category_.json) wird von scripts/check-doc-consistency.sh geprüft (harte Teilmenge blockt in CI, Rest warnt — OP-DOCS-9/-14, §5.1).

3. Identifikator-System

Jede Entscheidung, jedes Feld, jede Empfehlung, jeder offene Punkt hat eine kurze stabile ID. Diese IDs sind über das gesamte Repo durchsuchbar und werden in Commits, PRs, Issues, Chats referenziert.

PräfixBedeutungQuelle
G-nGlobales PrinzipLastenheft §3
RxModul (R1 Mitarbeiter, R2 Arbeitsplätze, …)Lastenheft §4–5
Rx-F##Feld einer EntitätLastenheft Tabellen
Rx-S##Sub-Entität / TabLastenheft
A-nArchitektur-EmpfehlungLastenheft §9
S-nVereinfachung gegenüber AltsystemLastenheft §10
UC-xKern-Use-CaseLastenheft §2
OP-Rx-nOffener Punktops/<ID>.md (fachliches Detail oft Lastenheft §11)
FR-nFuture-Release-NoteLastenheft §12
FM-nFuture-Module-NoteLastenheft §12

Regel für Commits: Wenn ein Commit eine entscheidung-relevante Änderung vornimmt, ID(s) in der Commit-Message nennen, z. B.:

Resolve OP-R7-8: Termin-Ampel Schwellen (4h grün, 0h orange)

4. Verbindliche Dokumente (lesen in dieser Reihenfolge)

  1. HANDOFF.mdWie ist der aktuelle Stand? Status, geparkte Fragen, nächste Schritte. Bei jeder neuen Session zuerst.
  2. docs/fachlich/Lastenheft.mdWas bauen wir? Vollständige fachliche Spezifikation mit Diagrammen. Master.
  3. docs/konventionen/agents.md — dieses Dokument.
  4. README.mdWie starte ich es? Orientierung, Setup, Deploy.

Außerdem gepflegt (nicht zwingend zuerst zu lesen): docs/betrieb/Timesheet.md — Arbeitszeit-Timesheet (Start/Stop je Session · Gap-Regel · Methodik); am Session-Ende aktualisieren. Protokoll → §5.1 „Arbeitszeit erfassen".

5. Verhaltensregeln für Agenten

5.1 Was tun

  • IDs respektieren: Beim Verweis auf existierende Entscheidungen ID nennen (z. B. „gemäß R3a-F04 ist Standzeit in Stunden").
  • Lastenheft und HANDOFF gemeinsam pflegen: Eine neue Entscheidung landet als Update im Lastenheft (Kern-Spec) und in HANDOFF.md (kompakt für die nächste Session).
  • Markdown + Mermaid: Neue Dokumente in .md anlegen. Diagramme als Mermaid inline.
  • Single Source of Truth: Wenn ein Wert (z. B. Status) abgeleitet werden kann, wird er abgeleitet — nirgends doppelt gespeichert. Siehe G-2 / S-2.
  • Selbsterklärbarkeit: Taktano soll ohne Schulung verständlich sein — durchgängig sprechende, eindeutige Bezeichnungen für Status, Aktionen, Felder und Räume (Werkstatt-Sprache statt technischer/abstrakter Labels; z. B. „Fahrzeug angeliefert" statt „Reserviert"). Gilt für UI und Doku. Bei neuen Labels diesen Maßstab anlegen. (Lastenheft §1.2 Leitprinzip.)
  • Anführungszeichen: gerade ASCII-Zeichen (" und ') sind der Standard — in Code, Doku und UI-Strings (PO-Entscheid 07-18). Keine typografischen/geschwungenen Anführungszeichen in neuem Text; Bestehendes bleibt (kein retroaktiver Umbau, keine ungefragten Sweeps). CodeRabbit ist entsprechend konfiguriert (.coderabbit.yamltone_instructions), den Anführungszeichen-Stil nicht mehr zu beanstanden.
  • Tests on-demand + CI: Alle automatischen Tests müssen lokal on demand ausführbar sein (Anleitung in README.md) und in der CI/CD-Pipeline laufen. Neue Tests immer beiden Wegen hinzufügen (Lastenheft §11.10; OP-TEST-1/2/3).
  • Versioniertes Datenmodell + automatische Migration: Jede Datenmodell-Änderung ist versioniert (z. B. schemaVersion). Für jede neue Version gibt es eine automatische Migration. Jede Instanz wird beim Laden auf die Version geprüft und ggf. automatisch migriert (idempotent, jede Versionsstufe genau einmal). Beispiel im Code: SCHEMA_VERSION + versionierte Remaps in server/party/leitstand.ts (onStart). Persistierte Daten nie ohne Migration „brechen".
  • Logging via OpenTelemetry: Anwendungs-Logs (und Traces/Metrics) über das OTel-SDK je Laufzeit (Worker/DO · Angular-Client · Python-Solver) emittieren — nicht roh console.log/print im Laufzeit-/Produktivpfad (CLI-Demos & Self-Tests dürfen console/print). Strukturiert über einen Logger-Wrapper, trace_id-korreliert. Verdrahtung + Collector/Backend: OP-OBS-1 (heute noch console-basiert). Siehe Root-CLAUDE.mdObservability / Logging.
  • Tasks tracken: Multi-Step-Arbeit über das Task-System der Coding-Umgebung (Cowork TaskCreate/TaskUpdate, Claude Code TODO-System, etc.) sichtbar machen.
  • Bei jeder größeren Aktion: offene Punkte im Auge behalten (ops/*.mdOffene-Punkte.md).
  • Jedes Feature wird dokumentiert (goldene Regel): Kein Feature ist „fertig", bevor die zuständige Produkt-/Design-Doku es beschreibt (WORKSPACES.md, OPTIMIERER_TERMINKLASSEN.md, COMPONENTS.md, DESIGN_TOKENS.md, Lastenheft). HANDOFF ist das Arbeitslog, kein Ersatz für die Produkt-Docs.
  • Doku-Konsistenz-Check (verbindlich, OP-DOCS-9): Die Doku muss in sich konsistent sein und zur Implementierung passen. Cadence: zu Session-Beginn die relevanten Docs sichten und vor jedem PR/Merge gegenprüfen (zusätzlich zu den Test-Gates). Zwei Achsen:
    • Doku↔Doku (in sich): IDs (G-/R-/A-/S-/OP-…) existieren & sind eindeutig, Glossar-Begriffe einheitlich verwendet (z. B. Crystal-Bar), Workspace-/Phasen-Liste und Status (✅/🟡/⛔) stimmen über HANDOFF.md · docs/fachlich/Lastenheft.md · CHANGELOG.md · design/ überein, Version/Build überall = server/src/version.ts, Querverweise (§-Verweise, Datei-/Bildlinks) lösen auf, keine widersprüchlichen Aussagen.
    • Doku↔Implementierung: in der Doku genannte Feldnamen/Enums/DTOs/Routen/Token existieren im Code (und umgekehrt) und tragen dieselbe Bedeutung; beschriebene Features sind gebautund Gebautes ist beschrieben (goldene Regel). Bei Abweichung: entweder Code oder Doku angleichen (begründet entscheiden), nie still auseinanderlaufen lassen.
    • Mechanik: der maschinell prüfbare Teil läuft als bash scripts/check-doc-consistency.sh. Seit OP-DOCS-14 Teil 3 zweistufig: die harte Teilmenge (tote Links/Bilder · Version/Build-Single-Source · veraltete generierte Offene-Punkte.md) blockt den Merge (CI-Job doc-consistency läuft mit --strict und hängt am ci-gate); alle übrigen Checks (Landkarte/Frontmatter/Sidebar · Log-Hygiene · Zeilenlängen · Footer-Staleness · Landkarte-Rücklink, Generator scripts/gen-doc-footer.mjs) warnen weiter (::warning::). Der semantische Teil (IDs/Glossar/Workspace-Liste · Doku↔Code) ist Agenten-Pflicht und nicht voll automatisierbar — das Skript ersetzt ihn nicht. Bei Unklarheit/Widerspruch: nachfragen (nicht raten).
  • Audit-Trail: Entscheidungen + Diskussionsergebnisse festhalten: Jede Design-/Architektur-/Prozess-Entscheidung und jedes Diskussionsergebnis (auch UX-Richtungen, verworfene Optionen mit Begründung) landet in der Doku — fachlich im Lastenheft, OPs als ops/<ID>.md, Design in design/, Guiding Principles im Root-CLAUDE.md. Ziel: lückenloser, nachvollziehbarer Audit-Trail.
  • CHANGELOG.md pflegen (je PR): CHANGELOG.md (Repo-Root) immer aktuell halten — ein Eintrag pro PR: Datum · PR-Nummer mit Link · kurze Beschreibung inkl. getroffener Entscheidungen, neueste zuerst. Der Changelog ist der schnelle chronologische Audit-Trail; die Tiefe steht in HANDOFF/Lastenheft.
  • Versionierung (je PR): nur APP_VERSION (SemVer) in server/src/version.ts bewusst setzen — die Build-Nummer kommt automatisch (Git-Commit-Count beim Deploy, build-number.ts/stamp-build.mjs, nicht von Hand). Details: Root-CLAUDE.md §Versionierung, OP-PM-2.
  • Test-Übersicht mitführen (je PR): Wer eine automatische Prüfung hinzufügt/entfernt (test:*-Script, Smoke, Gate, CI-Job), zieht docs/betrieb/Tests.md nach (Befehl · Prüfgegenstand · OP-Bezug · CI-Job) — die lebende, vollständige Liste aller automatischen Tests. Mechanischer Rückhalt: scripts/check-doc-consistency.sh warnt, wenn ein test:*-Script (server/ + client/) dort fehlt; der semantische Teil bleibt Pflicht (§5.1/OP-DOCS-9). Root-CLAUDE.md §Tests & CI.
  • Log-Hygiene (regelmäßig): die merge=union-Logs (CHANGELOG/HANDOFF/Timesheet) zu Session-Beginn + nach Merges glätten (Duplikate raus, Nummern eindeutig, chronologisch) — scripts/check-doc-consistency.sh flaggt Kandidaten, npm run smooth-logs entfernt sichere Duplikate automatisch. Detail: §6.6.
  • Annahmen sichtbar machen + Optionen zuerst: Berührt eine Aufgabe versteckte Annahmen oder Produkt-/Datenmodell-Entscheidungen, nicht drauflosbauen — Annahme explizit auflisten + begründen (gegen das Datenmodell prüfen), Optionen mit Empfehlung vorlegen, entscheiden lassen, dann bauen + Entscheidung dokumentieren.
  • Verifizieren statt behaupten: Previewbare Änderungen live verifizieren (Preview-Tools, echte Daten) statt den User prüfen zu lassen; reine Logik als self-asserting Demo (in CI, z. B. test:*); bei Client↔Server-Protokollen Symmetrie prüfen (jeder Client-Sender hat einen Server-Handler).
  • Arbeitszeit erfassen: docs/betrieb/Timesheet.md pflegen — Start/Stop je Session, Gap-Regel (> 1 h seit letzter Interaktion → User nach Stop fragen, neue Session). Am Session-Ende aktualisieren.

5.2 Was NICHT tun

  • Keine binären Dokumente als Master-Quelle. Kein .docx, kein .pdf als Spezifikations-Quelle. Wenn vorhanden, sind diese reine Exporte aus dem .md.
  • Keine ungefragten Refactorings am Lastenheft oder Prototyp. Erst klären, dann tun.
  • Kein Pushen ohne Confirm in main, wenn der Wert der Änderung unklar ist. Lieber Branch + PR.
  • Keine duplizierten Decision-Docs außerhalb von Lastenheft + HANDOFF. Wir vermeiden „Decision-Sprawl".
  • Keine Read-Only-Analyse von Drittsystemen ohne expliziten User-Auftrag. Wenn nötig: User loggt selbst ein, Agent navigiert per Browser-Extension.
  • Keine PII / Passwörter in Klartext committen.

5.3 Bei Unsicherheit

  • Lieber eine kurze Frage stellen als annehmen.
  • Wenn die Antwort nicht entscheidbar ist: Punkt als ops/OP-Rx-n.md parken (§6.2) und weitermachen.

6. Workflow für Änderungen

6.1 Eine Entscheidung treffen

  1. ID vergeben (oder bestehende referenzieren).
  2. Lastenheft §X (passender Abschnitt) updaten.
  3. HANDOFF.md §3 bzw. betroffene ops/<ID>.md updaten (Entscheidung kompakt notieren oder OP schließen + gen-ops).
  4. Commit-Message: Resolve <ID>: <kurz>.

6.2 Eine offene Frage aufnehmen (ops/-first — verbindlich seit 07-12, OP-DOCS-11)

  1. ops/<OP-ID>.md anlegen (Vorlage ops/_Vorlage.md; Frontmatter-Pflicht id/title/status/ audiencegen-ops.mjs validiert hart). Diese Datei ist die einzige Quelle für Lebenszyklus/Status/Priorität des OP; die Beschreibung bleibt prägnant (wird als GitHub-Issue gespiegelt), Tiefe gehört ins detail-Ziel (Owning-Doc).
  2. node scripts/gen-ops.mjs (bzw. npm run gen-ops in server/) → regeneriert docs/betrieb/Offene-Punkte.md (Staleness blockt in CI, §5.1); der GitHub-Issues-Spiegel läuft automatisch bei Push (sync-ops.yml).
  3. Fachlicher Kontext (falls vorhanden): im Owning-Doc bzw. passenden Lastenheft-Abschnitt kurz verlinken (ops/<ID>.md als Status-Quelle nennen); bekommt der OP ein eigenes Dokument → Zeile in IDs.md ergänzen (§2.1).
  4. Commit-Message: Park <ID>: <kurz>.

Nicht mehr: OP-Einträge in HANDOFF.md §4 oder als Lastenheft-§11-Vollbeschreibung anlegen/pflegen — der komplette Alt-Bestand wurde am 12.07.2026 hierher migriert (Big-Bang auf PO-Auftrag; §4 ist nur noch ein Pointer, Lastenheft §11 bleibt fachliche Detailbeschreibung als detail:-Ziel, Status dort nicht mehr pflegen). Die frühere Dreifach-Buchführung war Doku-Review-Befund D4.

Sichten & Steuern (OP-ORG-1, PO-Vorgabe 07-12): Die generierte 📊-Statistik + Grafik in Offene-Punkte.md (OPs · Alt-Archiv · Entscheidungen · Risiken, offen vs. abgeschlossen) ist der Standard-Blick — zu Session-Beginn kurz sichten (zusammen mit dem Risikoregister-Check, §5). Fürs Stakeholder-Steuern dient das GitHub-Projects-Board über die op-sync-Issues (seit 07-12 live; Auto-Add-Filter is:issue label:op-sync; die Spiegel-Labels status:*/prio:*/bereich:*/audience:* dienen als Filter/Slice — Board-Spalten sind das Projects-eigene Status-Feld, „Item closed → Done" läuft automatisch). Kadenz (PO-Entscheid 07-12): wöchentlicher PO-Blick aufs Board. Das Board ist reiner Konsument — Statusänderungen laufen ausschließlich über ops/<ID>.md im Repo.

6.2a OP-Grooming & Diskussion (agentgetrieben, on-demand — PO-Entscheid 07-12)

Bewusst keine Pipeline/Automatik, sondern stehende Tasks, die ein Agent (Claude Code / Codex) auf Zuruf ausführt; das Repo bleibt alleinige Quelle (das Board ist reiner Spiegel).

  • Priorität/Reihenfolge = im Repo entscheiden. prio: (jetzt|next|spaeter) und status: werden direkt in ops/<ID>.md gesetzt — nicht auf dem Board. Der sync-ops-Spiegel trägt sie als prio:*/status:*-Label ins Issue, das Board filtert danach. Es gibt keinen Board→Repo- Backflow (PO-Entscheid: Everything-as-Code, eine Quelle).
  • OP-Diskussion zusammenfassen (Task, auf Zuruf — „fasse die Diskussion zu OP-X zusammen"): Der Agent liest die Kommentare des zugehörigen op-sync-Issues (GitHub-MCP), verdichtet sie zu einem Block ## Diskussion (Stand JJJJ-MM-TT) in der ops/<ID>.md und legt einen PR an. Weil der Datei-Body 1:1 ins Issue gespiegelt wird, ist die Zusammenfassung danach auch auf dem Board sichtbar. So kommt die Stakeholder-Diskussion (die sonst nur auf GitHub lebt) zurück in die Quelle der Wahrheit.
  • OP anreichern / grooming (Task, auf Zuruf — „groome OP-X"): Der Agent ergänzt je genanntem OP einen Block ## Grooming (Stand JJJJ-MM-TT) mit Akzeptanzkriterien · Aufwand (grob) · Abhängigkeiten (OP-/RISK-IDs) · offene Compliance-/DSGVO-Fragen (DE/AT/CH) · prio-Vorschlag und legt einen PR an — du entscheidest je OP. Genau hier werden die von Reviews angemahnten Klärpunkte bewusst abgearbeitet (statt sie in die Migration zu zwängen). Kein Massen-Lauf.

6.3 Eine neue Architektur-/Vereinfachungs-Idee

  1. Eintrag in Lastenheft §9 (A-) oder §10 (S-).
  2. Begründung mit ggf. Mermaid-Diagramm.
  3. Commit-Message: Propose <ID>: <kurz>.

6.4 Codeänderungen am Prototyp

  1. TypeScript-Server: cd server && npm run typecheck muss passen.
  2. Angular-Client: cd client && npx ng build --configuration production muss passen (CI-Hook geplant, siehe HANDOFF §7).
  3. Commit-Message-Konvention frei, aber mit relevanter Lastenheft-ID, wenn die Änderung eine Anforderung implementiert.

6.5 Doku-Konsistenz prüfen (Session-Start + vor jedem PR)

  1. Session-Start: HANDOFF.mddocs/fachlich/Lastenheft.mddocs/konventionen/agents.md lesen; relevante Docs zum Vorhaben sichten (der SessionStart-Hook scripts/session-start-hook.sh blendet diese Erinnerung ein).
  2. Vor dem PR: beide Achsen prüfen (Doku↔Doku und Doku↔Implementierung, s. §5.1 „Doku-Konsistenz-Check"); bash scripts/check-doc-consistency.sh für die mechanische Teilmenge laufen lassen.
  3. Drift gefunden? Code oder Doku angleichen (begründet) — bei Unklarheit nachfragen. Ergebnis im PR/CHANGELOG vermerken.
  4. Commit-Message bei reiner Angleichung: Sync docs <Bereich>: <kurz>.

6.6 Merge-Strategie & Log-Hygiene (OP-PM-2)

Problem: Praktisch jeder PR ergänzt die append-only Logs (CHANGELOG.md, HANDOFF.md, docs/betrieb/Timesheet.md) und früher auch die Build-Nummer in version.ts → bei parallelen Merges Dauer-Konflikte + Build-/Session-Nummern-Kollisionen.

Maßnahmen (umgesetzt):

  1. merge=union für die drei Log-Dateien (.gitattributes): Git konkateniert beide Seiten statt zu blocken — kein Stop-the-line mehr.
  2. Build-Nummer automatisch aus dem Git-Commit-Count (kein Hand-+1 mehr) → keine Build-Kollision (siehe Root-CLAUDE.md §Versionierung; scripts/stamp-build.mjs).
  3. Session-ID sprechend, repo- & branch-abgeleitet (<repo>-<Datum>-<branch-slug>, z. B. taktano-2026-06-28-comments-image-support-caix8o) statt fortlaufender Zahl (OP-PM-3): Der Repository-Name als Präfix macht die ID repo-übergreifend eindeutig und auf einen Blick zuordenbar; Branch-Name + Datum sind git-weit eindeutig → die Timesheet-Session-ID kann nicht kollidieren, der union-Merge konkateniert nur (kein Umnummerieren mehr). Sprechend (Repo=wo, Datum=wann, Slug=was) + chronologisch sortierbar. Alt-Sessions (Zahl 0…52 bzw. frühere <Datum>-<branch-slug> ohne Repo-Präfix) bleiben unverändert (nicht rückwirkend umgeschrieben). Detail: docs/betrieb/Timesheet.md §Protokoll.
  4. Empfohlen (Repo-Setting): GitHub Merge Queue bzw. „Allow auto-merge" (Settings → General → Pull Requests) → serialisiert Merges, beendet das Wettrennen. Kann nicht per Repo-Datei gesetzt werden.
  5. „Update branch" lokal, nicht server-seitig (wichtige Einschränkung, 06-27 verifiziert): GitHubs server-seitiger Merge — der „Update branch"-Button, die update-branch-API und die Mergeability-Berechnung — wendet den .gitattributes-merge=union-Treiber NICHT an. Ein PR, der die Logs berührt, zeigt nach einem main-Vorlauf darum trotzdem dirty/Konflikt, und „Update branch" scheitert mit 422 merge conflict, obwohl derselbe Merge lokal (mit union) sauber durchläuft. Konsequenz: einen log-berührenden PR lokal aktualisieren — git fetch origin maingit merge origin/main (union greift) → vom Repo-Root node scripts/smooth-logs.mjs → push —, nicht den GitHub-Button. Automatisiert: der Workflow .github/workflows/sync-pr-logs.yml macht genau das per Knopfdruck — Auslöser /sync-logs-Kommentar am PR oder manueller workflow_dispatch (PR-Nummer); bei echten Konflikten (jenseits der union-Logs) bricht er ab und kommentiert. (Hinweis: ein Push mit dem Default-GITHUB_TOKEN triggert keine neue PR-CI — optionales Secret SYNC_BOT_TOKEN [PAT, contents:write] setzen, dann läuft die CI nach dem Sync neu.) Der squash-Merge selbst ist von der Einschränkung unberührt, sobald der Branch main enthält (deshalb zuerst lokal syncen, dann squash-mergen).

Setup SYNC_BOT_TOKEN (optional, für den sync-pr-logs-Workflow): Damit der Push des Workflows die PR-CI neu auslöst, ein Repo-Secret SYNC_BOT_TOKEN hinterlegen — GitHub unterdrückt CI-Trigger für Pushes mit dem Default-GITHUB_TOKEN (Loop-Schutz), d. h. ohne das Secret wird der Branch zwar aktualisiert, die CI muss aber einmal manuell angestoßen werden (Checks-Tab → Re-run, oder leerer Commit). Least-privilege empfohlen: fine-grained PAT, nur auf drkv-com/taktano begrenzt, Permissions Contents: R/W (+ Pull requests: R/W für den Sync-Kommentar); alternativ ein GitHub-App-Installations-Token (sauberste Variante, nicht an ein Personenkonto gebunden). Ein klassischer PAT braucht zusätzlich den workflow-Scope, falls ein gesyncter Branch .github/workflows/** ändert. Anlegen: Settings → Secrets and variables → Actions → New repository secret SYNC_BOT_TOKEN, oder gh secret set SYNC_BOT_TOKEN. Compliance (OP-SEC-1/Risikoregister): langlebige Credentials — Ablauf setzen + rotieren, breite klassische PATs meiden. Der Workflow liest das Secret bereits (token: ${{ secrets.SYNC_BOT_TOKEN || github.token }}).

Pflicht — Logs regelmäßig glätten (union-Merge kann Duplikate/Reihenfolge-Unschärfe erzeugen):

  • Wann: zu Session-Beginn und nach jedem Merge von main.
  • Was: exakte Duplikate entfernen; Session-IDs (Timesheet — neu branch-abgeleitet/kollisionsfrei) und OP-/PR-Nummern eindeutig + chronologisch; Summen/KW-Aggregate im Timesheet stimmig; keine Konflikt-Marker-Reste.
  • Hilfe (flaggt): bash scripts/check-doc-consistency.sh flaggt Kandidaten (Marker-Reste · doppelte Timesheet-Session-IDs · doppelte CHANGELOG-PR-Zeilen · Mega-Zeilen > 2000 Zeichen) — diese Log-Hygiene-Checks warnen, blocken nicht (die harte Teilmenge des Skripts blockt separat, §5.1).
  • Hilfe (fixt): npm run smooth-logs (in server/; oder node scripts/smooth-logs.mjs) entfernt byte-identische Duplikate automatisch (CHANGELOG-Einträge · Timesheet-Session-Zeilen) und meldet alles, was menschliches Urteil braucht (Konflikt-Marker-Reste · gleiche Session-ID mit abweichendem Inhalt) — es fasst Zweifelhaftes nie an und sortiert nicht um. Vorschau ohne Schreiben: npm run smooth-logs:check (Exit 1 bei Glätt-Bedarf). Das Urteils-Glätten (Reihenfolge/Chronologie, abweichende Inhalte zusammenführen) bleibt Agenten-Aufgabe.

6.7 Nicht-automatisierbare Checks (Agenten-Pflicht — „nicht per MCP/Skript prüfbar")

Problem: Einige Sicherheits-/Setup-Kontrollen lassen sich nicht per CI-Skript und nicht über die GitHub-MCP zuverlässig prüfen — entweder fehlt ein MCP-Tool (Repo-Settings/Code-Scanning-Modus) oder der CI-GITHUB_TOKEN hat keinen Admin-Scope. scripts/check-security-setup.sh (im wöchentlichen weekly-audit.yml) prüft die mechanische Teilmenge und meldet diese Punkte best-effort als ℹ️/⚠️ „nicht abfragbar" — die eigentliche Verifikation ist dann Agenten-Pflicht.

Wann: zu Session-Beginn, vor jedem PR und nach jeder Repo-Setting-Änderung.

Wie: wenn ein gh/Token mit ausreichendem Scope vorhanden ist, per gh api prüfen; sonst den Nutzer fragen bzw. aktiv darauf hinweisen (Optionen zeigen, §5.3) und Abweichungen melden — nie still übergehen.

Checkliste (nicht-mechanisch):

  1. Merge-Methoden = nur Squash aktiv (Merge-Commits + Rebase aus). — gh api repos/<o>/<r> --jq '.allow_squash_merge,.allow_merge_commit,.allow_rebase_merge'
  2. allow_auto_merge = true (OP-PM-2). — gh api repos/<o>/<r> --jq '.allow_auto_merge'
  3. delete_branch_on_merge = true (Branch-Cleanup). — gh api repos/<o>/<r> --jq '.delete_branch_on_merge'
  4. Code scanning läuft (Entscheidung 06-27: GitHub Default Setup, deckt TS+Python automatisch; kein eigener codeql.yml — advanced + default schließen sich aus). — gh api repos/<o>/<r>/code-scanning/default-setup --jq '.state' (erwartet configured); ergänzend Security-Tab/Alerts sichten.
  5. Branch-Protection auf main (erforderliche Checks gesetzt). — gh api repos/<o>/<r>/branches/main/protection (Admin-Scope nötig).
  6. Semantische Doku-Konsistenz (§5.1/§6.5) — ohnehin Agenten-Pflicht (kein Skript ersetzt sie).

Soll-Zustand (Stand 06-27): 1–4 ✅ gesetzt; verwaiste Alt-Branches (vor Auto-Delete gemergt) sind manuell aufzuräumen. Abweichungen vom Soll → im PR/HANDOFF vermerken und dem Nutzer melden.

6.8 CI-Pipelines: Concurrency (überholte Läufe abbrechen)

Regel: Jede Workflow-Pipeline bekommt einen concurrency-Block, wo er Nutzen bringt — d. h. überall, wo mehrere Läufe desselben Kontexts (PR/Branch, Deploy-Ziel) überlappen können und der ältere Lauf durch den neueren überflüssig wird. Das spart Runner-Minuten und liefert schneller ein aktuelles Ergebnis. Gemeint ist das GitHub-Actions-Schlüsselwort concurrency: (Läufe gruppieren/canceln) — nicht die Job-Parallelität (die regelt der Job-Graph über needs).

Muster (je Pipeline-Typ):

  • CI / PR-Pipelines → nächsten Push auf denselben PR/Branch den vorherigen Lauf abbrechen lassen:
    concurrency:
    group: ci-${{ github.workflow }}-${{ github.ref }}
    cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
    Nicht auf main abbrechen — dort liefe sonst ein Deploy ins Leere. Umgesetzt in ci.yml.
  • Deploy-/Ressourcen-Pipelines (genau ein Ziel, z. B. ein Worker) → überlappende Deploys verhindern: group: <deploy-ziel> (fixer Name), cancel-in-progress: true.
  • Serielle Jobs, die nicht abgebrochen werden dürfen (z. B. Log-Sync, Migrationen) → nur serialisieren, nicht canceln: cancel-in-progress: false. Umgesetzt in sync-pr-logs.yml.

Faustregel cancel-in-progress: true für idempotente/überholbare Läufe (PR-CI, Deploy); false, wenn jeder Lauf zu Ende laufen muss. Ergänzend wirkt die Trigger-Hygiene gegen Doppelläufe (push nur auf main + pull_request statt push auf allen Branches, OP-CI-1) — Concurrency und Event-Trigger greifen zusammen: der eine cancelt überholte Läufe desselben Events, der andere verhindert den doppelten push+pull_request-Lauf desselben Commits.

Kein actions/setup-node-cache: npm auf dem persistenten self-hosted Runner. Der npm-Cache von setup-node ist für ephemere GitHub-Runner gedacht (die nach jedem Lauf verschwinden). Unser Org-Runner ist persistent~/.npm ist zwischen Läufen ohnehin warm; cache: npm würde nur ein großes Archiv langsam durch den Actions-Cache-Service tarren/laden (auf flakiger Runner-Anbindung ein Timeout-Risiko). Daher in ci.yml entfernt; npm ci/npm install nutzen das lokale ~/.npm. Auf Fork-PRs (ubuntu-latest, ephemer) lädt npm dann frisch aus der Registry — selten und akzeptabel.

Schnelle Installs: die npm ci-Aufrufe in ci.yml laufen mit --prefer-offline --no-audit --fund=false — nutzt das warme lokale ~/.npm ohne Audit-/Funding-Netz-Calls (spart Zeit, robuster bei flakiger Anbindung). Der Pfad-Filter (changes-Job) hält bereichsfremde/​docs-only-PRs schlank (schwere Jobs skippen; „CI Gate" bleibt grün, skipped ≠ failure).

Runner-Labels hot vs. ephemeral (wichtig): Die self-hosted Runner der Org tragen ein Label — hot = persistent (Arbeitsordner + ~/.npm + Build-Caches überleben zwischen Läufen), ephemeral = frisch je Lauf. CI pinnt auf hot (runs-on: … || 'hot'), weil alle Cache-/Offline-Hebel nur dort greifen: warmes ~/.npm (Offline-Installs), fehlender setup-node-npm-Cache (auf ephemeral wäre er sogar nützlich), und der persistente Build-Cache (unten). Fork-PRs bleiben über das Gate auf ubuntu-latest; Umschalten via Repo-Variable CI_RUNNER. Kapazität beachten: Pinnt CI auf hot, ist die Zahl der hot-Runner die Parallelitäts-Obergrenze — genügend hot-Runner bereitstellen (≥ breitester Job-Fächer).

Persistenter Build-Cache (nur hot): Der Angular-Disk-Cache (.angular/cache) beschleunigt Folge-Builds inkrementell. Zwei Voraussetzungen, beide gesetzt: (1) angular.jsoncli.cache.environment: "all" (Angular deaktiviert den Cache in CI sonst per Default), (2) actions/checkout mit clean: false im Client-Job, damit der (gitignorierte) Cache den git clean -ffdx überlebt. Der Cache ist content-adressiert (selbst-invalidierend) → unbedenklich; auf ephemeral/Fork-Runnern ist er wirkungslos (kein Zustand), aber nie schädlich.

Auto-Rerun bei flakigem Runner (auto-rerun.yml): Schlägt ein CI-Lauf fehl, stößt ein workflow_run-getriggerter Job die fehlgeschlagenen Jobs einmalig neu an (run_attempt < 2 deckelt auf genau 1 Retry → kein Loop). Heilt die typische self-hosted-Flakiness (github.com:443-Timeout, Runner mitten im Job gestorben, Laptop zu). Nicht neugestartet: abgebrochene Läufe (Concurrency-Cancel = cancelledfailure) und Fork-PRs. Ein echter Test-Fail läuft im Retry erneut rot (Preis: ein Extra-Lauf je Fehlschlag; auf self-hosted ohne Minuten-Kosten vertretbar). Deploys sind bewusst ausgenommen (bei Bedarf manuell re-runnen).

6.9 Kanonische PR-Checkliste (OP-DOCS-15)

Die vollständige Liste aller Je-PR-Pflichten steht an genau einem Ort: .github/PULL_REQUEST_TEMPLATE.md — GitHub legt sie jedem neuen PR automatisch in den Body (Checkboxen). Hintergrund: das Doku-Review 2026-07 (Befund D5) belegte ~20 Pflichten verstreut über ≥5 Orte, einige nur als Tabellenzelle (z. B. Funktionsumfang-Pflicht) — Rezept für selektive Compliance.

Rollenverteilung (kein neuer Regel-Owner!): Die Checkliste ist eine Sicht; jede Pflicht zitiert ihre Owner-Regel (CLAUDE.md bzw. dieses Dokument). Pflege-Regel: Wer eine Je-PR-Pflicht einführt, ändert oder streicht, zieht das Template im selben PR nach — eine Pflicht, die dort fehlt, existiert praktisch nicht. Agenten, die PRs per API erstellen (eigener Body statt Template), arbeiten die Checkliste inhaltlich ab und spiegeln die Struktur im PR-Body.

7. Branch- und Push-Konventionen

  • Default-Branch: main.
  • GitHub-Operationen über die GitHub-API/MCP, nicht über lokales git/gh (verbindlich, v. a. in der Remote-/Cloud-Session): Remote-Schreibvorgänge — PR anlegen/mergen, Review-/Issue-Kommentare, Commits/Pushes auf Remote-Branches — laufen über die GitHub-MCP-Tools (create_pull_request, merge_pull_request, create_or_update_file/push_files, add_issue_comment, …); CI-Status & Mergeability über pull_request_read (get_status/get_check_runs) prüfen, nicht erraten. Grund: in der Remote-Ausführungs-Umgebung sind lokale git-Schreibbefehle (push/commit) unzuverlässig (der Permission-Stream bricht intermittierend ab); die API ist robust, atomar und permissions-arm. Lokales git bleibt für lokale Arbeit ok (Branch anlegen, Merge/Rebase + Konflikt-Auflösung im Arbeitsbaum, Reads wie status/diff/log). Der „go"-Gate (unten) gilt unverändert — nur der Transport-Weg ist die API.
  • Neuer Code (KI) → immer zuerst einen neuen Branch anlegen und nur dort arbeiten. Verbindlich: Erzeugt/ändert ein KI-Agent Code, legt er vor der ersten Änderung einen Feature-Branch an (git checkout -b …) und committet/pusht ausschließlich dort; Merge nach main nur via PR (mit grüner CI). Niemals Code direkt auf main.
  • Doku-Fast-Track statt Direkt-Push: Auch reine Doku-Änderungen laufen über Branch + PR (nie Direkt-Push auf main) — der Audit-/PR-Nummern-Trail bleibt lückenlos (§5.1, CHANGELOG „je PR ein Eintrag"). Damit das friktionsfrei bleibt, gilt für PRs, deren Diff ausschließlich Doku berührt (alle geänderten Dateien liegen unter docs/ oder sind *.md): (1) die schweren CI-Jobs (Server/Client/Solver/Design/SBOM) werden übersprungen — der changes-Job in ci.yml erkennt „docs-only" und der aggregierte CI Gate (einziger Required-Check) wird trotzdem grün; (2) Auto-Merge darf aktiviert werden (GitHub „Auto-merge", Squash). So ist ein Doku-PR praktisch Ein-Klick, ohne die App-CI zu binden. Sobald eine Nicht-Doku-Datei im Diff ist, läuft die volle CI (Fast-Track entfällt automatisch). Repo-Voraussetzung: Branch-Protection von main verlangt nur den Check CI Gate (nicht die Einzel-Jobs), und „Allow auto-merge" ist aktiv.
  • Force-Pushes nur lokal, niemals auf shared Branches.
  • „go"-Gate: Commit, Push und Merge erfolgen nur auf explizites „go" des Users. Einen Branch anlegen + Dateien im Arbeitsbaum vorbereiten ist ok; das Schreiben in die Historie / nach außen (Push, PR, Merge) wartet auf „go".
  • pr-weise: offene PRs einzeln mergen (einer nach dem anderen), jeweils mit grüner CI — kein Sammel-Merge.
  • Branch laufend auf main aktuell halten: Den Feature-Branch nicht nur am Ende, sondern durchgängig auf den aktuellen main bringen — (1) zu Beginn, bevor inhaltliche Änderungen starten (frisch von main abzweigen bzw. direkt aktualisieren); (2) in vernünftigen Abständen während längerer Arbeit; (3) vor dem Erstellen des PR; (4) vor dem Merge. Mechanik: git fetch origin maingit rebase origin/main (bei bereits geteiltem/gestapeltem Branch: git merge origin/main). Grund: main bewegt sich durch parallele Merges; frühes + regelmäßiges Aktualisieren hält die Divergenz klein — etwaige Konflikte entstehen lokal beim Autor (nicht erst beim Merge als „base branch was modified") und bleiben winzig.
  • Branch nach Merge schließen: Sobald ein PR gemergt ist, wird der zugehörige Feature-Branch gelöscht (remote und lokal) — kein Sammeln verwaister Branches. Empfohlen ist die GitHub-Repo-Einstellung „Automatically delete head branches" (löscht den Head-Branch automatisch beim Merge); ist sie nicht aktiv, löscht der Agent den Branch unmittelbar nach dem Merge selbst (git push origin --delete <branch> + git branch -d <branch>). Ausnahme nur für Branches, die noch von anderen offenen PRs als Basis dienen.
  • Feature-Branches aktuell halten: Laufende Feature-Branches werden regelmäßig gegen main aktualisiert, damit zwischenzeitlich gemergte PRs einfließen und Konflikte klein bleiben. Konkret: zu Session-Beginn und vor PR-Erstellung git fetch origin main und main in den Branch mergen bzw. den Branch darauf rebasen; bei langen Sessions auch zwischendurch, sobald relevante PRs auf main landen.
  • Doku-Pflicht je PR & Merge: Jeder PR pflegt HANDOFF.md und docs/betrieb/Timesheet.md mit (und die fachlich betroffenen Docs — Lastenheft, Design-Docs, Sanity-Checkliste; goldene Doku-Regel §5.1). Konkret: (a) vor dem Erstellen eines PR ist HANDOFF (§2 Stand) + betroffene ops/-Dateien auf den Stand des Branches gebracht und der Timesheet-Eintrag der Session aktualisiert; (b) beim Merge wird, falls sich seit PR-Erstellung etwas geändert hat, HANDOFF nachgezogen. Ein PR ohne HANDOFF-/Timesheet-Pflege gilt als unvollständig.

8. Cowork-Setup-Snippet (für eine neue Session)

Was der User in der ersten Nachricht typischerweise sagt:

Lies HANDOFF.md und docs/konventionen/agents.md. Dann arbeiten wir an: <Aufgabe>.

Damit hat der Agent (a) den aktuellen Stand, (b) die Konventionen, (c) den Auftrag — und kann sofort liefern.

9. Was nicht in dieses Repo gehört

  • Personendaten realer Kunden / Mitarbeiter (auch nicht in Beispielen — die im Lastenheft sind synthetisch).
  • Secrets, API-Keys, Tokens (für CI: GitHub Encrypted Secrets nutzen).
  • Generierte Build-Artefakte (dist/, .angular/, .wrangler/ — siehe .gitignore).
  • Binär-Exporte als „Master" (.docx, .pdf). Falls jemand temporär einen Export braucht, kann er ihn lokal aus Lastenheft.md generieren, sollte ihn aber nicht committen.

Letztes Update: 27.06.2026 (Way-of-Working: Doku-Fast-Track — reine Doku-PRs überspringen die schwere CI [changes-Job + aggregierter CI Gate als einziger Required-Check] und dürfen per Auto-Merge durch; §7 — baut auf OP-PM-2 [union-Merge-Logs + Auto-Build-Nummer, §6.6] auf). Frühere: 26.06.: GitHub-Operationen über die GitHub-API/MCP statt lokales git/gh für Remote-Writes (§7; lokales git push/commit ist in der Remote-Session unzuverlässig). 23.06.: Branch laufend auf main aktuell halten — zu Beginn, in Abständen, vor PR & vor Merge [fetch+rebase/merge origin/main]. 22.06.: goldene Doku-Regel · Annahmen-sichtbar/Optionen-zuerst · Verifizieren statt behaupten · Timesheet-Pflicht · „go"-Gate · pr-weise · Branch nach Merge schließen · Doku-Pflicht je PR & Merge: HANDOFF + Timesheet.