From ac67d6c83eda5116c4d24dd51fe8fc319707a458 Mon Sep 17 00:00:00 2001 From: Benjamin Tenke Date: Sat, 3 Oct 2026 15:44:41 +0200 Subject: [PATCH 01/31] docs: plan context sources in BPMN Co-Authored-By: Claude Opus 5.5 --- docs/plans/kontextquellen/plan.md | 151 +++++++++++++++++++ docs/plans/kontextquellen/tasks.md | 226 +++++++++++++++++++++++++++++ 2 files changed, 377 insertions(+) create mode 100644 docs/plans/kontextquellen/plan.md create mode 100644 docs/plans/kontextquellen/tasks.md diff --git a/docs/plans/kontextquellen/plan.md b/docs/plans/kontextquellen/plan.md new file mode 100644 index 0000000..1dfd2d2 --- /dev/null +++ b/docs/plans/kontextquellen/plan.md @@ -0,0 +1,151 @@ +# Kontextquellen im BPMN modellieren + +Status: Entwurf, abgestimmt am 2026-10-03. Aufgaben: [`tasks.md`](tasks.md). + +## Ziel + +Kontext ist am Ende Daten. Wer einen Prozess für lanecraft modelliert, soll beim Zeichnen +überlegen, **welche Daten jeder Schritt braucht und wo sie liegen**. Aus diesen Angaben baut die +Pipeline Wissensreferenzen, Tool-Freigaben, Schreibschutz und ein Gedächtnis über Läufe hinweg. + +Heute modelliert das Diagramm nur Übergaben (Data Objects → Artefaktverträge). Wissensquellen +ordnet `bpmn2agent-knowledge` erst nachträglich Lanes zu. `dataStoreReference` ignoriert die +Pipeline (`inventory.mjs` überspringt es, die Mapping-Ansicht würde es rot färben). + +## Notation + +Jede dauerhafte Quelle ist ein **Data Store** (Zylinder). Seine Dokumentation trägt zwei Zeilen: + +``` +Art: wissen | live | gedächtnis +Quelle: notebook: | mcp: | cli: | | datei: | websearch +``` + +- **Lesen/Schreiben ergibt sich nur aus der Pfeilrichtung.** Store → Task heißt lesen, + Task → Store heißt schreiben. Es gibt keine `Zugriff:`-Zeile. +- **Ein Store ist ein fachlicher Datenbestand**, z. B. „Jira-Tickets Projekt LANE“, und kein + System. Mehrere Stores dürfen dieselbe `Quelle:` haben. +- **Fehlt eine Zeile, fragt analyze nach.** Unsinnige Kombinationen (Matrix unten) ebenfalls. + +### Art × Quelle + +| Art | erlaubte Quelle | geladen | wird zu | +|---|---|---|---| +| `wissen` | `notebook:`, URL, `datei:`, `websearch` | bei der Generierung | `knowledge/.md` → Skill-`references/` | +| `wissen` | `mcp:` | bei der Generierung (Snapshot), nur wenn der Server verbunden ist | wie oben | +| `live` | `mcp:`, `cli:` | zur Laufzeit | Tool-Allowlist + `## Kontextquellen` im Skill | +| `live` | `notebook:` | zur Laufzeit, behandelt als `mcp:gemini-notebook-mcp` | wie oben | +| `live` | URL | zur Laufzeit | `WebFetch` | +| `live` | `datei:` | zur Laufzeit | `Read` | +| `gedächtnis` | `datei:` (Standard `.claude/memory//.md`) | zu Laufbeginn gelesen, am Ende geschrieben | kuratierte Datei + Cap-Hook | + +### Prozess-Ein- und -Ausgabe + +- **Eingabe:** ein echtes prozessweites `dataInput` (über bpmn-authoring geschrieben; bpmn.io + rendert es, hat aber keinen Palette-Eintrag) **oder** die Konvention „Data Object ohne + Erzeuger, das ein Task liest“. +- **Ausgabe:** `dataOutput` **oder** „Data Object, das niemand liest“. +- **Was daraus wird:** Die Eingabe wird ein Artefaktvertrag mit Pflichtfeldern. Der Orchestrator + bekommt daraus ein `argument-hint` und fragt nach, wenn ein Pflichtfeld fehlt. Die Ausgabe wird + der Vertrag für das Endergebnis. + +## Regeln + +### Wissen + +- **Das Diagramm ist die Quelle der Wahrheit.** Die Pfeile von Wissens-Stores sind die Zuordnung. + knowledge fragt nicht mehr „welches Notebook deckt welche Lane ab“, sondern extrahiert pro + lesendem Task aus genau dieser Quelle. +- **Eine Datei pro Task:** `knowledge/.md`, ein Abschnitt pro Store, Zitate je Abschnitt. +- **Rückfall:** Diagramme ohne Wissens-Store und Tasks ohne Wissens-Eingang nutzen die bisherige + Lane-Zuordnung, mit dem Hinweis, dass Stores genauer wären. + +### Live + +- **Tools auflösen:** design holt die Tool-Liste des Servers per ToolSearch und sortiert nach + Namen. `get/list/search/read/fetch/view` gilt als lesen, + `create/update/delete/add/post/edit/transition/push` als schreiben. Wo der Server + `readOnlyHint` liefert, gilt der. **Unklar heißt schreiben.** Die Nutzerin bestätigt die Liste im + Mapping-Plan. +- **Server nicht verbunden:** Der Store bleibt `unresolved`. verify warnt, generate lässt die + Tools weg (kein Wildcard). +- **Wohin die Tools gehen:** Wo Lanes Agents sind (orchestrator-agent), in `tools:` des + Lane-Agents, nur die nötigen Lese-Tools. Sonst in `.claude/settings.json` → + `permissions.allow` (Vereinigung aller Lese-Tools), und der Mapping-Plan sagt offen + „Lesezugriff nicht pro Rolle getrennt“. Unterscheiden sich die nötigen Rechte der Rollen, gibt + die Rubrik das als Signal für orchestrator-agent aus. +- **Skill-Text:** Jeder lesende Task bekommt einen Abschnitt `## Kontextquellen` mit dem + Store-Namen (wörtlich), was für diesen Schritt zu holen ist und mit welchem Tool. + +### Schreiben in Live-Stores + +- **Vor jedem Schreiben ein `userTask`:** verify meldet einen Fehler, wenn nicht auf jedem Pfad + ein `userTask` vor dem Schreiben liegt. +- **Hook als Rückhalt:** generate erzeugt einen PreToolUse-Hook, der für die Schreib-Tools + `permissionDecision: "ask"` zurückgibt. Claude Code fragt den Menschen dann direkt beim Aufruf. +- **Musterwahl:** Eine Phase, die in einen Live-Store schreibt, darf nicht workflow-script sein, + weil dieses Muster keine menschlichen Checkpoints erlaubt. + +### Gedächtnis + +- **Ablage:** `.claude/memory//.md` relativ zum cwd des Laufs, überschreibbar + mit `Quelle: datei:`. Das Gedächtnis liegt im Projekt der Nutzerin, nicht im Plugin. +- **Format:** ein kuratiertes Dokument mit festen Abschnitten (*Bewährt*, *Vermeiden*, + *Offene Muster*) und höchstens 150 Zeilen. Der schreibende Task führt neue Erkenntnisse ein, + statt sie anzuhängen. +- **Schreiber und Leser:** Ein Gedächtnis-Store braucht mindestens einen schreibenden + `serviceTask` und einen Leser. Fehlt einer, fragt analyze nach. Schreiben braucht keine + Freigabe. +- **Cap:** Ein PostToolUse-Hook auf Schreibzugriffe auf den Gedächtnispfad meldet bei über + 150 Zeilen Exit 2 mit „verdichten“ an Claude zurück. + +### Rückverfolgung und Mapping-Ansicht + +- **Stores:** Jeder Store bekommt `elements.` mit `kind: context-source` und eine + eigene Farbe (Türkis). verify verlangt den Eintrag wie bei Flow Nodes; fehlt er, ist der Store + rot. +- **Prozess-I/O:** Bekommt `kind: workflow-input` / `workflow-output` und wird aus + `ioSpecification` indiziert. + +## Spec-Erweiterung (`workflow-spec.yaml`) + +```yaml +contextSources: + jira-tickets-lane: + name: Jira-Tickets Projekt LANE # Label wörtlich + bpmnElement: DataStore_JiraTickets + art: live # wissen | live | gedaechtnis + quelle: { type: mcp, ref: atlassian } # notebook|mcp|cli|url|datei|websearch + readers: [Task_TicketAnalysieren] + writers: [Task_KommentarPosten] + tools: # nur art: live; oder: unresolved + read: [mcp__atlassian__getJiraIssue] + write: [mcp__atlassian__addCommentToJiraIssue] + memory: { path: .claude/memory//.md, maxLines: 150 } # nur gedaechtnis +workflowIO: + input: { artifact: , required: [ticketId] } + output: { artifact: } +``` + +`contextSources` steht bewusst neben `artifacts`. Artefakte gelten nur für einen Lauf, Stores +haben einen anderen Lebenszyklus und andere Felder. + +## Nicht in v1 + +- **Datenzustände** (`[freigegeben]`) und daraus abgeleitete Status-Hooks +- **Freigabe-Records** zur Laufzeit (`runs//approvals/…`) +- **Zusätzliche Lint-Regeln:** toter Store, `serviceTask` ohne Eingang +- **Pro-Lane-Tools im workflow-script-Muster** (`agent({ agentType })`) +- **`.mcp.json`-Erzeugung:** keine Endpunkte oder Zugangsdaten im generierten Output +- **Änderungen am dark-factory-Beispiel** (bleibt Snapshot) + +## Prüfstand + +Neue Fixture `.agents/skills/bpmn2agent-verify/fixtures/context-flow.bpmn` mit: +- je einem Store pro Art +- einem geschützten Schreiben (`userTask` → Schreib-Task → Live-Store) +- Prozess-Ein- und -Ausgabe (einmal echt, einmal per Konvention) +- einem ungeschützten Schreiben in einer Negativ-Variante + +Die ganze Pipeline läuft darauf. verify muss für die positive Fixture grün sein und für die +Negativ-Variante den Schreibfehler melden. diff --git a/docs/plans/kontextquellen/tasks.md b/docs/plans/kontextquellen/tasks.md new file mode 100644 index 0000000..bc116f2 --- /dev/null +++ b/docs/plans/kontextquellen/tasks.md @@ -0,0 +1,226 @@ +# Aufgaben: Kontextquellen im BPMN + +Plan: [`plan.md`](plan.md). Branch `feat/context-sources`. Ein Commit pro Aufgabe +(Conventional Commits, Scope in Klammern). Jede Aufgabe endet mit `npm run validate`. + +## Reihenfolge + +``` +Welle 1: T1 Spec-Vertrag T2 Authoring + Fixture T3 process-design + │ │ +Welle 2: └──────── T4 analyze ┘ + │ +Welle 3: T5 knowledge T6 design T7 verify + │ +Welle 4: T8 generate + │ +Welle 5: T9 Doku T10 Ende-zu-Ende +``` + +Aufgaben in derselben Welle sind unabhängig und können parallel laufen. + +--- + +## T1 — Spec-Vertrag: Schema und Mapping-Rubrik + +`feat(design): add contextSources and workflowIO to the spec contract` + +- **Dateien:** + - `.agents/skills/bpmn2agent-design/assets/workflow-spec.schema.yaml` + - `.agents/skills/bpmn2agent-design/references/mapping-rubric.md` +- **Schema:** + - neue Top-Level-Abschnitte `contextSources.` und `workflowIO`, Felder wie in + plan.md §Spec-Erweiterung + - `tools` ist entweder `{read, write}` oder `unresolved` + - `memory` nur bei `art: gedaechtnis` +- **Neue Element-Kinds:** `context-source`, `workflow-input`, `workflow-output`. +- **Rubrik:** + - Zeilen für Data Store je Art und für Prozess-I/O + - die Art×Quelle-Matrix + - die Regel „Schreiben in Live-Store braucht `userTask`, nicht workflow-script“ + - Platzierung der Tools (Agent-`tools:` vs. `permissions.allow`) + - Farbe Türkis in der Farbtabelle + - Musterhinweis „unterschiedliche Rechte je Rolle → orchestrator-agent“ +- **Abnahme:** + - Das Schema validiert ein Beispiel-Snippet mit allen drei Arten. + - Bestehende Specs (dark-factory, verify-Fixtures) validieren weiterhin, weil alle neuen + Felder optional sind. + +## T2 — bpmn-authoring: Stores und Prozess-I/O zeichnen, Fixture anlegen + +`feat(bpmn-authoring): support data stores and process io; add context-flow fixture` + +- **Dateien:** + - `.agents/skills/bpmn-authoring/references/xml-and-di.md` + - `.agents/skills/bpmn-authoring/references/layout.md` + - `.agents/skills/bpmn2agent-verify/fixtures/context-flow.bpmn` + - `.agents/skills/bpmn2agent-verify/fixtures/context-flow-unguarded.bpmn` +- **XML und DI:** + - `dataStore` (Root) + `dataStoreReference` (sichtbar, 50×50), Dokumentation mit + `Art:`/`Quelle:` + - prozessweite `ioSpecification` mit `dataInput`/`dataOutput` + `inputSet`/`outputSet` + - DI-Hinweis: Shapes für dataInput/dataOutput sind nötig, damit bpmn-js sie zeichnet; + bpmnlint verlangt sie nicht +- **Layout:** Stores unterhalb der Lane ihres ersten Lesers. Prozess-Eingabe links neben dem + Start, Ausgabe rechts neben dem Ende. +- **Positive Fixture:** + - je ein Store `wissen` (notebook), `live` (mcp, gelesen + geschrieben nach `userTask`) und + `gedächtnis` + - ein echtes `dataInput` und eine Ausgabe per Konvention +- **Negativ-Fixture:** dieselbe, aber ohne den `userTask` vor dem Schreiben. +- **Abnahme:** Beide Fixtures bestehen `validate.sh` (XSD, moddle ohne Warnungen, + bpmnlint:recommended ohne Warnungen) und rendern sauber. + +## T3 — bpmn-process-design: Kontext beim Modellieren abfragen + +`feat(skills): ask for context sources in bpmn-process-design` + +- **Datei:** `.agents/skills/bpmn-process-design/SKILL.md` +- **Inhalt:** + - Notationstabelle um Data Store (drei Arten) und Prozess-I/O ergänzen + - Regeln: Store = fachlicher Datenbestand; Pfeilrichtung = lesen/schreiben; `userTask` vor + Schreiben in Live-Stores; Gedächtnis braucht Schreiber und Leser +- **Outline (§5):** pro Schritt die Frage „Was muss dieser Schritt wissen, und wo liegt es?“. + Die Bestätigungsübersicht zeigt Stores mit Art, Quelle, Lesern und Schreibern sowie die + Prozess-Eingabe mit Pflichtfeldern. +- **Abhängig von:** nur plan.md (läuft parallel zu T1/T2). +- **Abnahme:** `npm run validate` grün. Der Text bleibt schlank (Skill-Authoring-Regeln). + +## T4 — analyze: Stores und Prozess-I/O inventarisieren + +`feat(analyze): inventory data stores and process io into contextSources` + +- **Abhängig von:** T1, T2 +- **Dateien:** + - `.agents/skills/bpmn2agent-analyze/scripts/inventory.mjs` + - `.agents/skills/bpmn2agent-analyze/SKILL.md` + - `.agents/skills/bpmn2agent-analyze/references/conventions.md` +- **inventory.mjs:** + - `dataStoreReference` mit Name, Dokumentation (geparste `Art:`/`Quelle:`), Scope + - Leser und Schreiber aus den Data Associations + - prozessweite `ioSpecification` + - Konventions-I/O: Data Object ohne Erzeuger, das gelesen wird, und Data Object ohne Leser +- **SKILL.md:** + - `contextSources` und `workflowIO` in den Spec-Entwurf schreiben + - per `AskUserQuestion` nachfragen bei: fehlendem `Art:`/`Quelle:`, ungültiger Kombination, + Gedächtnis ohne Schreiber oder Leser + - Stores in den ID-Diff bei geänderten Diagrammen aufnehmen +- **Abnahme:** + - Die Inventur der Fixture listet alle drei Stores mit korrekten Lesern/Schreibern und beide + I/O-Varianten. + - dark-factory-Inventur unverändert (Diff leer bis auf neue leere Felder). + +## T5 — knowledge: Zuordnung aus dem Diagramm + +`feat(knowledge): ground tasks from knowledge stores in the diagram` + +- **Abhängig von:** T4 +- **Dateien:** + - `.agents/skills/bpmn2agent-knowledge/SKILL.md` + - `.agents/skills/bpmn2agent-knowledge/references/notebook-extraction.md` +- **Inhalt:** + - Wissens-Stores ersetzen §2 „welches Notebook für welche Lane“. Die Quelle wird je nach + Typ aufgelöst (`notebook:` über notebook_list per Titel, URL per WebFetch, `datei:` als + lokales Doc, `websearch`, `mcp:` als Snapshot nur bei verbundenem Server). + - Pro lesendem Task `knowledge/.md`, ein Abschnitt pro Store. + - Lane-Rückfall für Tasks ohne Wissens-Store. + - `serviceTask` ohne jeden Wissens-Eingang wird als offene Frage erfasst, nicht als Fehler. +- **Abnahme:** Ein Lauf auf der Fixture erzeugt Dateien je Task mit Quellenangaben. Diagramme + ohne Stores laufen wie bisher. + +## T6 — design: Tools auflösen und Mapping-Plan + +`feat(design): resolve live store tools and place them per role` + +- **Abhängig von:** T1, T4 +- **Dateien:** + - `.agents/skills/bpmn2agent-design/SKILL.md` + - `references/mapping-rubric.md` (Ergänzung zu T1) + - `references/pattern-rubric.md` +- **Tools auflösen:** + - `mcp:` per ToolSearch auf `mcp____` + - Namensheuristik plus `readOnlyHint`; unklar = schreiben + - `cli:` als `Bash( :*)`-Muster, gleiche Heuristik auf die Unterbefehle + - nicht verbunden → `unresolved` +- **Platzierung:** Agent-`tools:` bei orchestrator-agent, sonst `permissions.allow`. +- **Musterwahl:** Eine Phase mit Schreiben in einen Live-Store wird nicht workflow-script. +- **Mapping-Plan:** listet je Store Art, Quelle, Leser/Schreiber und die Tool-Aufteilung zur + Bestätigung, inkl. „Lesezugriff nicht pro Rolle getrennt“, wo zutreffend. +- **Abnahme:** Die Spec der Fixture hat vollständige `contextSources.*.tools` (oder + `unresolved`) und `elements.*` für alle Stores. + +## T7 — verify: Stores prüfen + +`feat(verify): trace context sources and guard live store writes` + +- **Abhängig von:** T1, T4 (läuft parallel zu T5/T6, testet gegen handgeschriebene Spec) +- **Dateien:** + - `.agents/skills/bpmn2agent-verify/scripts/verify.mjs` + - `.agents/skills/bpmn2agent-verify/SKILL.md` +- **Prüfungen:** + - Jeder Store und jedes Prozess-I/O-Element braucht einen `elements`-Eintrag. + - `contextSources.*.readers/writers` müssen mit den Associations übereinstimmen. + - **Schreiben in Live-Store ohne `userTask` auf jedem Pfad → Fehler** (Pfadanalyse über + Sequenzflüsse, Schleifen beachten). + - Live-Schreiben in einer workflow-script-Phase → Fehler. + - `tools: unresolved` → Warnung. +- **Fehlermeldungen:** in Fachsprache, geroutet an analyze/design/generate. +- **Abnahme:** Die positive Fixture besteht diese Prüfungen. Die Negativ-Fixture meldet genau + den Schreibfehler, geroutet an analyze (Diagramm ändern). + +## T8 — generate: Dateien erzeugen + +`feat(generate): emit context sources, write guard and memory hooks` + +- **Abhängig von:** T6 (T7 für die Prüfung) +- **Dateien:** + - `.agents/skills/bpmn2agent-generate/SKILL.md` + - `assets/templates/*` (skill, agent, orchestrator, settings, hook, README, mapping-report) + - `scripts/render-mapping.mjs` + - `scripts/check-mapping-view.mjs` +- **Skill- und Agent-Templates:** Abschnitt `## Kontextquellen`; `tools:`-Platzhalter in + Agent-Templates. +- **settings.json:** `permissions.allow` mit den Lese-Tools, wo Lanes keine Agents sind. +- **Schreibschutz-Hook:** PreToolUse, Matcher = Schreib-Tools aller Live-Stores, + `permissionDecision: "ask"` mit Begründung (Store-Name, Freigabe-Task). +- **Gedächtnis:** + - PostToolUse-Hook auf Schreibzugriffe auf den Gedächtnispfad; über `maxLines` → Exit 2 + „verdichten“ + - Skill-Text für Schreiber: einpflegen statt anhängen, feste Abschnitte, Cap + - Leser laden die Datei zuerst; leer oder fehlend ist in Ordnung +- **Orchestrator:** `argument-hint` aus `workflowIO.input`; fragt nach, wenn ein Pflichtfeld + fehlt. +- **README:** Voraussetzungen (MCP-Server, CLIs), Gedächtnisablage. +- **Mapping-Ansicht:** `context-source` in Türkis, Prozess-I/O aus `ioSpecification` + indizieren, Stores ohne Eintrag rot. +- **Abnahme:** Generate auf der Fixture, danach verify grün und `check-mapping-view` ohne Rot. + +## T9 — Doku + +`docs: describe context sources in README and ARCHITECTURE` + +- **Abhängig von:** T3–T8 +- **Dateien:** + - `ARCHITECTURE.md` + - `README.md` + - `.agents/skills/agentic-workflow-kb/references/process-to-agents.md` + - `.agents/skills/agentic-workflow-kb/references/multi-agent-handoffs.md` +- **ARCHITECTURE.md:** Abschnitt Kontextquellen (Notation, Art×Quelle, Weg durch die Stufen). +- **README.md:** Kurzbeschreibung + Beispiel aus der Fixture. +- **Agent-Definitionen:** `agentic-workflow-architect` und `agentic-artifact-reviewer` prüfen + Stores mit: ungeschütztes Schreiben, zu breite Tool-Listen, Gedächtnis ohne Cap. +- **Abnahme:** `npm run validate` grün. Doku auf Deutsch, Skill-Text auf Englisch. + +## T10 — Ende-zu-Ende + +`test: run the full pipeline on the context-flow fixture` + +- **Abhängig von:** alle +- **Ablauf:** `bpmn-to-agentic-workflow` auf `context-flow.bpmn` in einem Scratch-Verzeichnis + (analyze → knowledge → design → generate → verify) laufen lassen. +- **Abnahme:** + - verify grün, Mapping-Ansicht ohne Rot. + - Hooks per Smoke-Test: Schreib-Tool → `ask`; Gedächtnis mit 151 Zeilen → Exit 2. + - Negativ-Fixture scheitert an verify mit der erwarteten Meldung. + - `examples/dark-factory/tools/dark-factory-gen/regenerate.sh` endet weiterhin mit + `RESULT: PASS`, `no reference problems`, den drei Smoke-Zeilen und `mapping view ok`. From 1df1ada3dceabc30fe16bc84b9613120da52d877 Mon Sep 17 00:00:00 2001 From: Benjamin Tenke Date: Sat, 3 Oct 2026 15:47:08 +0200 Subject: [PATCH 02/31] feat(skills): ask for context sources in bpmn-process-design Co-Authored-By: Claude Sonnet 5.5 --- .agents/skills/bpmn-process-design/SKILL.md | 33 +++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/.agents/skills/bpmn-process-design/SKILL.md b/.agents/skills/bpmn-process-design/SKILL.md index 1c6e3f7..0e87488 100644 --- a/.agents/skills/bpmn-process-design/SKILL.md +++ b/.agents/skills/bpmn-process-design/SKILL.md @@ -1,6 +1,6 @@ --- name: bpmn-process-design -description: Designs a new process from what the user wants to build plus domain knowledge from Gemini notebooks (NotebookLM, via gemini-notebook-mcp), and draws it as an agent-ready BPMN 2.0 diagram in the lanecraft notation (lane = role, serviceTask = AI, userTask = human checkpoint, scriptTask = script, data object = handoff, capped loops) that the bpmn2agent pipeline turns into agents and skills without rework. Use for "model a process for X", "draw the BPMN for what I want to build", "design a workflow from my notebook", or when a user has a goal but no diagram yet. To edit an existing .bpmn use bpmn-authoring; to turn a finished diagram into agents use bpmn-to-agentic-workflow. +description: Designs a new process from what the user wants to build plus domain knowledge from Gemini notebooks (NotebookLM, via gemini-notebook-mcp), and draws it as an agent-ready BPMN 2.0 diagram in the lanecraft notation (lane = role, serviceTask = AI, userTask = human checkpoint, scriptTask = script, data object = handoff, data store = context source, capped loops) that the bpmn2agent pipeline turns into agents and skills without rework. Use for "model a process for X", "draw the BPMN for what I want to build", "design a workflow from my notebook", or when a user has a goal but no diagram yet. To edit an existing .bpmn use bpmn-authoring; to turn a finished diagram into agents use bpmn-to-agentic-workflow. --- # Design an agent-ready BPMN process @@ -59,6 +59,10 @@ model-only steps `⚠ unverified`. | exclusive / parallel gateway | branches, joins or loops | orchestrator logic | | collapsed `subProcess` | is a phase with its own sequence | reusable skill or sub-workflow | | data object | is a result a later step needs | artifact contract | +| data store `Art: wissen` | holds reference knowledge a step must know | cited reference in the reading skill, loaded at generation | +| data store `Art: live` | holds data read or changed at run time | tool allowlist + `## Kontextquellen` in the skill | +| data store `Art: gedächtnis` | keeps learnings across runs | curated memory file with a size cap | +| process input / output | is what a run needs to start / finally delivers | argument contract with required fields / result contract | - 2–6 lanes, one per role, never one per task. A role that only decides is a human lane of `userTask`s. @@ -71,6 +75,17 @@ model-only steps `⚠ unverified`. (`Nein (max. 3×)`, default 3), and has a way out (escalation `userTask` or end). - Results cross lanes as data objects. Every task gets `Input: … Output: … Quelle: `. +- A data store is a business data set named in business terms ("Jira-Tickets Projekt LANE"), not a + system; several stores may share one source. Its documentation carries `Art: wissen | live | + gedächtnis` and `Quelle: notebook: | mcp: | cli: | | datei: | + websearch`. Notebooks picked in step 2 are candidates for `wissen` stores. +- Valid pairs: `wissen` with `notebook:`, URL, `datei:`, `websearch`, or `mcp:` (a snapshot, only if + the server is connected); `live` with `mcp:`, `cli:`, `notebook:`, URL or `datei:`; `gedächtnis` + with `datei:` only (default `.claude/memory//.md`). Anything else: pick another + Art or Quelle. +- Read or write follows only the arrow: store → task reads, task → store writes. No `Zugriff:` line. +- A `userTask` precedes every write to a `live` store, on every path. +- A `gedächtnis` store needs a `serviceTask` that writes it and a reader; writing needs no approval. - A phase over ~8 steps becomes a collapsed `subProcess` with its own lanes. - One pool; no message flows, timer or message events, event sub-processes or compensation (rewrites: `${CLAUDE_SKILL_DIR}/../bpmn2agent-analyze/references/unsupported.md`). Error @@ -78,15 +93,23 @@ model-only steps `⚠ unverified`. ## 5. Confirm the outline +For each step ask: "What must this step know, and where does it live?" Every answer is a store +(Art, Quelle), a data object from an earlier step, or the process input; nothing means the step +needs no context. Does it write anywhere? Then name the store and the `userTask` before it. + Before drawing, show: lanes with what each becomes, then per phase the steps with type -(AI / human / script / rule) and source, gateways with answers, loops with caps, data objects. Ask: -draw as is / change what / ask the notebook more. Repeat until confirmed; never draw an unconfirmed -design. +(AI / human / script / rule) and source, gateways with answers, loops with caps, data objects. Add +a store table (name, Art, Quelle, readers, writers) and the process input with its required fields +and the result the run delivers. Ask: draw as is / change what / ask the notebook more. Repeat until +confirmed; never draw an unconfirmed design. ## 6. Draw Follow `${CLAUDE_SKILL_DIR}/../bpmn-authoring/SKILL.md` steps 2–7, starting from its -`assets/skeleton.bpmn`. Use readable ids (`Task_FeedbackFormulieren`, `Gw_InvestErfuellt`). +`assets/skeleton.bpmn`. Use readable ids (`Task_FeedbackFormulieren`, `Gw_InvestErfuellt`). Draw +stores and the process input/output with its data store and `ioSpecification` conventions +(`${CLAUDE_SKILL_DIR}/../bpmn-authoring/references/xml-and-di.md` and `layout.md`); a +convention-based input is a data object no task produces. ## 7. Check it's agent-ready From 66c450d20eac5ed2408dfff9ef15aacf3f786f0c Mon Sep 17 00:00:00 2001 From: Benjamin Tenke Date: Sat, 3 Oct 2026 15:48:04 +0200 Subject: [PATCH 03/31] feat(design): add contextSources and workflowIO to the spec contract Co-Authored-By: Claude Sonnet 5.5 --- .../assets/workflow-spec.schema.yaml | 158 +++++++++++++++++- .../references/mapping-rubric.md | 47 ++++++ 2 files changed, 203 insertions(+), 2 deletions(-) diff --git a/.agents/skills/bpmn2agent-design/assets/workflow-spec.schema.yaml b/.agents/skills/bpmn2agent-design/assets/workflow-spec.schema.yaml index 3ff15dc..aa3c4d7 100644 --- a/.agents/skills/bpmn2agent-design/assets/workflow-spec.schema.yaml +++ b/.agents/skills/bpmn2agent-design/assets/workflow-spec.schema.yaml @@ -27,6 +27,14 @@ # sdlc:collection -> elements..collection # sdlc:bundle -> artifacts..bundledIn (informational, not a separate section) # +# Beyond the sdlc: vocabulary, two optional top-level sections carry context the diagram draws as +# data stores and process-wide input/output (plan: docs/plans/kontextquellen/plan.md): +# +# dataStoreReference -> contextSources. (+ elements..kind: context-source) +# ioSpecification dataInput/dataOutput (or the "no producer" / "no reader" data-object +# convention) -> workflowIO.{input,output} +# (+ elements..kind: workflow-input | workflow-output) +# $schema: "http://json-schema.org/draft-07/schema#" $id: "https://ai-sdlc.internal/schemas/bpmn2agent/workflow-spec.schema.yaml" title: workflow-spec @@ -63,6 +71,18 @@ properties: type: object additionalProperties: $ref: "#/definitions/artifact" + contextSources: + description: > + One entry per durable data store the diagram draws (bpmn:dataStoreReference): knowledge to + ground steps (wissen), a live system read/written at run time (live), or a curated memory file + carried across runs (gedaechtnis). Map key is a kebab-case store id. Deliberately separate from + `artifacts`: artifacts live for one run, stores outlive it and have different fields. Absent in + specs of diagrams without data stores. + type: object + additionalProperties: + $ref: "#/definitions/contextSource" + workflowIO: + $ref: "#/definitions/workflowIO" pattern: $ref: "#/definitions/pattern" knowledge: @@ -155,7 +175,7 @@ definitions: description: > BPMN element type, e.g. task/userTask/manualTask/serviceTask/scriptTask/businessRuleTask/ callActivity/subProcess/exclusiveGateway/parallelGateway/inclusiveGateway/startEvent/ - endEvent/boundaryEvent/dataObjectReference/lane. See mapping-rubric.md for the v1 + endEvent/boundaryEvent/dataObjectReference/dataStoreReference/dataInput/dataOutput/lane. See mapping-rubric.md for the v1 supported/unsupported construct list. label: type: string @@ -172,9 +192,16 @@ definitions: - orchestrator - human-checkpoint - artifact-contract + - context-source + - workflow-input + - workflow-output - not-generated - unresolved - description: Generation decision for this element. See mapping-rubric.md for how each is chosen. + description: > + Generation decision for this element. See mapping-rubric.md for how each is chosen. + context-source = a dataStoreReference (its details live in `contextSources.`); + workflow-input / workflow-output = the process-wide input/output (details in `workflowIO`). + None of the three has a generated file of its own. generatedPaths: type: array items: { type: string } @@ -300,6 +327,133 @@ definitions: items: { type: string } description: Ids of higher-level bundle artifacts this one rolls up into (sdlc:bundle equivalent), if any. + contextSource: + type: object + required: [name, bpmnElement, art, quelle] + additionalProperties: false + properties: + name: + type: string + description: Verbatim data store label from the BPMN (a business data set such as "Jira-Tickets Projekt LANE", not a system). + bpmnElement: + type: string + description: id of the bpmn:dataStoreReference; also the key into `elements` (kind context-source). + art: + enum: [wissen, live, gedaechtnis] + description: > + wissen = reference knowledge loaded at generation time into knowledge/.md; live = a + system read (and maybe written) at run time through tools; gedaechtnis = a curated memory + file read at the start and written at the end of a run. Valid Art x Quelle combinations are + in mapping-rubric.md. + quelle: + type: object + required: [type] + additionalProperties: false + properties: + type: + enum: [notebook, mcp, cli, url, datei, websearch] + ref: + type: string + description: > + notebook title, MCP server name, CLI command, URL or file path, as written after the + prefix of the diagram's "Quelle:" line. Omitted for websearch. + readers: + type: array + items: { type: string } + description: Element ids of tasks with a data input association from this store (store -> task = read). + writers: + type: array + items: { type: string } + description: Element ids of tasks with a data output association to this store (task -> store = write). + tools: + description: > + Only for art: live. Tools the readers/writers use, resolved by bpmn2agent-design (MCP tool + names, Bash( :*) patterns, WebFetch, Read) and split by read vs. write; unclear + counts as write. The literal "unresolved" means the source could not be resolved (e.g. MCP + server not connected): verify warns, generate emits no tools for it (never a wildcard). + oneOf: + - type: object + additionalProperties: false + properties: + read: + type: array + items: { type: string } + write: + type: array + items: { type: string } + - const: unresolved + memory: + type: object + required: [path] + additionalProperties: false + description: "Only for art: gedaechtnis." + properties: + path: + type: string + description: > + Memory file relative to the run's cwd; default .claude/memory//.md, + overridden by the diagram's "Quelle: datei:". + maxLines: + type: integer + minimum: 1 + default: 150 + description: Line cap enforced by a PostToolUse hook (exit 2 asks Claude to condense). + allOf: + - if: + properties: { art: { const: wissen } } + then: + properties: + quelle: + properties: + type: { enum: [notebook, mcp, url, datei, websearch] } + tools: false + memory: false + - if: + properties: { art: { const: live } } + then: + properties: + quelle: + properties: + type: { enum: [notebook, mcp, cli, url, datei] } + memory: false + - if: + properties: { art: { const: gedaechtnis } } + then: + properties: + quelle: + properties: + type: { const: datei } + tools: false + + workflowIO: + type: object + additionalProperties: false + description: > + Process-wide input and output: a real ioSpecification dataInput/dataOutput, or by convention a + data object nobody produces (input) / nobody reads (output). Both become artifact contracts; + the orchestrator derives its argument-hint from the input's required fields. + properties: + input: + type: object + required: [artifact] + additionalProperties: false + properties: + artifact: + type: string + description: Artifact type id; key into the top-level `artifacts` map. + required: + type: array + items: { type: string } + description: Frontmatter fields the orchestrator must have before starting; it asks when one is missing. + output: + type: object + required: [artifact] + additionalProperties: false + properties: + artifact: + type: string + description: Artifact type id; the contract for the final result. + pattern: type: object required: [chosen, rationale] diff --git a/.agents/skills/bpmn2agent-design/references/mapping-rubric.md b/.agents/skills/bpmn2agent-design/references/mapping-rubric.md index c2f4e5d..9d2f047 100644 --- a/.agents/skills/bpmn2agent-design/references/mapping-rubric.md +++ b/.agents/skills/bpmn2agent-design/references/mapping-rubric.md @@ -9,6 +9,7 @@ mapping plan. - [serviceTask → skill vs. agent-checklist item](#servicetask--skill-vs-agent-checklist-item) - [businessRuleTask / gateway condition → hook vs. script](#businessruletask--gateway-condition--hook-vs-script) - [callActivity / subProcess → reusable skill vs. sub-workflow](#callactivity--collapsed-subprocess--reusable-skill-vs-sub-workflow) +- [Data stores → context sources](#data-stores--context-sources) - [v1 supported / unsupported constructs](#v1-supported--unsupported-constructs) - [Legend: mapping view colours](#legend-mapping-view-colours) - [Worked mini example](#worked-mini-example) @@ -27,6 +28,10 @@ mapping plan. | Intermediate throw/catch event (link, none/signal used as a plain marker) | `kind: orchestrator`, same as a gateway | Timer/message intermediate events are **unsupported in v1** (see below). | | `callActivity` / collapsed `subProcess` | Reusable skill, or a sub-workflow — see decision below | A skill-backed one folds its inner flow nodes into the same skill. | | Data object / data object reference | Artifact contract (`artifacts.`, `kind: artifact-contract` on the producing element) | Path pattern + frontmatter fields, no generated file (see the schema's `artifact` definition). `producer` is one element id, or an array when the diagram has more than one real writer (`dataOutputAssociation`). | +| Data store reference, `Art: wissen` | `contextSources.`, `kind: context-source` | Loaded at generation time into `knowledge/.md` for each reading task, then the task skill's `references/`. No file of its own. | +| Data store reference, `Art: live` | `contextSources.`, `kind: context-source` | Read/written at run time: resolved tool lists (see below), a `## Kontextquellen` section in each reading task's skill, and for writes a PreToolUse `ask` hook. | +| Data store reference, `Art: gedächtnis` | `contextSources.`, `kind: context-source`, `memory` | A curated memory file plus a line-cap hook. Needs at least one writing `serviceTask` and one reader. | +| Process-wide `dataInput` / `dataOutput`, or a data object nobody produces / nobody reads | `workflowIO.input` / `.output`, `kind: workflow-input` / `workflow-output` on the element | Both also get an `artifacts.` contract. The input's required fields become the orchestrator's `argument-hint`; the output is the contract for the end result. | ### `serviceTask` → skill vs. agent-checklist item @@ -99,6 +104,46 @@ artifacts: `bpmn2agent-verify` and `render-mapping.mjs` handle exactly this representation; don't invent another (e.g. `not-generated` for every inner step, or a file per inner element). +## Data stores → context sources + +A `dataStoreReference` is one business data set (e.g. "Jira-Tickets Projekt LANE"), not a system. +Its documentation carries `Art:` and `Quelle:`; reading or writing comes only from the arrow +direction (store → task = read, task → store = write). A missing line or a combination not in the +matrix is a question for the business user, never a guess. + +| Art | Allowed `Quelle:` | Loaded | Becomes | +|---|---|---|---| +| `wissen` | `notebook:`, URL, `datei:`, `websearch` | at generation | `knowledge/.md` → skill `references/` | +| `wissen` | `mcp:` | at generation (snapshot), only if the server is connected | same | +| `live` | `mcp:`, `cli:` | at run time | tool allowlist + `## Kontextquellen` in the skill | +| `live` | `notebook:` | at run time, treated as `mcp:gemini-notebook-mcp` | same | +| `live` | URL | at run time | `WebFetch` | +| `live` | `datei:` | at run time | `Read` | +| `gedächtnis` | `datei:` (default `.claude/memory//.md`) | read at run start, written at the end | curated file + line-cap hook | + +Anything else (e.g. `live` + `websearch`, `gedächtnis` + `mcp:`) is invalid. + +### Live stores: tools and placement + +- **Resolve the tools.** For `mcp:`, fetch the server's tool list with ToolSearch (`mcp____`) + and sort by name: `get/list/search/read/fetch/view` read; `create/update/delete/add/post/edit/transition/push` + write. A server's `readOnlyHint` wins over the name. **Unclear counts as write.** `cli:` becomes + `Bash( :*)` patterns, same heuristic on the subcommands. The user confirms the list in + the mapping plan. Server not connected → `tools: unresolved` (verify warns, generate emits no tools, + never a wildcard). +- **Place them.** Where lanes are agents (`orchestrator-agent`), the needed read tools go into that + lane agent's `tools:`, least privilege per role. Otherwise they go into `.claude/settings.json` → + `permissions.allow` (union of all read tools) and the plan says openly "Lesezugriff nicht pro Rolle + getrennt". **If the roles need different privileges, that is a signal for `orchestrator-agent`** + (see `pattern-rubric.md`). + +### Writing into a live store + +A write needs a `userTask` before it on every path; verify errors otherwise. A phase that writes into +a live store is **never `workflow-script`**: that pattern has no human checkpoints. A PreToolUse hook +on the write tools (`permissionDecision: "ask"`) backs the `userTask` up. Writes to a `gedächtnis` +store need no approval. + ## v1 supported / unsupported constructs Supported: @@ -111,6 +156,7 @@ Supported: - `callActivity` - Multi-instance markers - Data objects / data object references +- Data store references (`Art: wissen | live | gedächtnis`) and process-wide data input/output - Start / end events - Error boundary events @@ -141,6 +187,7 @@ the kind or status name, so colour is never the only signal (exact values: the h | Teal | `orchestrator` | Gateways, loop back-edges, multi-instance markers — no file of its own. | | Amber | `human-checkpoint` | `userTask`/`manualTask`: a person decides here. | | Brown | `artifact-contract` | A data object with a path/frontmatter contract. | +| Turquoise | `context-source`, `workflow-input`, `workflow-output` | A data store (knowledge, live system, memory) or the process-wide input/output; no file of its own. A greener shade than the `orchestrator` teal, so the two stay apart; the annotation names the Art (exact values: `render-mapping.mjs`, set in generate). | | **Grey** | `not-generated` | Deliberately not generated; the element's `reason` is shown in its annotation and on click. Not an error. | | **Red** | `unresolved` | Unmapped or still an open question; blocks `bpmn2agent-verify`'s "no red in the map" check. | From 3e8a9a534ae749a6f52f77b6863eb7da79b2abce Mon Sep 17 00:00:00 2001 From: Benjamin Tenke Date: Sat, 3 Oct 2026 15:49:30 +0200 Subject: [PATCH 04/31] refactor(design): rename the store documentation line Quelle to Ort Task documentation already uses Quelle for provenance; a store's location is a different thing. Spec key quelle becomes ort. Co-Authored-By: Claude Sonnet 5.5 --- .agents/skills/bpmn-process-design/SKILL.md | 8 ++++---- .../assets/workflow-spec.schema.yaml | 16 ++++++++-------- .../references/mapping-rubric.md | 4 ++-- docs/plans/kontextquellen/plan.md | 14 +++++++------- docs/plans/kontextquellen/tasks.md | 16 ++++++++-------- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.agents/skills/bpmn-process-design/SKILL.md b/.agents/skills/bpmn-process-design/SKILL.md index 0e87488..ad246f0 100644 --- a/.agents/skills/bpmn-process-design/SKILL.md +++ b/.agents/skills/bpmn-process-design/SKILL.md @@ -77,12 +77,12 @@ model-only steps `⚠ unverified`. `Input: … Output: … Quelle: `. - A data store is a business data set named in business terms ("Jira-Tickets Projekt LANE"), not a system; several stores may share one source. Its documentation carries `Art: wissen | live | - gedächtnis` and `Quelle: notebook: | mcp: | cli: | | datei: | + gedächtnis` and `Ort: notebook: | mcp: | cli: | | datei: | websearch`. Notebooks picked in step 2 are candidates for `wissen` stores. - Valid pairs: `wissen` with `notebook:`, URL, `datei:`, `websearch`, or `mcp:` (a snapshot, only if the server is connected); `live` with `mcp:`, `cli:`, `notebook:`, URL or `datei:`; `gedächtnis` with `datei:` only (default `.claude/memory//.md`). Anything else: pick another - Art or Quelle. + Art or Ort. - Read or write follows only the arrow: store → task reads, task → store writes. No `Zugriff:` line. - A `userTask` precedes every write to a `live` store, on every path. - A `gedächtnis` store needs a `serviceTask` that writes it and a reader; writing needs no approval. @@ -94,12 +94,12 @@ model-only steps `⚠ unverified`. ## 5. Confirm the outline For each step ask: "What must this step know, and where does it live?" Every answer is a store -(Art, Quelle), a data object from an earlier step, or the process input; nothing means the step +(Art, Ort), a data object from an earlier step, or the process input; nothing means the step needs no context. Does it write anywhere? Then name the store and the `userTask` before it. Before drawing, show: lanes with what each becomes, then per phase the steps with type (AI / human / script / rule) and source, gateways with answers, loops with caps, data objects. Add -a store table (name, Art, Quelle, readers, writers) and the process input with its required fields +a store table (name, Art, Ort, readers, writers) and the process input with its required fields and the result the run delivers. Ask: draw as is / change what / ask the notebook more. Repeat until confirmed; never draw an unconfirmed design. diff --git a/.agents/skills/bpmn2agent-design/assets/workflow-spec.schema.yaml b/.agents/skills/bpmn2agent-design/assets/workflow-spec.schema.yaml index aa3c4d7..081dd64 100644 --- a/.agents/skills/bpmn2agent-design/assets/workflow-spec.schema.yaml +++ b/.agents/skills/bpmn2agent-design/assets/workflow-spec.schema.yaml @@ -329,7 +329,7 @@ definitions: contextSource: type: object - required: [name, bpmnElement, art, quelle] + required: [name, bpmnElement, art, ort] additionalProperties: false properties: name: @@ -343,9 +343,9 @@ definitions: description: > wissen = reference knowledge loaded at generation time into knowledge/.md; live = a system read (and maybe written) at run time through tools; gedaechtnis = a curated memory - file read at the start and written at the end of a run. Valid Art x Quelle combinations are + file read at the start and written at the end of a run. Valid Art x Ort combinations are in mapping-rubric.md. - quelle: + ort: type: object required: [type] additionalProperties: false @@ -356,7 +356,7 @@ definitions: type: string description: > notebook title, MCP server name, CLI command, URL or file path, as written after the - prefix of the diagram's "Quelle:" line. Omitted for websearch. + prefix of the diagram's "Ort:" line. Omitted for websearch. readers: type: array items: { type: string } @@ -392,7 +392,7 @@ definitions: type: string description: > Memory file relative to the run's cwd; default .claude/memory//.md, - overridden by the diagram's "Quelle: datei:". + overridden by the diagram's "Ort: datei:". maxLines: type: integer minimum: 1 @@ -403,7 +403,7 @@ definitions: properties: { art: { const: wissen } } then: properties: - quelle: + ort: properties: type: { enum: [notebook, mcp, url, datei, websearch] } tools: false @@ -412,7 +412,7 @@ definitions: properties: { art: { const: live } } then: properties: - quelle: + ort: properties: type: { enum: [notebook, mcp, cli, url, datei] } memory: false @@ -420,7 +420,7 @@ definitions: properties: { art: { const: gedaechtnis } } then: properties: - quelle: + ort: properties: type: { const: datei } tools: false diff --git a/.agents/skills/bpmn2agent-design/references/mapping-rubric.md b/.agents/skills/bpmn2agent-design/references/mapping-rubric.md index 9d2f047..63763b8 100644 --- a/.agents/skills/bpmn2agent-design/references/mapping-rubric.md +++ b/.agents/skills/bpmn2agent-design/references/mapping-rubric.md @@ -107,11 +107,11 @@ artifacts: ## Data stores → context sources A `dataStoreReference` is one business data set (e.g. "Jira-Tickets Projekt LANE"), not a system. -Its documentation carries `Art:` and `Quelle:`; reading or writing comes only from the arrow +Its documentation carries `Art:` and `Ort:`; reading or writing comes only from the arrow direction (store → task = read, task → store = write). A missing line or a combination not in the matrix is a question for the business user, never a guess. -| Art | Allowed `Quelle:` | Loaded | Becomes | +| Art | Allowed `Ort:` | Loaded | Becomes | |---|---|---|---| | `wissen` | `notebook:`, URL, `datei:`, `websearch` | at generation | `knowledge/.md` → skill `references/` | | `wissen` | `mcp:` | at generation (snapshot), only if the server is connected | same | diff --git a/docs/plans/kontextquellen/plan.md b/docs/plans/kontextquellen/plan.md index 1dfd2d2..51b926c 100644 --- a/docs/plans/kontextquellen/plan.md +++ b/docs/plans/kontextquellen/plan.md @@ -14,22 +14,22 @@ Pipeline (`inventory.mjs` überspringt es, die Mapping-Ansicht würde es rot fä ## Notation -Jede dauerhafte Quelle ist ein **Data Store** (Zylinder). Seine Dokumentation trägt zwei Zeilen: +Jede dauerhafte Quelle ist ein **Data Store** (Zylinder). Seine Dokumentation trägt zwei Zeilen (`Ort:` statt `Quelle:`, weil die Task-Dokumentation `Quelle:` schon für die Herkunft belegt): ``` Art: wissen | live | gedächtnis -Quelle: notebook: | mcp: | cli: | | datei: | websearch +Ort: notebook: | mcp: | cli: | | datei: | websearch ``` - **Lesen/Schreiben ergibt sich nur aus der Pfeilrichtung.** Store → Task heißt lesen, Task → Store heißt schreiben. Es gibt keine `Zugriff:`-Zeile. - **Ein Store ist ein fachlicher Datenbestand**, z. B. „Jira-Tickets Projekt LANE“, und kein - System. Mehrere Stores dürfen dieselbe `Quelle:` haben. + System. Mehrere Stores dürfen denselben `Ort:` haben. - **Fehlt eine Zeile, fragt analyze nach.** Unsinnige Kombinationen (Matrix unten) ebenfalls. -### Art × Quelle +### Art × Ort -| Art | erlaubte Quelle | geladen | wird zu | +| Art | erlaubter Ort | geladen | wird zu | |---|---|---|---| | `wissen` | `notebook:`, URL, `datei:`, `websearch` | bei der Generierung | `knowledge/.md` → Skill-`references/` | | `wissen` | `mcp:` | bei der Generierung (Snapshot), nur wenn der Server verbunden ist | wie oben | @@ -89,7 +89,7 @@ Quelle: notebook: | mcp: | cli: | | datei: | ### Gedächtnis - **Ablage:** `.claude/memory//.md` relativ zum cwd des Laufs, überschreibbar - mit `Quelle: datei:`. Das Gedächtnis liegt im Projekt der Nutzerin, nicht im Plugin. + mit `Ort: datei:`. Das Gedächtnis liegt im Projekt der Nutzerin, nicht im Plugin. - **Format:** ein kuratiertes Dokument mit festen Abschnitten (*Bewährt*, *Vermeiden*, *Offene Muster*) und höchstens 150 Zeilen. Der schreibende Task führt neue Erkenntnisse ein, statt sie anzuhängen. @@ -115,7 +115,7 @@ contextSources: name: Jira-Tickets Projekt LANE # Label wörtlich bpmnElement: DataStore_JiraTickets art: live # wissen | live | gedaechtnis - quelle: { type: mcp, ref: atlassian } # notebook|mcp|cli|url|datei|websearch + ort: { type: mcp, ref: atlassian } # notebook|mcp|cli|url|datei|websearch readers: [Task_TicketAnalysieren] writers: [Task_KommentarPosten] tools: # nur art: live; oder: unresolved diff --git a/docs/plans/kontextquellen/tasks.md b/docs/plans/kontextquellen/tasks.md index bc116f2..14e5feb 100644 --- a/docs/plans/kontextquellen/tasks.md +++ b/docs/plans/kontextquellen/tasks.md @@ -36,7 +36,7 @@ Aufgaben in derselben Welle sind unabhängig und können parallel laufen. - **Neue Element-Kinds:** `context-source`, `workflow-input`, `workflow-output`. - **Rubrik:** - Zeilen für Data Store je Art und für Prozess-I/O - - die Art×Quelle-Matrix + - die Art×Ort-Matrix - die Regel „Schreiben in Live-Store braucht `userTask`, nicht workflow-script“ - Platzierung der Tools (Agent-`tools:` vs. `permissions.allow`) - Farbe Türkis in der Farbtabelle @@ -57,7 +57,7 @@ Aufgaben in derselben Welle sind unabhängig und können parallel laufen. - `.agents/skills/bpmn2agent-verify/fixtures/context-flow-unguarded.bpmn` - **XML und DI:** - `dataStore` (Root) + `dataStoreReference` (sichtbar, 50×50), Dokumentation mit - `Art:`/`Quelle:` + `Art:`/`Ort:` - prozessweite `ioSpecification` mit `dataInput`/`dataOutput` + `inputSet`/`outputSet` - DI-Hinweis: Shapes für dataInput/dataOutput sind nötig, damit bpmn-js sie zeichnet; bpmnlint verlangt sie nicht @@ -81,7 +81,7 @@ Aufgaben in derselben Welle sind unabhängig und können parallel laufen. - Regeln: Store = fachlicher Datenbestand; Pfeilrichtung = lesen/schreiben; `userTask` vor Schreiben in Live-Stores; Gedächtnis braucht Schreiber und Leser - **Outline (§5):** pro Schritt die Frage „Was muss dieser Schritt wissen, und wo liegt es?“. - Die Bestätigungsübersicht zeigt Stores mit Art, Quelle, Lesern und Schreibern sowie die + Die Bestätigungsübersicht zeigt Stores mit Art, Ort, Lesern und Schreibern sowie die Prozess-Eingabe mit Pflichtfeldern. - **Abhängig von:** nur plan.md (läuft parallel zu T1/T2). - **Abnahme:** `npm run validate` grün. Der Text bleibt schlank (Skill-Authoring-Regeln). @@ -96,13 +96,13 @@ Aufgaben in derselben Welle sind unabhängig und können parallel laufen. - `.agents/skills/bpmn2agent-analyze/SKILL.md` - `.agents/skills/bpmn2agent-analyze/references/conventions.md` - **inventory.mjs:** - - `dataStoreReference` mit Name, Dokumentation (geparste `Art:`/`Quelle:`), Scope + - `dataStoreReference` mit Name, Dokumentation (geparste `Art:`/`Ort:`), Scope - Leser und Schreiber aus den Data Associations - prozessweite `ioSpecification` - Konventions-I/O: Data Object ohne Erzeuger, das gelesen wird, und Data Object ohne Leser - **SKILL.md:** - `contextSources` und `workflowIO` in den Spec-Entwurf schreiben - - per `AskUserQuestion` nachfragen bei: fehlendem `Art:`/`Quelle:`, ungültiger Kombination, + - per `AskUserQuestion` nachfragen bei: fehlendem `Art:`/`Ort:`, ungültiger Kombination, Gedächtnis ohne Schreiber oder Leser - Stores in den ID-Diff bei geänderten Diagrammen aufnehmen - **Abnahme:** @@ -119,7 +119,7 @@ Aufgaben in derselben Welle sind unabhängig und können parallel laufen. - `.agents/skills/bpmn2agent-knowledge/SKILL.md` - `.agents/skills/bpmn2agent-knowledge/references/notebook-extraction.md` - **Inhalt:** - - Wissens-Stores ersetzen §2 „welches Notebook für welche Lane“. Die Quelle wird je nach + - Wissens-Stores ersetzen §2 „welches Notebook für welche Lane“. Der Ort wird je nach Typ aufgelöst (`notebook:` über notebook_list per Titel, URL per WebFetch, `datei:` als lokales Doc, `websearch`, `mcp:` als Snapshot nur bei verbundenem Server). - Pro lesendem Task `knowledge/.md`, ein Abschnitt pro Store. @@ -144,7 +144,7 @@ Aufgaben in derselben Welle sind unabhängig und können parallel laufen. - nicht verbunden → `unresolved` - **Platzierung:** Agent-`tools:` bei orchestrator-agent, sonst `permissions.allow`. - **Musterwahl:** Eine Phase mit Schreiben in einen Live-Store wird nicht workflow-script. -- **Mapping-Plan:** listet je Store Art, Quelle, Leser/Schreiber und die Tool-Aufteilung zur +- **Mapping-Plan:** listet je Store Art, Ort, Leser/Schreiber und die Tool-Aufteilung zur Bestätigung, inkl. „Lesezugriff nicht pro Rolle getrennt“, wo zutreffend. - **Abnahme:** Die Spec der Fixture hat vollständige `contextSources.*.tools` (oder `unresolved`) und `elements.*` für alle Stores. @@ -205,7 +205,7 @@ Aufgaben in derselben Welle sind unabhängig und können parallel laufen. - `README.md` - `.agents/skills/agentic-workflow-kb/references/process-to-agents.md` - `.agents/skills/agentic-workflow-kb/references/multi-agent-handoffs.md` -- **ARCHITECTURE.md:** Abschnitt Kontextquellen (Notation, Art×Quelle, Weg durch die Stufen). +- **ARCHITECTURE.md:** Abschnitt Kontextquellen (Notation, Art×Ort, Weg durch die Stufen). - **README.md:** Kurzbeschreibung + Beispiel aus der Fixture. - **Agent-Definitionen:** `agentic-workflow-architect` und `agentic-artifact-reviewer` prüfen Stores mit: ungeschütztes Schreiben, zu breite Tool-Listen, Gedächtnis ohne Cap. From b9f45f32e9a32912fc61dac61b9ef66f3cf234a6 Mon Sep 17 00:00:00 2001 From: Benjamin Tenke Date: Sat, 3 Oct 2026 15:51:23 +0200 Subject: [PATCH 05/31] feat(bpmn-authoring): support data stores and process io; add context-flow fixtures Co-Authored-By: Claude Sonnet 5.5 --- .../bpmn-authoring/references/layout.md | 10 + .../bpmn-authoring/references/xml-and-di.md | 79 ++++- .../fixtures/context-flow-unguarded.bpmn | 243 ++++++++++++++ .../fixtures/context-flow.bpmn | 305 ++++++++++++++++++ 4 files changed, 636 insertions(+), 1 deletion(-) create mode 100644 .agents/skills/bpmn2agent-verify/fixtures/context-flow-unguarded.bpmn create mode 100644 .agents/skills/bpmn2agent-verify/fixtures/context-flow.bpmn diff --git a/.agents/skills/bpmn-authoring/references/layout.md b/.agents/skills/bpmn-authoring/references/layout.md index ca1d987..b0cdf7c 100644 --- a/.agents/skills/bpmn-authoring/references/layout.md +++ b/.agents/skills/bpmn-authoring/references/layout.md @@ -16,6 +16,16 @@ Sizes and why: `xml-and-di.md`, "Standard sizes". - **Data objects**: `y=170`, height 50, centred above the task that outputs them; labels above them. Input associations from an earlier data object route via a waypoint at `y=195` before dropping into the consuming task's top edge. +- **Data stores** (`dataStoreReference`, 50×50): below the task row, inside the lane of their first + reader, ~60px under the task bottom, label beside or below the store. Read arrows run straight up + into the task's bottom edge. A store that is also written later gets its write arrow routed in a + channel below the stores (own `y` per store, ~25px apart) so no two arrows cross; with lanes, put + the lane that the happy path leaves and re-enters above the other, so the vertical hops do not + cross those channels. Several stores under one task sit side by side. +- **Process input/output** (`dataInput`/`dataOutput`, 36×50): the input left of the start event, the + output right of the end event, both in the data-object band above the task row (`y=170`, or the + lane's top band). Route the input's association along `y≈195` into the first consuming task's top + edge; route the output's association over the tasks between its producer and the end. - **Groups (phase bands)**: `y=40`, `height=500`, from just left of the phase's first task to just right of its last, ~30–40px padding; label bounds inside the top of the band. - New elements extend this row; never start a second main row. diff --git a/.agents/skills/bpmn-authoring/references/xml-and-di.md b/.agents/skills/bpmn-authoring/references/xml-and-di.md index 09c3073..07afb42 100644 --- a/.agents/skills/bpmn-authoring/references/xml-and-di.md +++ b/.agents/skills/bpmn-authoring/references/xml-and-di.md @@ -2,6 +2,7 @@ - [Document skeleton](#document-skeleton) - [Element catalogue](#element-catalogue) +- [Data stores and process input/output](#data-stores-and-process-inputoutput) - [Sub-processes and drill-down](#sub-processes-and-drill-down) - [Lanes (`laneSet`)](#lanes-laneset) - [Diagram Interchange (DI)](#diagram-interchange-di) @@ -29,7 +30,7 @@ Note: the spec *version* is 2.0.2 but XML namespaces still carry the 2.0 date (`20100524`); XSDs live under `20100501/`. There is no separate 2.0.2 namespace. -**Element order inside `process`**: `laneSet` → flow elements (events, tasks, gateways, sequence +**Element order inside `process`**: `ioSpecification` (if any) → `laneSet` → flow elements (events, tasks, gateways, sequence flows, data objects/associations) → artifacts (group, textAnnotation, association) last. xmllint enforces this via the XSD's element sequence. @@ -52,6 +53,7 @@ enforces this via the XSD's element sequence. `dataObjectRef` pointing at the `dataObject`). `dataInputAssociation`/`dataOutputAssociation` connect a reference to a task; an input association needs a `property` on the task as its `targetRef` (``). +- **Data stores & process input/output**: see "Data stores and process input/output" below. - **Text annotations & associations**: `textAnnotation` + plain `association` (not sequence flow) to the annotated element. - **Groups / category / categoryValue**: `category` + nested `categoryValue` at `definitions` level; @@ -59,6 +61,79 @@ enforces this via the XSD's element sequence. - **Pools/message flows**: not used here. **Lanes**: see "Lanes (`laneSet`)" below; whether to use them is decided in `modelling-rules.md`. +## Data stores and process input/output + +Context sources (where a step reads or writes data that outlives the run) are data stores; what +goes into and out of the whole process is its `ioSpecification`. Both feed the bpmn2agent pipeline. + +**Data store**: a root element plus a visible reference, like `dataObject`/`dataObjectReference`. +`dataStore` sits directly under `definitions` (before the `process`); `dataStoreReference` sits in +the process among the flow elements, 50×50, with the name = the business data set (e.g. +"Jira-Tickets Projekt LANE", not "Jira"). Its `` carries exactly two lines: + +``` +Art: wissen | live | gedächtnis +Ort: notebook: | mcp: | cli: | | datei: | websearch +``` + +Task documentation uses `Quelle:` for provenance, so the store location is `Ort:`. There is no +access line: the arrow direction alone says read or write. + +```xml + + + ... + + Flow_1 + Flow_2 + + + StoreRef_Jira + Property_Analysieren_1 + + + + ... + + StoreRef_Jira + + + + Art: live +Ort: mcp:atlassian + + +``` + +One `property` per input association (as with data objects). Stores are not flow nodes: no lane +`flowNodeRef`, no sequence flow. Several stores may share one `Ort:`. A `wissen` store is only read; a +`gedächtnis` store needs a writing `serviceTask` and a reader; every write into a `live` store needs a +`userTask` on each path before it (`bpmn2agent-verify` reports a violation). + +**Process input/output**: a real, process-wide `ioSpecification` as the *first* child of `process` +(before `laneSet`). The XSD requires at least one `inputSet` and one `outputSet`; an `outputSet` +without refs is valid. + +```xml + + + + + DataInput_TicketId + DataOutput_Bericht + + ... + +``` + +A task consumes a `dataInput` through a `dataInputAssociation` whose `sourceRef` is the `dataInput` id +(plus a `property` target, as above); a `dataOutput` is fed by a `dataOutputAssociation` whose +`targetRef` is the `dataOutput` id. bpmn.io's palette has no entry for these, so they exist only +through XML. bpmn-js draws them as 36×50 data-object shapes (input arrow icon) **only if a +`BPMNShape` with `bpmnElement` = the `dataInput`/`dataOutput` id exists**; bpmnlint does not require +that shape, so a missing one is silent: add it. The pipeline also accepts a convention instead: a +data object nobody produces that a task reads (input), or one nobody reads (output). + ## Sub-processes and drill-down | Element | Meaning | @@ -168,6 +243,8 @@ Without DI, bpmn-js can't render the model, and bpmnlint's `no-bpmndi` fires for - Shape attributes: `isMarkerVisible="true"` on **exclusive gateways** (draws the "X"; otherwise renders as an empty diamond); `isHorizontal="true"` on pools/lanes; `isExpanded="true|false"` on sub-processes. +- **Data stores, `dataInput`, `dataOutput`**: a `BPMNShape` each (store 50×50, data input/output + 36×50), with the name as external label; the associations get edges as below. - **Data associations**: an edge whose `bpmnElement` is the `dataInputAssociation`/ `dataOutputAssociation` ID, waypoints from producer to data object (output) or data object to consumer (input). diff --git a/.agents/skills/bpmn2agent-verify/fixtures/context-flow-unguarded.bpmn b/.agents/skills/bpmn2agent-verify/fixtures/context-flow-unguarded.bpmn new file mode 100644 index 0000000..4e5d444 --- /dev/null +++ b/.agents/skills/bpmn2agent-verify/fixtures/context-flow-unguarded.bpmn @@ -0,0 +1,243 @@ + + + + + + + + + + DataInput_TicketId + + + + + + Start_TicketEingegangen + Task_TicketAnalysieren + Task_AntwortEntwerfen + Task_KommentarPosten + Task_LernnotizFortschreiben + End_Beantwortet + + + + Flow_1 + + + Input: Ticket-ID, Ticket aus Jira, Lernnotizen. Output: Analyse (Problem, Dringlichkeit). Quelle: ⚠ unverified + Flow_1 + Flow_2 + + + + + DataInput_TicketId + Property_Analysieren_1 + + + StoreRef_Jira + Property_Analysieren_2 + + + StoreRef_Lernnotizen + Property_Analysieren_3 + + + DataRef_Analyse + + + + + + Input: Analyse, Support-Handbuch. Output: Antwortentwurf. Quelle: ⚠ unverified + Flow_2 + Flow_3 + + + + DataRef_Analyse + Property_Entwerfen_1 + + + StoreRef_Handbuch + Property_Entwerfen_2 + + + + Input: freigegebener Antwortentwurf. Output: Antwortprotokoll. Quelle: ⚠ unverified + Flow_3 + Flow_5 + + StoreRef_Jira + + + DataRef_Protokoll + + + + + + Input: Ticket, Antwort. Output: aktualisierte Lernnotizen. Quelle: ⚠ unverified + Flow_5 + Flow_6 + + StoreRef_Lernnotizen + + + + Flow_6 + + + Art: wissen +Ort: notebook:Support-Handbuch + + + Art: live +Ort: mcp:atlassian + + + Art: gedächtnis +Ort: datei:.claude/memory/context-flow/lernnotizen-support.md + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.agents/skills/bpmn2agent-verify/fixtures/context-flow.bpmn b/.agents/skills/bpmn2agent-verify/fixtures/context-flow.bpmn new file mode 100644 index 0000000..b10952f --- /dev/null +++ b/.agents/skills/bpmn2agent-verify/fixtures/context-flow.bpmn @@ -0,0 +1,305 @@ + + + + + + + + + + DataInput_TicketId + + + + + + Task_AntwortFreigeben + Gw_Freigegeben + End_Verworfen + + + Start_TicketEingegangen + Task_TicketAnalysieren + Task_AntwortEntwerfen + Task_KommentarPosten + Task_LernnotizFortschreiben + End_Beantwortet + + + + Flow_1 + + + Input: Ticket-ID, Ticket aus Jira, Lernnotizen. Output: Analyse (Problem, Dringlichkeit). Quelle: ⚠ unverified + Flow_1 + Flow_2 + + + + + DataInput_TicketId + Property_Analysieren_1 + + + StoreRef_Jira + Property_Analysieren_2 + + + StoreRef_Lernnotizen + Property_Analysieren_3 + + + DataRef_Analyse + + + + + + Input: Analyse, Support-Handbuch. Output: Antwortentwurf. Quelle: ⚠ unverified + Flow_2 + Flow_3 + + + + DataRef_Analyse + Property_Entwerfen_1 + + + StoreRef_Handbuch + Property_Entwerfen_2 + + + + Input: Antwortentwurf. Output: Freigabeentscheidung. Quelle: ⚠ unverified + Flow_3 + Flow_4 + + + Flow_4 + Flow_Ja + Flow_Nein + + + Input: freigegebener Antwortentwurf. Output: Antwortprotokoll. Quelle: ⚠ unverified + Flow_Ja + Flow_5 + + StoreRef_Jira + + + DataRef_Protokoll + + + + + + Input: Ticket, Antwort. Output: aktualisierte Lernnotizen. Quelle: ⚠ unverified + Flow_5 + Flow_6 + + StoreRef_Lernnotizen + + + + Flow_6 + + + Flow_Nein + + + Art: wissen +Ort: notebook:Support-Handbuch + + + Art: live +Ort: mcp:atlassian + + + Art: gedächtnis +Ort: datei:.claude/memory/context-flow/lernnotizen-support.md + + + + + + + Ja + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From bce54dc329bd93cbbb46f7f8e7b6c92b893d757f Mon Sep 17 00:00:00 2001 From: Benjamin Tenke Date: Sat, 3 Oct 2026 15:55:28 +0200 Subject: [PATCH 06/31] feat(analyze): inventory data stores and process io into contextSources Co-Authored-By: Claude Sonnet 5.5 --- .agents/skills/bpmn2agent-analyze/SKILL.md | 45 ++++- .../references/conventions.md | 51 ++++++ .../bpmn2agent-analyze/scripts/inventory.mjs | 154 +++++++++++++++++- 3 files changed, 240 insertions(+), 10 deletions(-) diff --git a/.agents/skills/bpmn2agent-analyze/SKILL.md b/.agents/skills/bpmn2agent-analyze/SKILL.md index 2dde090..6dfb31a 100644 --- a/.agents/skills/bpmn2agent-analyze/SKILL.md +++ b/.agents/skills/bpmn2agent-analyze/SKILL.md @@ -1,6 +1,6 @@ --- name: bpmn2agent-analyze -description: Reads a hand-drawn .bpmn, validates and inventories it, flags constructs the pipeline can't generate yet (pools/message flows, timer/message events, event sub-processes, compensation), asks the business user about gaps only, and writes the draft generated//workflow-spec.yaml. On a changed .bpmn it diffs by element id and asks only about what changed. Never edits the .bpmn. Use when a diagram is new or changed, before bpmn2agent-knowledge. +description: Reads a hand-drawn .bpmn, validates and inventories it, flags constructs the pipeline can't generate yet (pools/message flows, timer/message events, event sub-processes, compensation), asks the business user about gaps only (incl. data stores and process input/output), and writes the draft generated//workflow-spec.yaml. On a changed .bpmn it diffs by element id and asks only about what changed. Never edits the .bpmn. Use when a diagram is new or changed, before bpmn2agent-knowledge. bpmn: file: docs/planning/bpmn-to-agentic-workflow.bpmn elements: @@ -50,8 +50,10 @@ node ${CLAUDE_SKILL_DIR}/scripts/inventory.mjs \ ``` Prints JSON: scopes with pattern-rubric signals, lanes, flow nodes, sequence flows, data objects and -associations, annotations, `meta.sha256` and `findings[]`. Save it to a scratch file; later steps -reuse it. How to read role hints, task types and annotations: `references/conventions.md`. What each +associations, `dataStores[]` (parsed `Art:`/`Ort:`, readers, writers), `processIO` (workflow input and +output), annotations, `meta.sha256` and `findings[]`. Save it to a scratch file; later steps +reuse it. How to read role hints, task types, annotations, data stores and process input/output: +`references/conventions.md`. What each `unresolved` finding means and which rewrite to suggest: `references/unsupported.md`. ## 4. Flag unsupported elements @@ -83,8 +85,23 @@ Ask only about these gaps, never about generation decisions and never about an e as a note (rename to a typed task in `bpmn-authoring`). Don't write a `kind`. - **Unclear multi-instance collection**: `multiInstance.collectionHint` is `null` or came only from an annotation/name pattern. Ask what the collection is (e.g. "one per epic"). +- **`store-missing-art-ort` finding**: the store has no readable `Art:` or `Ort:` line. Ask for the + missing value as concrete options (the three Arts; the Orts that fit the Art, see the matrix in + `references/conventions.md`), recommending the one the store's name and readers suggest. +- **`store-invalid-art-ort` finding**: offer the two repairs, a valid Ort for that Art or a different Art + for that Ort (e.g. `gedächtnis` + `mcp:` becomes `live` + `mcp:` or `gedächtnis` + `datei:`), with a + recommendation. +- **`memory-store-incomplete` finding**: a `gedächtnis` store needs a writing `serviceTask` and a reader. + Ask which task should write or read it (options: the tasks in the diagram), or whether the store is + really `wissen`/`live`. +- **`store-without-associations` finding**: ask which task reads or writes it, or whether to drop it. +- **Several `processIO.inputs[]` or `outputs[]`**: ask which one is the workflow's real input/result + (`workflowIO` holds one each); the others stay plain artifacts. - **Every unresolved finding from step 4.** +A store gap is answered in the spec only: record `art`/`ort` as the user confirmed and tell them to fix +the `Art:`/`Ort:` lines in the `.bpmn` (in `bpmn-authoring`) so the diagram and spec stay in sync. + ## 6. Write the spec draft Write (or merge, step 7) `generated//workflow-spec.yaml`: @@ -104,6 +121,19 @@ Write (or merge, step 7) `generated//workflow-spec.yaml`: `pathPattern` defaults to `generated//artifacts//{id}.md`. `producer`/`consumers` from associations; `producer` is an array when more than one element has a real `dataOutputAssociation` into it (both are producers, not consumers). +- **`contextSources`**: one per `dataStores[]` entry, as the schema defines it. Id = kebab-case of the + store name; `name` verbatim; `bpmnElement` = the reference id; `art` and `ort` (`{type, ref}`) as parsed + or as confirmed in step 5; `readers`/`writers` from the inventory (the store's arrows alone decide + read vs. write). Leave `tools` and `memory` unset (design resolves them). Each store also gets + `elements.` (`bpmnType: dataStoreReference`, `label` verbatim, `kind: context-source` as a + proposal). +- **`workflowIO`**: from `processIO`. `input.artifact`/`output.artifact` = the artifact id of the chosen + entry. A real `dataInput`/`dataOutput` gets its own `artifacts.` (kebab-case of its name; `producer` + unset for an input, `consumers`/`producer` from `readers`/`writers`) and `elements.` (`bpmnType: + dataInput|dataOutput`, `kind: workflow-input|workflow-output`). A convention entry is an ordinary data + object artifact; its `elements.` gets `kind: workflow-input|workflow-output` instead of + `artifact-contract`. For a real input, `input.required` = its name as a camelCase field (`Ticket-ID` + becomes `ticketId`); for a convention input leave it unset. Omit `workflowIO` when `processIO` is empty. - **`pattern`**, **`knowledge`**: leave unset (design and knowledge own them). - **`openQuestions`**: one per gap from steps 4–5 the user deferred, keys `elementId`, `question`, `answer`. Record the user's answer when given; `answer: null` when deferred. @@ -124,13 +154,14 @@ If the spec already exists: 1. Compare its `meta.sourceBpmn.sha256` with the inventory's `meta.sha256`. Equal: tell the user nothing changed and stop (or confirm they meant to re-run). -2. Otherwise diff by element id across `flowNodes`/`dataObjects`/`lanes` vs. the spec's - `elements`/`artifacts`/`roles`, comparing `bpmnType`, `label`, `lane`, `documentation`, - `multiInstance`, `eventDefinitions`. Classify each id as new, changed, removed or unchanged. +2. Otherwise diff by element id across `flowNodes`/`dataObjects`/`dataStores`/`processIO`/`lanes` vs. the + spec's `elements`/`artifacts`/`contextSources`/`workflowIO`/`roles`, comparing `bpmnType`, `label`, `lane`, `documentation`, + `multiInstance`, `eventDefinitions`; for a store also `art`, `ort`, `readers`, `writers`. Classify each id as new, changed, removed or unchanged. 3. Interview (step 5) only new and changed elements with a gap. Never touch an unchanged element's `kind`/`reason`/`generatedPaths` or other later-stage decisions. 4. Removed elements: flag them to the user; don't delete without confirmation, especially roles or - artifacts still referenced (`elements.*.lane`, `artifacts.*.producer`/`consumers`). + artifacts or stores still referenced (`elements.*.lane`, `artifacts.*.producer`/`consumers`, + `workflowIO`). 5. Update `meta.sourceBpmn.sha256` and `meta.updated`; merge into the existing file instead of rewriting it, so untouched sections stay byte-identical. diff --git a/.agents/skills/bpmn2agent-analyze/references/conventions.md b/.agents/skills/bpmn2agent-analyze/references/conventions.md index f5b8d53..17eb79f 100644 --- a/.agents/skills/bpmn2agent-analyze/references/conventions.md +++ b/.agents/skills/bpmn2agent-analyze/references/conventions.md @@ -52,9 +52,60 @@ formal `loopCardinality`/`loopDataInputRef` → name pattern ("per X": `je`/`pro `for each`) → associated annotation text. Treat an annotation-derived hint as unconfirmed: ask for the actual collection instead of writing the annotation text into `collection.ref`. +## Data stores = context sources + +Every durable source is a `bpmn:DataStoreReference` (cylinder, name = the business data set, e.g. +"Jira-Tickets Projekt LANE", not the system). The visible reference carries the documentation; the root +`bpmn:DataStore` is unnamed, so `inventory.mjs` reads `Art:`/`Ort:` from the reference. Two lines: + +``` +Art: wissen | live | gedächtnis +Ort: notebook: | mcp: | cli: | | datei: | websearch +``` + +`Art` is normalised for the spec (`gedächtnis` becomes `gedaechtnis`); `Ort` becomes `{type, ref}` +(`ref` omitted for `websearch`; a URL keeps the whole URL as `ref`). Task documentation uses `Quelle:` +for provenance, which is why the store location is `Ort:`. Several stores may share one `Ort:`. + +**Arrow direction is the only access rule**: store → task (`dataInputAssociation`) = read, task → store +(`dataOutputAssociation`) = write; there is no access line. An association on a `subProcess` counts for +the sub-process element. Stores are not flow nodes: no lane, no sequence flow. + +### Art × Ort + +| Art | Valid Ort type | +|---|---| +| `wissen` | `notebook`, URL, `datei`, `websearch`, `mcp` | +| `live` | `mcp`, `cli`, `notebook`, URL, `datei` | +| `gedaechtnis` | `datei` | + +Anything else is a `store-invalid-art-ort` finding (e.g. `live` + `websearch`, `wissen` + `cli`, +`gedächtnis` + `mcp`). Further store findings, all `warning`: `store-missing-art-ort` (a line is missing or +unparseable, details in `dataStores[].problems`), `memory-store-incomplete` (a `gedaechtnis` store needs a +writing `serviceTask` and a reader), `store-without-associations`. They are questions for the user; the +inventory never repairs a store. Whether a write into a `live` store has a `userTask` in front of it is +checked by `bpmn2agent-verify`, not here. + +## Process input and output + +`inventory.mjs` reports the workflow's input and output in `processIO.inputs[]`/`outputs[]`, each entry +tagged `source: ioSpecification | convention`. Only the top-level workflow process counts, not +sub-processes and not a process some `callActivity` calls. + +1. **Real**: a process-wide `bpmn:ioSpecification` (first child of the `process`) with `dataInput` / + `dataOutput`. Readers/writers come from the data associations whose `sourceRef` (input) or `targetRef` + (output) is that element. bpmn.io has no palette entry for these, so they only exist through XML. +2. **Convention**: an input is a data object reference that no activity produces and some activity reads; + an output is one that is produced and nobody reads. It only applies when the process draws at least one + data-object read; a diagram with output associations only has no "nobody reads" signal and yields none. + +A diagram may mix both. When several entries qualify, the user picks the real input/result in the +interview; `workflowIO` holds one of each. + ## Left to `bpmn2agent-design` - skill vs. agent-checklist item per `serviceTask` (mapping rubric); - the orchestration pattern — `inventory.mjs` only computes the pattern-rubric signals; +- tool lists and placement for `live` stores, the memory path/cap for `gedaechtnis` stores; - deterministic vs. judgement gateways — `evaluateGateway()` is a heuristic feeding `judgementBranchCount`; design confirms borderline cases. diff --git a/.agents/skills/bpmn2agent-analyze/scripts/inventory.mjs b/.agents/skills/bpmn2agent-analyze/scripts/inventory.mjs index de29a8e..2c28486 100644 --- a/.agents/skills/bpmn2agent-analyze/scripts/inventory.mjs +++ b/.agents/skills/bpmn2agent-analyze/scripts/inventory.mjs @@ -4,9 +4,12 @@ // Parses with bpmn-moddle and prints a JSON inventory to stdout: every // process/subProcess scope, every lane, every flow node (with lane/scope/documentation/ // incoming/outgoing/multi-instance/boundary-events/eventDefinitions), every sequence flow, -// every data object/reference + data association, every text annotation + its associated -// element, computed pattern-rubric signals (per scope and aggregated), and a `findings` -// array of things bpmn2agent-analyze's SKILL.md should ask the business user about. +// every data object/reference + data association, every data store reference (`dataStores[]`: +// parsed Art:/Ort: documentation, readers/writers from the arrow direction), the process-wide +// input/output (`processIO`: real ioSpecification plus the data-object convention), every text +// annotation + its associated element, computed pattern-rubric signals (per scope and +// aggregated), and a `findings` array of things bpmn2agent-analyze's SKILL.md should ask the +// business user about. // // bpmn-moddle is resolved via createRequire against /package.json, same reasoning // as bpmn-authoring/scripts/check-moddle.mjs: Node's ESM resolver won't find a package @@ -93,11 +96,42 @@ function extractCollectionHint(el, textAnnotationsByAssociatedId) { return null; } +// --- data stores: `Art:` / `Ort:` lines in the store reference's --- +// Art x Ort matrix, same as references/conventions.md and mapping-rubric.md. +const ART_ORT_MATRIX = { + wissen: new Set(['notebook', 'url', 'datei', 'websearch', 'mcp']), + live: new Set(['mcp', 'cli', 'notebook', 'url', 'datei']), + gedaechtnis: new Set(['datei']), +}; +const normaliseArt = (raw) => + raw.trim().toLowerCase().replace(/ä/g, 'ae').replace(/ö/g, 'oe').replace(/ü/g, 'ue').replace(/ß/g, 'ss'); +function parseOrt(raw) { + const v = raw.trim(); + if (/^https?:\/\/\S+$/i.test(v)) return { type: 'url', ref: v }; + if (/^websearch$/i.test(v)) return { type: 'websearch' }; + const m = /^(notebook|mcp|cli|datei):\s*(\S.*)$/i.exec(v); + return m ? { type: m[1].toLowerCase(), ref: m[2].trim() } : null; +} +function parseStoreDoc(doc) { + const artRaw = /^\s*Art:[ \t]*(.*?)\s*$/im.exec(doc || '')?.[1] ?? null; + const ortRaw = /^\s*Ort:[ \t]*(.*?)\s*$/im.exec(doc || '')?.[1] ?? null; + const art = artRaw ? (normaliseArt(artRaw) in ART_ORT_MATRIX ? normaliseArt(artRaw) : null) : null; + const ort = ortRaw ? parseOrt(ortRaw) : null; + const problems = []; + if (!artRaw) problems.push('missing-art'); + else if (!art) problems.push('unparseable-art'); + if (!ortRaw) problems.push('missing-ort'); + else if (!ort) problems.push('unparseable-ort'); + if (art && ort && !ART_ORT_MATRIX[art].has(ort.type)) problems.push('invalid-combination'); + return { artRaw, ortRaw, art, ort, problems }; +} + const scopes = []; const lanes = []; const flowNodes = []; const sequenceFlows = []; const dataObjects = []; +const dataStores = []; const textAnnotations = []; const associationsRaw = []; // bpmn:Association elements, resolved into textAnnotations after the walk const findings = []; @@ -210,6 +244,21 @@ function walkScope(scopeEl, scopeId, parentScopeId, scopeType) { }); continue; } + if (el.$type === 'bpmn:DataStoreReference') { + // The visible node carries the documentation; the root bpmn:DataStore is unnamed (like + // DataObject vs. DataObjectReference), so Art:/Ort: are read from the reference. + dataStores.push({ + id: el.id, + name: el.name || null, + scopeId, + dataStoreRef: el.dataStoreRef?.id || null, + documentation: docText(el), + ...parseStoreDoc(docText(el)), + readers: [], + writers: [], + }); + continue; + } // bpmn:TextAnnotation / bpmn:Association already handled above; bpmn:Group, // bpmn:Category etc. are purely visual and out of scope for the inventory. } @@ -363,6 +412,103 @@ function collectDataAssociations(scopeEl) { } for (const proc of rootProcesses) collectDataAssociations(proc); +// --- data stores: readers/writers from the arrow direction (store -> task = read, task -> +// store = write; no access line), then validity findings. Associations hanging on a subProcess +// element count like those on a task. --- +const flowNodeById = new Map(flowNodes.map((n) => [n.id, n])); +const dataStoreById = new Map(dataStores.map((d) => [d.id, d])); +const addUnique = (arr, id) => { if (!arr.includes(id)) arr.push(id); }; +for (const a of dataObjects) { + if (a.kind === 'dataInputAssociation') { + for (const ref of a.dataRefIds) if (dataStoreById.has(ref)) addUnique(dataStoreById.get(ref).readers, a.activityId); + } else if (a.kind === 'dataOutputAssociation') { + for (const ref of a.dataRefIds) if (dataStoreById.has(ref)) addUnique(dataStoreById.get(ref).writers, a.activityId); + } +} +const storeLabel = (d) => `${d.id}${d.name ? ` ("${d.name}")` : ''}`; +for (const d of dataStores) { + const doc = d.problems.filter((p) => p !== 'invalid-combination'); + if (doc.length) { + pushFinding( + 'store-missing-art-ort', 'warning', + `Data store ${storeLabel(d)}: ${doc.map((p) => `${p.startsWith('missing') ? 'missing' : 'unreadable'} ${p.endsWith('art') ? 'Art:' : 'Ort:'} line`).join(', ')} in its documentation.`, + { elementId: d.id, problems: doc, artRaw: d.artRaw, ortRaw: d.ortRaw } + ); + } + if (d.problems.includes('invalid-combination')) { + pushFinding( + 'store-invalid-art-ort', 'warning', + `Data store ${storeLabel(d)}: Art "${d.art}" does not work with Ort type "${d.ort.type}" (allowed Ort for ${d.art}: ${[...ART_ORT_MATRIX[d.art]].join(', ')}).`, + { elementId: d.id, art: d.art, ort: d.ort, allowedOrt: [...ART_ORT_MATRIX[d.art]] } + ); + } + if (!d.readers.length && !d.writers.length) { + pushFinding( + 'store-without-associations', 'warning', + `Data store ${storeLabel(d)} has no data association at all: no task reads from or writes to it.`, + { elementId: d.id } + ); + } else if (d.art === 'gedaechtnis') { + const serviceWriters = d.writers.filter((id) => flowNodeById.get(id)?.bpmnType === 'bpmn:ServiceTask'); + const missing = []; + if (!serviceWriters.length) missing.push('writer'); + if (!d.readers.length) missing.push('reader'); + if (missing.length) { + pushFinding( + 'memory-store-incomplete', 'warning', + `Memory store ${storeLabel(d)} (Art: gedächtnis) has no ${missing.join(' and no ')}: it needs at least one writing serviceTask and one reader.${missing.includes('writer') && d.writers.length ? ` Its current writer(s) ${d.writers.join(', ')} are not serviceTasks.` : ''}`, + { elementId: d.id, missing, readers: d.readers, writers: d.writers } + ); + } + } +} + +// --- process-wide input/output: a real ioSpecification dataInput/dataOutput on the workflow's +// process, or the data-object convention (input = reference nobody produces that some activity +// reads; output = reference that is produced but nobody reads; both only when the process draws +// at least one data-object read). Only top-level workflow processes count (not sub-processes, +// not processes some callActivity calls). --- +const calledProcessIds = new Set(flowNodes.map((n) => n.calledElement).filter(Boolean)); +const ioScopes = rootProcesses.filter((p) => !calledProcessIds.has(p.id)); +const processIO = { inputs: [], outputs: [] }; +for (const proc of ioScopes) { + const io = proc.ioSpecification; + for (const di of io?.dataInputs || []) { + const readers = []; + for (const a of dataObjects) { + if (a.kind === 'dataInputAssociation' && a.dataRefIds.includes(di.id)) addUnique(readers, a.activityId); + } + processIO.inputs.push({ id: di.id, name: di.name || null, source: 'ioSpecification', scopeId: proc.id, readers }); + } + for (const dout of io?.dataOutputs || []) { + const writers = []; + for (const a of dataObjects) { + if (a.kind === 'dataOutputAssociation' && a.dataRefIds.includes(dout.id)) addUnique(writers, a.activityId); + } + processIO.outputs.push({ id: dout.id, name: dout.name || null, source: 'ioSpecification', scopeId: proc.id, writers }); + } + // "Nobody reads / nobody produces" only says something when the diagram models reads at all; + // a diagram that draws only output associations (reads sit in the task text) has no signal. + const objectRefs = dataObjects.filter((d) => d.kind === 'dataObjectReference' && d.scopeId === proc.id); + const refIds = new Set(objectRefs.map((r) => r.id)); + const readsModelled = dataObjects.some( + (a) => a.kind === 'dataInputAssociation' && a.dataRefIds.some((id) => refIds.has(id)) + ); + for (const ref of readsModelled ? objectRefs : []) { + const readers = []; + const writers = []; + for (const a of dataObjects) { + if (a.kind === 'dataInputAssociation' && a.dataRefIds.includes(ref.id)) addUnique(readers, a.activityId); + if (a.kind === 'dataOutputAssociation' && a.dataRefIds.includes(ref.id)) addUnique(writers, a.activityId); + } + if (!writers.length && readers.length) { + processIO.inputs.push({ id: ref.id, name: ref.name, source: 'convention', scopeId: proc.id, readers }); + } else if (writers.length && !readers.length) { + processIO.outputs.push({ id: ref.id, name: ref.name, source: 'convention', scopeId: proc.id, writers }); + } + } +} + // --- signals per scope (pattern-rubric.md), computed from THIS scope's own flow nodes/ // flows only (nested sub-process scopes get their own signals, computed independently, so // bpmn2agent-design can recurse per callActivity/subProcess as the rubric requires) --- @@ -462,6 +608,8 @@ const inventory = { flowNodes, sequenceFlows, dataObjects, + dataStores, + processIO, textAnnotations, signals: aggregate, findings, From 3f0a9a9d6868c8bc698f39790ad76f837720a8ac Mon Sep 17 00:00:00 2001 From: Benjamin Tenke Date: Sat, 3 Oct 2026 15:57:39 +0200 Subject: [PATCH 07/31] feat(knowledge): ground tasks from knowledge stores in the diagram Co-Authored-By: Claude Sonnet 5.5 --- .agents/skills/bpmn2agent-knowledge/SKILL.md | 121 ++++++++++++------ .../references/notebook-extraction.md | 60 ++++++++- 2 files changed, 136 insertions(+), 45 deletions(-) diff --git a/.agents/skills/bpmn2agent-knowledge/SKILL.md b/.agents/skills/bpmn2agent-knowledge/SKILL.md index a7d2bc9..05b9ae1 100644 --- a/.agents/skills/bpmn2agent-knowledge/SKILL.md +++ b/.agents/skills/bpmn2agent-knowledge/SKILL.md @@ -1,6 +1,6 @@ --- name: bpmn2agent-knowledge -description: Grounds the agents and skills to be generated from a BPMN diagram in domain knowledge. Maps Gemini notebooks (NotebookLM, via gemini-notebook-mcp) to lanes/tasks, uses them to challenge the diagram (gaps become open questions, never silent redesign) and extracts cited reference material per element. Falls back to WebSearch, reviewed repo docs, or model knowledge marked "unverified". Use after bpmn2agent-analyze wrote generated//workflow-spec.yaml, before bpmn2agent-design. +description: Grounds the agents and skills to be generated from a BPMN diagram in domain knowledge. Reads the diagram's knowledge data stores (else maps Gemini notebooks, NotebookLM via gemini-notebook-mcp, to lanes/tasks), resolves each store's Ort, uses the sources to challenge the diagram (gaps become open questions, never silent redesign) and extracts cited reference material per reading task. Falls back to WebSearch, reviewed repo docs, or model knowledge marked "unverified". Use after bpmn2agent-analyze wrote generated//workflow-spec.yaml, before bpmn2agent-design. bpmn: file: docs/planning/bpmn-to-agentic-workflow.bpmn elements: @@ -10,8 +10,11 @@ bpmn: # BPMN → Agent Knowledge Grounding Input: the spec `bpmn2agent-analyze` wrote. Output: the same spec with `knowledge:` and -`openQuestions:` filled, plus `generated//knowledge/*.md` per mapped element/lane. Later -stages read these; they don't query notebooks themselves. +`openQuestions:` filled, plus `generated//knowledge/*.md`: one file per reading task, or per +element/lane under the fallback (§3). Later stages read these; they don't query notebooks themselves. + +The diagram is the source of truth: a `wissen` data store drawn with an arrow into a task **is** the +mapping. Ask the user only where the diagram says nothing. Every question goes through `AskUserQuestion` with concrete options plus a recommendation, in the user's business language. @@ -20,53 +23,88 @@ user's business language. Read `generated//workflow-spec.yaml`. Missing: **stop** and tell the user to run `bpmn2agent-analyze` first; never parse the `.bpmn` here. Its lanes/roles and elements are the -mapping targets and the units extraction writes one file per. +mapping targets. From `contextSources` take every store with `art: wissen`: its `name`, `ort` +(`{type, ref}`), `readers` and `bpmnElement`. Each reader is a **reading task**, the unit extraction +writes one file for. + +Only `wissen` stores are handled here. `live` stores are read at run time and `gedaechtnis` stores are +curated at run time; `bpmn2agent-design` resolves both, so skip them, extract nothing from them, and +don't ask about them. -## 2. Ask about notebooks +## 2. Resolve each store's Ort -Ask whether they have Gemini notebooks (NotebookLM) with knowledge the agents should have (process -handbooks, policies, prior write-ups, glossaries). Load the tools first: +Load the notebook tools once, when a `notebook:` store exists or step 3 needs them: ``` ToolSearch: select:mcp__gemini-notebook-mcp__notebook_list,mcp__gemini-notebook-mcp__notebook_describe,mcp__gemini-notebook-mcp__notebook_query,mcp__gemini-notebook-mcp__notebook_get ``` -Call `notebook_list` and offer the actual titles as options (plus "none of these" and a -recommendation), so the user picks by name, not UUID. On an auth/connection error, tell the user to -run `nlm login` in a terminal and ask whether to retry or continue without a notebook. Use -`notebook_describe` to sanity-check a pick before mapping. +Resolve by `ort.type`; nothing is asked when the store resolves cleanly: + +- **`notebook`**: call `notebook_list`, match `ort.ref` against the titles (exact, then + case-insensitive). One match: take its id and sanity-check it with `notebook_describe`. No match: ask + the user which notebook is meant, offering the actual titles (plus "none of these" and a + recommendation), and tell them to fix the `Ort:` line in the diagram. Auth/connection error: tell + the user to run `nlm login` in a terminal, then retry or treat the store as unresolved. +- **`url`**: `WebFetch` the page. `evidence: cited`, URL as the citation. +- **`datei`**: a local repo doc, cited through `references/notebook-extraction.md` §Citing local repo + docs. File missing: unresolved. +- **`websearch`**: targeted `WebSearch` queries per reading task. `evidence: cited`. +- **`mcp`**: only if the server's tools are connected (check with `ToolSearch` on + `mcp____`). Then read through its read tools once and keep the result as a + generation-time snapshot, cited as server, tool and date. Not connected: unresolved. + +An **unresolved** store gets an `openQuestions` entry (`elementId` = the store reference id, never +silently dropped or downgraded to model knowledge); offer the user: fix and re-run, or knowingly use a +fallback from step 3 for its readers. -Allow multiple notebooks. Ask which lanes/tasks each covers and record: +Record the notebooks, with `mappedTo` taken from the store readers (task ids), not from a question: ```yaml knowledge: notebooks: - id: title: - mappedTo: [, ...] - mode: notebook | websearch | local-docs | unverified # see §3 + mappedTo: [, ...] + mode: notebook | websearch | local-docs | unverified # see step 3 ``` -## 3. No notebook → offer a fallback +## 3. Fallback for what the stores don't cover -For lanes without a notebook, offer via `AskUserQuestion`. Recommend (d) if reviewed reference docs -for this domain exist in the repo, else (b) for generic domains, else (a). +Covered: every reading task of a resolved `wissen` store. Not covered: +- **a store with no `ort`** (analyze normally asks; if it slipped through, ask now), +- **a `serviceTask` (or `callActivity`/`businessRuleTask`) that reads no `wissen` store**, and +- **every task of a diagram with no `wissen` store at all.** + +Each uncovered `serviceTask` gets an `openQuestions` entry: "No knowledge source is drawn for this +step. Intentional, or a missing source?" (`answer: null` until decided; never an error). Ask once per +lane (not per task) and offer: + +- **(0) Intentional, no knowledge needed** (the recommendation for tasks that only use `live` or + `gedaechtnis` stores): answer the open question, write no file. +- **Notebook**: call `notebook_list`, offer the actual titles (plus "none of these"), record it in + `knowledge.notebooks` with the lane/task ids as `mappedTo`. Several notebooks are fine. - **(a) WebSearch per lane** — targeted queries per lane/phase, cited, `evidence: cited`. - **(b) Model knowledge** — every claim `evidence: unverified`; never silently upgraded later. - **(c) Pause to create a notebook** — the user builds one and re-runs this skill. - **(d) Cite existing repo docs** — ask which reviewed file(s) apply per lane/element; `evidence: cited`. Format: `references/notebook-extraction.md` §Citing local repo docs. -`knowledge.mode`: `notebook` if every element has notebook coverage, else the fallback -(`websearch | local-docs | unverified`). Mixing is fine; record the fallback used for uncovered lanes -as `knowledge.mode` and name each lane's source in its `knowledge/*.md` `sources:`. +Recommend (d) if reviewed reference docs for this domain exist in the repo, else (b) for generic +domains, else (a). This is the old lane-level flow, unchanged, and it stays the only flow for diagrams +without stores. Mixed diagrams use the stores where drawn and this flow for the rest. + +`knowledge.mode`: `notebook` if every in-scope task has notebook coverage; otherwise the fallback in +use (`websearch | local-docs | unverified`; `url`/`websearch` stores count as `websearch`, `datei` as +`local-docs`). Mixing is fine; name each source in its file's `sources:`. ## 4. Challenge the BPMN -For each lane/phase, run the **challenge queries** from `references/notebook-extraction.md` -§Challenge queries against its source (notebook, WebSearch or repo file). Under (b), answer them -from model reasoning and mark every finding `unverified`; don't skip the step. +For each reading task (fallback: each lane/phase), run the **challenge queries** from +`references/notebook-extraction.md` §Challenge queries against its source (notebook, page, repo file or +WebSearch). Under (b), answer them from model reasoning and mark every finding `unverified`; don't skip +the step. Only domain questions belong here. Queue agentic-design questions (patterns, agents, skills, checkpoints, hooks) as `openQuestions` entries with `source: agentic-design` and `answer: null` for @@ -91,36 +129,39 @@ loop-to-analyze path). Never edit the `.bpmn` or the spec's structural fields he `references/notebook-extraction.md` §FAQ log). On a re-run, read `knowledge/faq/README.md` first and re-ask only what it doesn't answer or what the changed diagram makes stale. -## 5. Extract reference material per element +## 5. Extract reference material per reading task -For each mapped element, run the **extraction queries** from `references/notebook-extraction.md` -§Extraction queries and write the distilled, cited result to -`generated//knowledge/.md`. Under (d), cite the repo file directly in -`knowledge.refs` or distill it (same reference, §Citing local repo docs). Under (b), still write one -file per in-scope element, `evidence: unverified` with inline callouts. +For each reading task write `generated//knowledge/.md` (the task's BPMN element id, +e.g. `Task_AntwortEntwerfen.md`): **one section per `wissen` store it reads**, named with the store's +label verbatim, each with its own citations. Run the **extraction queries** from +`references/notebook-extraction.md` §Extraction queries against that store's source only; the store's +Ort picks the route (`references/notebook-extraction.md` §Store-driven extraction). A task reading two +stores gets two sections in one file. Under the fallback (§3), write `.md` as before; +under (b), still one file per in-scope element, `evidence: unverified` with inline callouts. -With many lanes × notebooks, extraction may run as parallel `Agent` calls, one per lane/notebook; -each writes its `knowledge/.md` and saves its raw query results for the FAQ log. No Workflow -script. +With many tasks × notebooks, extraction may run as parallel `Agent` calls, one per task; each writes its +`knowledge/.md` and saves its raw query results for the FAQ log. No Workflow script. -Frontmatter (incl. the required `bpmn:` key), citation format, evidence tiers, chunking of large -`notebook_query` output, target length and persistence of `knowledge/*.md`: see +Frontmatter (incl. the required `bpmn:` key), section layout, citation format, evidence tiers, chunking +of large `notebook_query` output, target length and persistence of `knowledge/*.md`: see `references/notebook-extraction.md`. -Record the refs: +Record the refs, still keyed by element id (a lane under the fallback): ```yaml knowledge: refs: - : generated//knowledge/.md + : generated//knowledge/.md ``` ## 6. Hand off -Before finishing, confirm: every mapped element has a `knowledge.refs` entry or an explicit "no -coverage, mode: " note; every challenge finding has an `openQuestions` entry with an answer -(not null) or is flagged for the user to resolve before design; `source: agentic-design` entries -stay null, design answers them. `bpmn2agent-generate` copies +Before finishing, confirm: every reading task of a resolved `wissen` store has a `knowledge.refs` entry +and a cited section per store; every other in-scope element has a `knowledge.refs` entry, an answered +"intentional" open question, or an explicit "no coverage, mode: " note; every +`knowledge.notebooks[].mappedTo` lists the reading tasks; every challenge finding has an `openQuestions` +entry with an answer (not null) or is flagged for the user to resolve before design; +`source: agentic-design` entries stay null, design answers them. `bpmn2agent-generate` copies `knowledge/*.md` into skills' `references/` and agents' "Domain knowledge"; this skill does neither. ## Scripts diff --git a/.agents/skills/bpmn2agent-knowledge/references/notebook-extraction.md b/.agents/skills/bpmn2agent-knowledge/references/notebook-extraction.md index 28a3115..67b8dd6 100644 --- a/.agents/skills/bpmn2agent-knowledge/references/notebook-extraction.md +++ b/.agents/skills/bpmn2agent-knowledge/references/notebook-extraction.md @@ -2,8 +2,9 @@ Detail for `bpmn2agent-knowledge` §4/§5. Load this when actually querying, not before. -Contents: Challenge queries · Extraction queries · Citing local repo docs · Citation format · -Evidence marking and frontmatter · Knowledge files persist · Chunking · FAQ log · Keep it short +Contents: Challenge queries · Extraction queries · Store-driven extraction · Citing local repo docs · +Citation format · Evidence marking and frontmatter · Knowledge files persist · Chunking · FAQ log · +Keep it short ## Challenge queries @@ -43,13 +44,62 @@ Per element likely to become a skill, agent or gate/critic; skip elements likely Run only the ones relevant to the element (a `scriptTask` rarely needs domain knowledge, a lane rarely needs a checklist). +## Store-driven extraction + +Per reading task of a `wissen` store (SKILL.md §1), run the extraction queries relevant to that task +against **each store it reads, separately**; the store's `ort.type` picks the route: + +| `ort.type` | Route | Cited as | +|---|---|---| +| `notebook` | `notebook_query` on the notebook found by title (`new_conversation: true`, one question per call, log the FAQ) | notebook source name + quote | +| `url` | `WebFetch` the page, distill what answers the query | page title + URL | +| `datei` | §Citing local repo docs | file title + relative path | +| `websearch` | `WebSearch` queries scoped to the task | page title + URL | +| `mcp` | read through the server's read tools once; snapshot only | ``, tool name, date | + +All five yield `evidence: cited`. An unresolved store (title not found, server not connected, file +missing) has no section; it is an open question instead, never filled from model knowledge. + +One file per reading task, `knowledge/.md`, one section per store, named with the store label +verbatim: + +```markdown +--- +element: Task_AntwortEntwerfen +evidence: cited +sources: ["Support-Handbuch"] +bpmn: + file: + elements: [Task_AntwortEntwerfen] +--- + +## Support-Handbuch + +_Ort: notebook:Support-Handbuch_ + +Procedure, checklist, terminology for this task, each claim cited [^1]. + +[^1]: "Support-Handbuch", NotebookLM source, queried 2026-10-03 — "short verbatim quote". +``` + +- `element` is the reading task's id; `bpmn.elements` lists only that id (the stores are named in the + section headings and `sources:`). +- `sources:` lists every store's source (notebook title, URL, repo path, server), in section order. + `evidence:` is the dominant tier over all sections. +- Footnotes are one list at the file bottom, numbered across sections. The citation format below + applies per section; a section without a footnote is not `cited`. +- Each section follows the length target at the end of this file; scale it down when a task reads + several stores. + ## Citing local repo docs (mode (d)) -No query to run; point at the reviewed file(s) instead. Per element: +Used for fallback (d) and for `datei:` stores. No query to run; point at the reviewed file(s) +instead. Per element: - **Cite directly**: if the file already answers the extraction query briefly and on point (e.g. `bpmn2agent-design/references/mapping-rubric.md` for a mapping-decision element), set - `knowledge.refs.` to its repo-relative path and write no `knowledge/*.md`. + `knowledge.refs.` to its repo-relative path and write no `knowledge/*.md`. For a + `datei:` store only when it is the task's sole `wissen` store; otherwise distill it as a section. - **Distill**: if it is long, broader than this element, or needs combining with another source, write a normal `knowledge/.md` citing it like any source (file title instead of notebook name, relative path instead of URL). @@ -78,7 +128,7 @@ Approvals above €10,000 require a second signer [^1]. | Tier | Frontmatter value | Meaning | |---|---|---| -| Cited | `cited` | Backed by at least one notebook or WebSearch citation (footnote present). | +| Cited | `cited` | Backed by at least one notebook, page, repo-file or snapshot citation (footnote present). | | Inferred | `inferred` | Reasoned from cited material or from the BPMN itself, no direct source claim. | | Unverified | `unverified` | Model knowledge only — no notebook, no search, mode (b) from SKILL.md §3. | From 0cd4bf0e41bf54d7c76c6d48f28bc5f4fbbc07ad Mon Sep 17 00:00:00 2001 From: Benjamin Tenke Date: Sat, 3 Oct 2026 15:59:01 +0200 Subject: [PATCH 08/31] feat(design): resolve live store tools and place them per role Co-Authored-By: Claude Sonnet 5.5 --- .agents/skills/bpmn2agent-design/SKILL.md | 90 +++++++++++++++++-- .../references/mapping-rubric.md | 5 +- .../references/pattern-rubric.md | 27 +++++- 3 files changed, 110 insertions(+), 12 deletions(-) diff --git a/.agents/skills/bpmn2agent-design/SKILL.md b/.agents/skills/bpmn2agent-design/SKILL.md index c367355..f8c0954 100644 --- a/.agents/skills/bpmn2agent-design/SKILL.md +++ b/.agents/skills/bpmn2agent-design/SKILL.md @@ -54,6 +54,13 @@ Sort the spec's `elements` into: to re-run `bpmn2agent-analyze` once the `.bpmn` is updated. Leave it → set `kind: not-generated` (not `unresolved`) with the same reason text, and set that element's `openQuestions` entry to `answer: "known gap — not generated"`, `answeredAt: `; it needs no further rubric work. +- **Unguarded live write** — a task in `contextSources..writers` of an `art: live` store that + can be reached from a start event without passing a `userTask`. Check on the inventory's + `flowNodes`/`sequenceFlows`: drop every `userTask`; if the writer is still reachable (loops + included), it is unguarded. This is a diagram defect (`mapping-rubric.md` → "Writing into a live + store"): tell the user in business words which write lacks a confirmation step, **stop the whole + design pass** and point them at `bpmn-authoring`, then `bpmn2agent-analyze`. Never invent a + checkpoint in the spec. - **Already decided** — concrete `kind` from a previous design pass. Leave as-is unless the element is in the analyze diff's new/changed set. @@ -70,7 +77,7 @@ element: the user's project: `.claude/skills//SKILL.md`, `.claude/skills//scripts/.mjs`, `.claude/agents/.md`, `.claude/hooks/.mjs` (hook registration goes into the one `.claude/settings.json`, which no element claims). Empty for `orchestrator`, `human-checkpoint`, - `not-generated` and `unresolved`. + `context-source`, `workflow-input`, `workflow-output`, `not-generated` and `unresolved`. - `reason` — required for `not-generated`/`unresolved`; it appears verbatim in the mapping report. - `knowledge` — for `skill`/`agent-checklist`/`human-checkpoint`/`hook` only: notebook ids mapped to the element or its lane, else its `knowledge.refs` path, else `"websearch"`/`"model-only"` per @@ -81,9 +88,39 @@ element: - `inputs`/`outputs` — carry forward from analysis; add only artifacts the decision itself introduces (e.g. a sub-workflow's intermediate artifacts). +Data stores and process-wide input/output get `kind: context-source` / `workflow-input` / +`workflow-output` (the rubric's table; a convention input/output data object takes the `workflow-*` +kind, not `artifact-contract`). Their content is step 3a. + Don't ask about individual rubric applications. Save every genuinely uncertain call for the step-7 confirmation. +## 3a. Resolve context sources + +For every `contextSources.` (valid Art × Ort pairs: `mapping-rubric.md` → "Data stores → context +sources"; analyze settled invalid ones, ask again only if one slipped through): + +- **`art: live` → `tools: {read, write}`**, per `Ort` type (rule and heuristic in the rubric's "Live + stores: tools and placement"; don't restate them in the spec): + - `mcp:` — ToolSearch with query `mcp____` (raise `max_results` to cover the + server). Nothing found or server not connected → `tools: unresolved`. Classify by name + (`get/list/search/read/fetch/view` read; `create/update/delete/add/post/edit/transition/push` + write; unclear = write); a `readOnlyHint` in the tool metadata wins. Keep only tools the + store's readers/writers plausibly need (from their label and documentation); `write` stays + empty when the store has no writers. + - `cli:` — `command -v ` and its `--help` for the subcommands (nothing runs beyond + that); patterns `Bash( :*)`, same heuristic. Not installed → `unresolved`. + - `notebook:` — treat as `mcp:gemini-notebook-mcp`: `read: [mcp__gemini-notebook-mcp__notebook_query]`; + write tools only when the store has writers. + - URL → `read: [WebFetch]`; `datei:` → `read: [Read]` (plus `Edit`/`Write` under `write` if the + store has writers). +- **`art: gedaechtnis` → `memory: {path, maxLines: 150}`.** `path` is `ort.ref`; without one, + `.claude/memory//.md`. No `tools`. +- **`art: wissen`**: nothing to resolve (knowledge already extracted); no `tools`/`memory`. + +Each store's and each workflow-I/O element's `elements.` entry keeps its `kind` and has no +`generatedPaths`. + ## 4. Apply the pattern rubric Load `references/pattern-rubric.md` and walk its decision table with step 1's top-level `signals`. @@ -91,6 +128,11 @@ Load `references/pattern-rubric.md` and walk its decision table with step 1's to checkpoint's answer toward `judgementBranchCount` (recompute before consulting the table). Repeat per `scopes[].signals` for every sub-workflow; each gets its own pattern under the same `elements` map. +Add the two context-store signals the inventory doesn't carry: `liveWriteCount` per phase (writers of +`art: live` stores) and `roleToolSpread` (from step 3a's tools per lane). A phase with a live write is +never `workflow-script`; differing role privileges are a signal for `orchestrator-agent` (both in +the rubric). The step-2 guard check already ran, so no write here lacks its `userTask`. + Write `pattern.rationale` in the business phrasing of the rubric's "Explaining the choice" section. Add an `alternativesConsidered` entry when the signals were close to another row. @@ -107,6 +149,21 @@ ask: - a hook needs a tool matcher, or a lane's skills touch production artifacts or external APIs → propose a `tools:` allowlist. +Place the live-store tools from step 3a (placement rule: `mapping-rubric.md` → "Live stores: tools +and placement"): + +- **`orchestrator-agent`** (also an orchestrator-agent phase of `mixed`): each lane agent gets + `roles..tools` with the read tools of the stores its tasks read, the write tools of the + stores its tasks write, and the built-ins its skills need (`Read`, `Grep`, `Glob`, `Write` for its + artifacts and memory file). Nothing for stores it doesn't touch. `unresolved` stores add nothing. +- **Any other pattern**: the union of all read tools goes into `.claude/settings.json` → + `permissions.allow`; write tools never do (the user is asked at the call, backed by the + PreToolUse hook generate emits). Say in the plan: "Lesezugriff nicht pro Rolle getrennt". If + `roleToolSpread` holds, also recommend `orchestrator-agent` there. + +No spec field holds the `permissions.allow` list; generate derives it from +`contextSources.*.tools.read`. + Apply agent-authoring's "Should this be an agent at all?" and split rule to every lane. A lane that should become two agents or a skill is a question for step 7 (the lane belongs to the diagram), not a split you make; when the user agrees, record the reason in the spec. @@ -115,7 +172,9 @@ a split you make; when the user agrees, record the reason in the spec. For each `artifacts.` (from analysis plus step 3's additions), fill `pathPattern` and `frontmatter`. Artifacts crossing a gate or loop get `version` and `status` frontmatter. Add no -field that no producer or consumer reads. +field that no producer or consumer reads. The artifact behind `workflowIO.input` carries a +frontmatter field (`required: true`) for every name in `workflowIO.input.required`; the one behind +`workflowIO.output` is the contract for the end result. ## 6a. Check the orchestration against the knowledge base @@ -154,6 +213,20 @@ lane/role, then element, e.g.: > Insgesamt baue ich das als eine Abfolge von Checklisten, die an deinem Prüfpunkt pausiert > (siehe Begründung oben) — kein separates Steuerprogramm nötig. +Add a part "Kontextquellen" with one entry per store, for the user to confirm: name verbatim, Art and +Ort in plain words, who reads and who writes it (by task name), and the access split in business +language, e.g.: + +> **"Jira-Tickets Projekt LANE"** (live, Atlassian) — "Ticket analysieren" liest, "Kommentar im Ticket +> posten" schreibt (erst nach deiner Freigabe in "Antwort freigeben", und Claude Code fragt beim +> Schreiben zusätzlich nach). Lesezugriff nicht pro Rolle getrennt. +> *Technisch — lesen: `mcp__atlassian__getJiraIssue`; schreiben: `mcp__atlassian__addCommentToJiraIssue`.* + +Gedächtnis: file path and the 150-line cap; `unresolved` tools: say that the server wasn't reachable +and that the step stays without tool access until it is. Tool names appear only in the italic +technical line. Also name the process input with its required fields, and the output. Where +`roleToolSpread` holds and the pattern isn't `orchestrator-agent`, recommend it here. + Include the pattern and rationale ("how it runs"), any model/tools proposals from step 5, open questions from 6a, and every `not-generated`/`unresolved` element with its reason. Fold every pending pattern or model/tools question into this one confirmation. Offer at least: @@ -168,8 +241,9 @@ pending pattern or model/tools question into this one confirmation. Offer at lea ## 8. Write the confirmed spec Only after confirmation, write the decisions into `generated//workflow-spec.yaml`: every -element's `kind`/`generatedPaths`/`reason`/`knowledge`/`gate`, `roles.*.modelTier`/`tools` where set, -`artifacts.*`, `pattern`, `openQuestions`; update `meta.updated`; delete +element's `kind`/`generatedPaths`/`reason`/`knowledge`/`gate` (including the store and workflow-I/O +entries), `roles.*.modelTier`/`tools` where set, `artifacts.*`, `contextSources.*.tools`/`memory` +and `workflowIO` as confirmed, `pattern`, `openQuestions`; update `meta.updated`; delete `workflow-spec.draft.yaml`. Validate: run `node ${CLAUDE_SKILL_DIR}/../bpmn2agent-verify/scripts/verify.mjs "$cacheDir" generated/` and read only its spec-schema section (other categories may fail this early). Fix until it passes. @@ -190,10 +264,10 @@ before writing. ## Reference files -- `references/mapping-rubric.md` — element → `kind` table, sub-decisions, v1 supported constructs, - mapping-view colours. -- `references/pattern-rubric.md` — signals, pattern table, per-pattern generation/checkpoint/loop - cap/resume detail, business phrasing. +- `references/mapping-rubric.md` — element → `kind` table, sub-decisions, data stores → context + sources (Art × Ort, tools and placement, write guard), v1 supported constructs, mapping-view colours. +- `references/pattern-rubric.md` — signals (incl. live writes, role tool spread), pattern table, + per-pattern generation/checkpoint/loop cap/resume detail, business phrasing. - `assets/workflow-spec.schema.yaml` — the schema for step 8. - `${CLAUDE_SKILL_DIR}/../agent-authoring/SKILL.md` — naming and split rule (step 5). - `${CLAUDE_SKILL_DIR}/../orchestration-design/SKILL.md` — inline fallback review (step 6a). diff --git a/.agents/skills/bpmn2agent-design/references/mapping-rubric.md b/.agents/skills/bpmn2agent-design/references/mapping-rubric.md index 63763b8..06ecd6f 100644 --- a/.agents/skills/bpmn2agent-design/references/mapping-rubric.md +++ b/.agents/skills/bpmn2agent-design/references/mapping-rubric.md @@ -132,8 +132,9 @@ Anything else (e.g. `live` + `websearch`, `gedächtnis` + `mcp:`) is invalid. the mapping plan. Server not connected → `tools: unresolved` (verify warns, generate emits no tools, never a wildcard). - **Place them.** Where lanes are agents (`orchestrator-agent`), the needed read tools go into that - lane agent's `tools:`, least privilege per role. Otherwise they go into `.claude/settings.json` → - `permissions.allow` (union of all read tools) and the plan says openly "Lesezugriff nicht pro Rolle + lane agent's `tools:`, least privilege per role (a lane that writes also gets that store's write +tools; they stay behind the `userTask` and the hook). Otherwise they go into `.claude/settings.json` → + `permissions.allow` (union of all read tools; write tools never go there) and the plan says openly "Lesezugriff nicht pro Rolle getrennt". **If the roles need different privileges, that is a signal for `orchestrator-agent`** (see `pattern-rubric.md`). diff --git a/.agents/skills/bpmn2agent-design/references/pattern-rubric.md b/.agents/skills/bpmn2agent-design/references/pattern-rubric.md index d291f72..c9e08de 100644 --- a/.agents/skills/bpmn2agent-design/references/pattern-rubric.md +++ b/.agents/skills/bpmn2agent-design/references/pattern-rubric.md @@ -32,6 +32,8 @@ Count these over the diagram (or sub-diagram) being decided: | `loopCount` | Back-edges (loop merge → split pairs per `bpmn-authoring/references/modelling-rules.md`) | | `judgementBranchCount` | `exclusiveGateway`s whose outgoing conditions require an LLM to weigh a case (e.g. "is this good enough?", "which of these applies?") rather than a deterministic threshold a script can evaluate | | `attended` | `humanTaskCount > 0` — a human must be present at least once while it runs | +| `liveWriteCount` | Tasks in the phase that write into a `live` context store (`contextSources.*.writers` of `art: live`). Writes into `gedaechtnis` stores don't count. | +| `roleToolSpread` | Two or more lanes need different live-store tools (a lane reads a store another doesn't need, or only some lanes write). Needs `contextSources.*.tools` resolved first (`SKILL.md` step 3a). | ## Decision table @@ -45,6 +47,20 @@ Count these over the diagram (or sub-diagram) being decided: If two rows plausibly apply, prefer the earliest that fits. Choose `mixed` only when phases are *structurally* different, not because the diagram is large. +Two context-store rules apply on top of the table: + +- **`liveWriteCount > 0` rules out `workflow-script` for that phase.** The pattern has no human + checkpoints, and a write into a live store needs a `userTask` before it on every path (the + write-guard rule in `mapping-rubric.md`). Take the next fitting row, or `mixed` with the writing + phase as `skill-chain-hooks`/`orchestrator-agent`. A phase with a live write and no `userTask` + before it is a diagram defect, not a pattern question: route to `bpmn2agent-analyze` (change the + `.bpmn`), never invent a checkpoint in the spec. +- **`roleToolSpread` is a signal for `orchestrator-agent`.** It is the only pattern where each role + is its own agent with its own `tools:`. If the table picks another row, keep that row, say in the + mapping plan that read access is not separated per role ("Lesezugriff nicht pro Rolle getrennt"; + the tools go into `permissions.allow`) and offer `orchestrator-agent` as the option that + separates them; record it under `alternativesConsidered`. + ## Per-pattern detail ### Skill chain + hooks @@ -67,8 +83,8 @@ If two rows plausibly apply, prefer the earliest that fits. Choose `mixed` only ### Claude Code Workflow script - **When**: fully unattended, real parallel/multi-instance structure, deterministic branching. -- **When not**: any human checkpoint inside the flow, or branching that needs judgment a script - condition can't express. +- **When not**: any human checkpoint inside the flow, branching that needs judgment a script + condition can't express, or any write into a live context store (`liveWriteCount > 0`). - **Sanity check**: the three-of-five rule in `${CLAUDE_SKILL_DIR}/../agentic-workflow-kb/references/claude-code-workflows.md`. Workflow `agent()` subagents can't ask the user, so any attended step disqualifies that phase. @@ -105,6 +121,8 @@ If two rows plausibly apply, prefer the earliest that fits. Choose `mixed` only phase (Workflow script) feeding a phase that needs a human sign-off between two skills (skill chain), or a deterministic phase followed by a judgment-heavy one (orchestrator agent). - **When not**: the whole diagram fits one pattern; re-check the decision table per phase first. +- **Live writes**: a phase with a live-store write is never the Workflow-script phase; its + `userTask` and the write sit in the same phase. - **Generated**: each phase per its own pattern; the phase boundary is the hand-off point (typically a human checkpoint or an orchestrator decision that starts the next phase). Record the split in `pattern.phases[]` (`[{name, pattern, elements: [...]}]`, one entry per phase in diagram order); @@ -130,3 +148,8 @@ Tie the explanation to the shape they drew, not to the pattern's name. Examples: - **Mixed**: "The first part of your diagram runs entirely on its own; the second part needs your sign-off partway through — I'll build the first part as an automated script and the second as a guided checklist, with a clear handoff between them." +- **Live write forces a human step**: "Your diagram posts into Jira, so I'll build this so that you + confirm first and nothing is written automatically — that rules out the fully automatic script." +- **Different access per role**: "The roles don't need the same access to your systems. As a guided + checklist they all share one set of permissions; a coordinating agent could give each role only + what it needs — I'd recommend that if the separation matters to you." From 47662b8d34ffbc1c04363fdd5d19345cadab6489 Mon Sep 17 00:00:00 2001 From: Benjamin Tenke Date: Sun, 4 Oct 2026 00:50:56 +0200 Subject: [PATCH 09/31] feat(verify): trace context sources and guard live store writes Co-Authored-By: Claude Sonnet 5.5 --- .agents/skills/bpmn2agent-verify/SKILL.md | 20 +- .../bpmn2agent-verify/scripts/verify.mjs | 276 +++++++++++++++++- 2 files changed, 290 insertions(+), 6 deletions(-) diff --git a/.agents/skills/bpmn2agent-verify/SKILL.md b/.agents/skills/bpmn2agent-verify/SKILL.md index 9818268..f651931 100644 --- a/.agents/skills/bpmn2agent-verify/SKILL.md +++ b/.agents/skills/bpmn2agent-verify/SKILL.md @@ -42,6 +42,20 @@ Categories, in run order: 6. **no-red** — no `kind: unresolved`, no `openQuestions[]` with `answer: null`, and `mapping/workflow-mapped.bpmn` (if rendered) validates. +Plus **context-sources**, run after element-to-artifact and only when the diagram has data stores or +a process `dataInput`/`dataOutput`, or the spec has `contextSources`/`workflowIO` (otherwise absent, +output unchanged). Each finding ends with `[fix in bpmn2agent-]`: + +- every store and process input/output has an `elements.` entry (`context-source` / + `workflow-input` / `workflow-output`) and a `contextSources` entry / `workflowIO` → design +- `contextSources.*.readers`/`writers` (and `art`, `ort.type`) match the diagram's arrows → analyze (stale spec) +- **write guard:** a task writing into a `live` store needs a `userTask` on **every** path from the + start (loops and sub-processes included: a loop's first pass must be guarded too) → analyze, + the diagram changes; verify never edits the `.bpmn` +- a live-store write inside a `workflow-script` phase (`pattern.chosen` or a `mixed` phase) → design +- `tools: unresolved` → design (warning) +- a `gedaechtnis` store without writer or reader in the spec → analyze + ## 2. Translate and route Translate each finding into business language, keeping the element label and file path. Group by @@ -49,9 +63,9 @@ where the fix belongs, not by category: | Route | When | Example | |---|---|---| -| `bpmn2agent-design` | the spec is wrong or inconsistent with what was confirmed | `kind` without `reason`, bad `generatedPaths` prefix, unknown `producer`/`consumers` id, `unresolved` element not meant to stay open, open question the user can now answer | +| `bpmn2agent-design` | the spec is wrong or inconsistent with what was confirmed | `kind` without `reason`, bad `generatedPaths` prefix, unknown `producer`/`consumers` id, `unresolved` element not meant to stay open, open question the user can now answer, store or process input/output without `elements`/`contextSources`/`workflowIO` entry, live-store write in a workflow-script phase, `tools: unresolved` (warning) | | `bpmn2agent-generate` | the spec is fine, the files don't match or don't parse | missing file, missing/wrong `bpmn:` header, unregistered hook, npm import, failing `node --check`, non-literal Workflow `meta`, orphan file (remove it; if it is real output, its element's `generatedPaths` must name it → design) | -| `bpmn2agent-analyze` | the diagram changed or is invalid | `sha256` mismatch, `validate.sh` failure on the source `.bpmn` | +| `bpmn2agent-analyze` | the diagram changed or is invalid | `sha256` mismatch, `validate.sh` failure on the source `.bpmn`, `contextSources` readers/writers out of date, live-store write without a `userTask` on every path (draw an approval step), memory store without writer or reader | Sample phrasing: *"The plan for '