diff --git a/README.de.md b/README.de.md index ab06fd9..831fb4a 100644 --- a/README.de.md +++ b/README.de.md @@ -219,6 +219,7 @@ anderen Domain läge das Web-Verzeichnis in `…/subs-ssl//`.) - `docs/DECISIONS.md` — Design-Entscheidungen mit Begründung - `docs/ROADMAP.md` — Mermaid-Plugin, Taiga-Integration, Tenzu - `docs/TASKS.md` — offene Aufgaben (Checkboxen) +- `docs/rfc/` — Vorschläge, die mehrere Teile des Repos berühren und vor dem Bauen abgewogen werden (001: ein MCP-Server für KI-Agenten) - `docs/brand/BRAND.md` — Logo, Wortbild, Anwendungsregeln - `docs/design/` — Design-Herleitung der Marke - `CLAUDE.md` — Projektkontext für Claude Code diff --git a/README.md b/README.md index 026c5b0..86c1a24 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,7 @@ directory would be `…/subs-ssl//`.) - `docs/DECISIONS.md` — design decisions with rationale - `docs/ROADMAP.md` — Mermaid plugin, Taiga integration, Tenzu - `docs/TASKS.md` — open tasks (checkboxes) +- `docs/rfc/` — proposals that span several parts of the repo, weighed before they are built (001: an MCP server for AI agents) - `docs/brand/BRAND.md` — logo, wordmark, usage rules - `docs/design/` — design derivation of the brand - `CLAUDE.md` — project context for Claude Code diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index b4ec06e..4b15fb1 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -17,6 +17,10 @@ the git history of `docs/examples/werkbaum.werkbaum`. A day can therefore carry a link without having a note (someone forgot to write one) — but never the reverse. +## 2026-09-02 + +- An MCP server for AI agents recorded as planned: a Node package that reuses the one JS parser, hands the plan to Claude Code and other agents as resource and tools, writes changes as conflict-safe line diffs, and mirrors the shared document into git after every agent write — spelled out in an RFC before it is built + ## 2026-08-28 - Folding or unfolding a node keeps it in place on screen now: the scroll position follows the layout shift, so the clicked node no longer jumps away diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index 9a68a46..10a751a 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -8673,3 +8673,68 @@ sagen weiterhin, wo sich einer lohnt. Und ein Doppelklick öffnet und schließt in einem Zug — hinnehmbar, auf Knoten doppelklickt niemand absichtlich. +## D93 — MCP-Server für KI-Agenten: als RFC vorgelegt, nichts gebaut +Gewünscht: ein Plan für ein MCP-Modul, mit dem KI-Agenten außerhalb des +Editors (Claude Code, IDE-Agenten, Desktop-Assistenten) einen Werkbaum-Plan +lesen, befragen und ändern können. Der Plan liegt als **RFC** in +`docs/rfc/001-mcp-server.md` — die erste Datei dieser Art; ein RFC ist die +Form für etwas, das über mehrere Teile des Repos reicht und Alternativen +abwägt, bevor eine Zeile Code entsteht (die Taiga-Anlage in D91 hat +dasselbe als Nachtragskette getan). Im mitgelieferten Plan steht es als +`#ai.mcp` mit Teilpaketen. + +**Was das RFC vorschlägt, in einem Satz:** Ein Node-Paket `mcp/`, das die +headless-Module des Frontends (`parser.js`, `model.js`, `live.js`) +**unverändert importiert** — kein zweiter Parser, D14 —, den Plan als +Ressource anbietet, mit Tools den Baum, die Warnungen und den günstigsten +Pfad liefert und Änderungen als Zeilen-Diff mit Basisversion und Prüfsumme +schreibt (D76), mit zwei Leitplanken: keine beschädigte Notation, kein +`[^]` von einem Agenten (D30). + +**Schon entschieden, weil es aus vorhandenen Entscheidungen folgt:** + +- **Kein Server im Kotlin-Backend** (`#ai.mcp.kotlin` als `[-]`): Jedes + nützliche Tool braucht den Parser, und ein Kotlin-Parser ist genau die + zweite Grammatik, die D14 verbietet. +- **Kein Modell im Server, kein API-Schlüssel:** Das Modell sitzt im Host; + `#ai.key` und `#ai.dialog` bleiben eigene Knoten. Der MCP-Server ist die + **Gegenrichtung** zu `#ai.dialog`, nicht sein Ersatz. +- **Kein Geheimnis über MCP:** Master-Passwort (D76-Nachtrag 6) und + Taiga-Token (D91) laufen nie durch ein Transkript — deshalb weder die + Dokumentenliste noch Taiga-Tools in der ersten Fassung. +- **Kein Backend-Umbau:** Die vorhandene REST-API genügt. +- **Geteiltes Dokument und Git zugleich** (Nutzer-Wunsch, mitten in der + Ausarbeitung): Der Agent arbeitet auf dem Server-Dokument, und nach + jedem seiner Schreibvorgänge committet der Server den Serverstand über + das vorhandene `pull-doc --git-commit` (D88) in eine Spiegel-Datei — + der Server ist die Quelle, Git das Archiv (`#ai.mcp.mirror`). Die + Umkehrung, Git als Quelle, bleibt bei `#col.git`. + +**Entschieden in einer Multiple-Choice-Runde** (RFC §11, jede Frage mit +der Option „zunächst offen halten“ — keine wurde gewählt): + +- **`@modelcontextprotocol/sdk` darf herein** — die erste + Laufzeit-Abhängigkeit des Repos, isoliert im MCP-Paket; der gebündelte + Editor bleibt abhängigkeitsfrei (D11/D19/D20). Die Rückfrage, die + CLAUDE.md verlangt, ist damit gestellt und beantwortet. +- **Nur Struktur-Warnungen blockieren** einen Agenten-Schreibvorgang + (`mixedGate`, `unknownStatus`, `descStray`, `duplicateId`); inhaltliche + Widersprüche (`sizeConflict`, `assigneeOverload`, `unknownDep`, …) + werden geschrieben und gemeldet. Vorgeschlagen war die strenge Fassung + (jede neue Warnung blockiert, D59-Linie); der Nutzer hat entschieden, + dass ein Agent in Zwischenschritten arbeiten darf und ein Mensch die + bernsteinfarbenen Marken sieht — wie bei einer eigenen Änderung. +- **Der Anzeigename ist der Host-Name aus dem Handshake** („Claude Code“), + Rückfall „Agent“. +- **Knoten-Verben kommen dazu** (`add_node`, `move_node`, `set_size`, + `remove_node`) — nicht nur `apply_ops`. Die Text→Text-Regeln dafür + liegen als `frontend/src/edit.js` neben `setFoldMark` und + `expandShortIds`, headless und getestet; das Paket verdrahtet nur. + Damit kennt weiterhin genau eine Stelle das Zeilenformat. +- **Die Baum-Serialisierung bleibt im MCP-Paket**, **verteilt wird nur + aus dem Repo** (`.mcp.json`, kein npm). + +Offen bleibt der Transport über Streamable HTTP (nach `#col.live.owner`) +und die Form der Urheber-Angabe im `pull-doc`-Commit. Die +Umsetzungsreihenfolge steht im RFC; gebaut ist nichts. + diff --git a/docs/examples/werkbaum.werkbaum b/docs/examples/werkbaum.werkbaum index 06658db..2157fd2 100644 --- a/docs/examples/werkbaum.werkbaum +++ b/docs/examples/werkbaum.werkbaum @@ -225,6 +225,16 @@ - [?] #ai.dialog: Edit the plan in a dialogue with the AI (L) - [?] #ai.key: Bring your own API key, no server in between (M) - [?] #ai.ground: llms.md grounds the model in the notation (S) + - [ ] #ai.mcp: An MCP server hands the plan to outside agents (XL) :#not.llms %% docs/rfc/001-mcp-server.md + - [ ] #ai.mcp.node: A Node package that reuses the one JS parser (S) %% no second parser, D14 + - [ ] #ai.mcp.read: Resources: the agent guide, a file, a server document (S) + - [ ] #ai.mcp.inspect: Tools that answer what the diagram answers (M) %% tree, warnings, cheapest path + - [ ] #ai.mcp.write: Writes go out as line diffs and are refused on conflict (M) :#col.live.diff + - [ ] #ai.mcp.guard: Guard rails: no broken notation, no [^] from an agent (S) + - [ ] #ai.mcp.verbs: Node verbs: add, move, size, remove — the rules live in the frontend (M) :#ai.mcp.write + - [ ] #ai.mcp.mirror: The shared document mirrors into git after every agent write (S) :#col.git.pull + + [?] #ai.mcp.http: A remote transport over streamable HTTP (M) + - [-] #ai.mcp.kotlin: A server inside the backend (L) %% would need a Kotlin parser, D14 --- #wb @@ -1285,3 +1295,64 @@ The system prompt is essentially llms.md (D43): the agent guide already explains the notation for reading and writing, so the model needs no training — just the document and the request. + +#ai.mcp + The other direction of the AI integration: not an LLM inside the editor, + but the plan handed to agents that live outside it — Claude Code, IDE + agents, desktop assistants — over the Model Context Protocol. Specified in + docs/rfc/001-mcp-server.md before anything is built. + +#ai.mcp.node + The server is a small Node package that imports the frontend's headless + modules (parser, model, live diff) as they are. That keeps D14 intact: the + one JS parser stays the only parser, and agents get the same warnings, + effective statuses and cheapest path the diagram shows. + +#ai.mcp.read + What an agent can read: llms.md as the notation guide, a local .werkbaum + file, and a shared document on a Werkbaum backend by its URL — the same + three sources a person has. + +#ai.mcp.inspect + Tools that return the parsed tree with ids, statuses (own and effective), + sizes (given and assumed), tags and dependencies, the warnings the editor + would show, and the cheapest path with its stations and per-person load — + so the agent reasons on the model instead of re-implementing the SPEC. + +#ai.mcp.write + Edits leave the server as the same line diffs the editor sends: against a + base version with checksum, refused on a real conflict, visible to every + open editor with "changed by" naming the agent. A local file is written + only if it is unchanged since it was read. + +#ai.mcp.guard + Guard rails on every write: the result must not break the notation (no new + mixedGate, unknownStatus, descStray or duplicateId), and an agent never + writes [^] — "in production" is a deploy's statement (D30), not a model's. + Content warnings like a size conflict are written and reported, so a human + sees them as the amber mark. Both rails can be lifted per call, never silently. + +#ai.mcp.verbs + Convenience for the model: add a node under a parent, move a subtree, set a + size, remove or discard a node — by id, not by line index, which an agent + gets wrong. The text-to-text rules live in frontend/src/edit.js beside the + fold and short-id helpers, so exactly one place keeps knowing the line format. + +#ai.mcp.mirror + Both at once: the agent works on the shared document, where the people + are, and the same plan stays under git control. After every agent write + the server runs pull-doc --git-commit for a configured mirror file, naming + the agent in the commit — the server is the source, git the archive. The + reverse (git as the source) is a different node, #col.git. + +#ai.mcp.http + Streamable HTTP as a second transport, so a hosted agent can reach the + server without a local process. Optional: stdio covers the local agents + first, and remote access raises the authentication question the backend + has not answered yet (#col.live.owner). + +#ai.mcp.kotlin + Building the server into the Spring backend would put it next to the + documents — but every useful tool needs the parser, and a Kotlin parser is + exactly the second grammar D14 forbids. Discarded in favour of the Node + package. diff --git a/docs/rfc/001-mcp-server.md b/docs/rfc/001-mcp-server.md new file mode 100644 index 0000000..2a6080b --- /dev/null +++ b/docs/rfc/001-mcp-server.md @@ -0,0 +1,562 @@ +# RFC 001 — MCP-Server: Werkbaum für KI-Agenten außerhalb des Editors + +| | | +|---|---| +| Status | **Abgestimmt** (2026-09-02, Entscheidungen in §11 und D93) — nichts gebaut | +| Plan-Knoten | `#ai.mcp` in `docs/examples/werkbaum.werkbaum` | +| Entscheidung | D93 in `docs/DECISIONS.md` (Verweis auf dieses RFC) | +| Berührt | `frontend/src/*` (headless-Module, lesend), neues Paket `mcp/`, `tools/pull-doc` (Aufrufer), README, `.mcp.json` | +| Berührt nicht | Notation (SPEC), `llms.md`, Backend-Code, Deploy-Skripte | + +## 1. Zusammenfassung + +Werkbaum bekommt einen **MCP-Server** (Model Context Protocol): ein kleines +Node-Paket, das KI-Agenten außerhalb des Editors — Claude Code, IDE-Agenten, +Desktop-Assistenten — einen Werkbaum-Plan als **Ressource** (Text) und als +**Werkzeuge** (Baum, Warnungen, günstigster Pfad, Schreiben) anbietet. + +Der Server **parst nicht selbst**: Er importiert die headless-Module des +Frontends (`parser.js`, `model.js`, `live.js`) unverändert. Damit bleibt D14 +gewahrt — es gibt weiterhin genau einen Parser — und ein Agent bekommt +wörtlich dieselben Warnungen, effektiven Status und Stationen, die das +Diagramm zeigt. + +Geschrieben wird über denselben Weg wie aus dem Editor: als **Zeilen-Diff +gegen eine Basisversion mit Prüfsumme** (D76). Fremde Änderungen werden nie +überschrieben, ein Konflikt kommt als Fehler zurück, und in jedem offenen +Editor steht „geändert von: *Claude Code*“. Zwei Leitplanken gelten auf +jedem Schreibvorgang: **keine beschädigte Notation** (Struktur-Warnungen +blockieren, inhaltliche werden gemeldet), **kein `[^]` von einem Agenten**. + +Der Server arbeitet bevorzugt auf dem **geteilten Dokument** — dort sitzen +die Menschen —, und derselbe Plan kann zugleich **unter Git-Kontrolle** +stehen: Nach jedem Agenten-Schreibvorgang committet der Server den +Serverstand über das vorhandene `tools/pull-doc --git-commit` (D88) in eine +Spiegel-Datei. Der Server ist die Quelle, Git das Archiv (§5.7). + +Das ist die **Gegenrichtung** zu `#ai.dialog`: Dort käme ein Modell in den +Editor, hier geht der Plan zu Agenten, die schon irgendwo laufen. Beides +teilt sich den Boden (`llms.md`, D43) und die Module; keines ersetzt das +andere. + +## 2. Motivation + +Heute kann ein Agent mit einem Werkbaum-Plan dreierlei tun — und alles +davon nur halb: + +1. **Eine `.werkbaum`-Datei lesen und schreiben.** Das geht mit Claude Code + bereits, `llms.md` erklärt die Notation (D43). Aber der Agent muss die + **Semantik** selbst nachrechnen: Ist der Plan warnungsfrei? Welcher + Knoten ist effektiv wie weit (§4)? Was ist die nächste Station auf dem + günstigsten Pfad (§9)? Für all das gibt es im Frontend geprüfte + Funktionen — der Agent bekommt sie nicht zu sehen und rät stattdessen. + Beim Größen-Konflikt (D62) oder der Closure-Rechnung (D42) ist Raten + nachweislich falsch. +2. **Ein Server-Dokument (`?live=`) anfassen.** Nur per `curl` gegen die + REST-API — mit Volltext-`PUT`, also ohne das Zeilen-Diff-Protokoll (D76). + Ein Agent, der so schreibt, überschreibt, was ein Mensch in der + Zwischenzeit getippt hat; genau der Verlust, gegen den D89 vier Netze + gespannt hat. +3. **Den Plan im Editor ändern lassen** — `#ai.dialog` ist eine Idee ohne + Entwurf. + +MCP ist inzwischen die Verkehrssprache dafür: Claude Code, Claude Desktop, +Cursor, IntelliJ-Agenten und die Anthropic-API selbst (MCP-Connector) +sprechen es. Ein Server, der Werkbaum darüber anbietet, macht Punkt 1 und 2 +auf einen Schlag richtig — und zwar für **alle** diese Hosts, nicht nur für +einen. + +## 3. Ziele und Nicht-Ziele + +**Ziele** + +- Ein Agent kann einen Plan **lesen** (Datei oder Server-Dokument) und den + Notationsleitfaden dazu bekommen. +- Ein Agent kann den Plan **befragen**, ohne die SPEC nachzuimplementieren: + Baum mit allem, was das Diagramm weiß; Warnungen; günstigster Pfad samt + Stationen und Personen-Last. +- Ein Agent kann den Plan **ändern**, ohne fremde Arbeit zu überschreiben, + und jede Änderung ist im Editor als Agenten-Änderung erkennbar. +- Kein zweiter Parser, keine zweite Semantik (D14). +- Kein Geheimnis läuft durch den Server, das er nicht braucht. + +**Nicht-Ziele (Abgrenzung — wird nicht gebaut, siehe §9)** + +- **Kein LLM im Server.** Der Server ruft kein Modell auf und kennt keinen + API-Schlüssel. Das Modell sitzt im Host; `#ai.key` bleibt ein eigener + Knoten. +- **Keine neue Notation.** Nichts an SPEC oder `llms.md` ändert sich. +- **Kein Backend-Umbau.** Die vorhandene REST-API genügt (§7.3). +- **Kein Taiga über MCP** in der ersten Fassung (§9). +- **Keine Rechteverwaltung** — der Server erbt das Zugriffsmodell des + Backends (unerratbare UUID, D76) und erfindet keines dazu. +- **Kein Ersatz für `#ai.dialog`** und kein Chat im Editor. + +## 4. Begriffe (soweit hier nötig) + +MCP trennt **Hosts** (die Anwendung mit dem Modell: Claude Code, Desktop, +IDE) von **Servern** (Prozesse, die Fähigkeiten anbieten). Ein Server +bietet drei Dinge an: + +- **Resources** — lesbare Inhalte mit URI, vom Host in den Kontext geholt + („zeig mir den Plan“). +- **Tools** — aufrufbare Funktionen mit JSON-Schema, die das Modell selbst + wählt („prüfe den Plan“, „setze den Status“). +- **Prompts** — vorgefertigte Anweisungen, die der Nutzer auswählt + („zerlege diesen Knoten“). + +Transporte: **stdio** (der Host startet den Server als Kindprozess — der +Normalfall für lokale Werkzeuge) und **Streamable HTTP** (ein +Netzwerk-Endpunkt; hat 2025 das ältere SSE-Verfahren abgelöst). Die +Protokollrevision wird vom SDK getragen; dieses RFC legt keine fest. + +## 5. Vorschlag + +### 5.1 Architektur + +``` + Host (Claude Code, IDE, Desktop) Werkbaum + ┌──────────────┐ stdio / JSON-RPC ┌──────────────────────────────┐ + │ Modell │◄────────────────────►│ mcp/server.js │ + │ + Werkzeuge │ │ ├─ resources (Text, Guide) │ + └──────────────┘ │ ├─ tools (inspect, │ + │ │ write) │ + │ └─ stores │ + │ ├─ file (fs) │ + │ └─ live (REST, D76) │ + │ importiert unverändert: │ + │ frontend/src/parser.js │ + │ frontend/src/model.js │ + │ frontend/src/live.js │ + └──────────────┬───────────────┘ + │ HTTP + ┌──────────────▼───────────────┐ + │ Backend /api/v1/documents/… │ + └──────────────────────────────┘ +``` + +Ein Paket `mcp/` neben `frontend/` und `backend/`, eigenes `package.json`, +ES-Module. Es hat **keine** Kopie von Werkbaum-Logik; alles Entscheidbare +kommt aus `frontend/src`. Was das Paket selbst beisteuert, ist Verdrahtung: +MCP-Rahmen, zwei Ablagen, JSON-Serialisierung des Baums und die +Leitplanken. + +### 5.2 Ablagen + +Ein Plan wird über eine **Quelle** adressiert — dieselben drei, die ein +Mensch hat, minus `?sourceUrl=` (nur lesend, kommt bei Bedarf dazu): + +| Quelle | Adressform | Lesen | Schreiben | +|---|---|---|---| +| Datei | absoluter Pfad oder relativ zum Arbeitsverzeichnis | `fs` | atomar (Temp-Datei + `rename`); **nur, wenn die Datei seit dem Lesen unverändert ist** (Prüfsumme) | +| Server-Dokument | `https://…/api/v1/documents/` oder der geteilte `?live=`-Link (ausgepackt wie bei `pull-doc`, D88) | `GET` | `PATCH /content` mit Zeilen-Diff, `baseVersion`, `checksum` (D76) | +| Leitfaden | `werkbaum://guide` | `frontend/public/llms.md` | — | + +Der Dateizugriff ist auf **erlaubte Wurzeln** begrenzt (Startparameter +`--root`, Voreinstellung: das Arbeitsverzeichnis des Hosts). Ein Agent, der +einen Pfad außerhalb nennt, bekommt einen Fehler — nicht, weil ihm misstraut +wird, sondern weil der Plan-Text Fremddaten ist (§8). + +### 5.3 Resources + +| URI | Inhalt | MIME | +|---|---|---| +| `werkbaum://guide` | `llms.md` — der Notationsleitfaden (D43) | `text/markdown` | +| `werkbaum://file/` | Notationstext der Datei | `text/plain` | +| `werkbaum://doc/` | Notationstext des Server-Dokuments, mit `version` als Metadatum | `text/plain` | + +Resources sind bewusst **nur der Text**: Er ist das führende Format (D14), +und ein Agent, der ihn im Kontext hat, kann mit `llms.md` schon alles +lesen. Die Semantik kommt aus den Tools. + +### 5.4 Tools + +Wenige Verben, sprechend benannt, alle mit `source` als erstem Parameter +(Pfad oder URL): + +| Tool | Eingabe | Ausgabe | Nutzt | +|---|---|---|---| +| `werkbaum_read` | `source` | Text, `version`/Prüfsumme, Zeilenzahl | Ablage | +| `werkbaum_inspect` | `source`, optional `id` (Teilbaum), `include: [tree, warnings, path]` | JSON: Baum je Knoten mit `id`, `label`, `line`, `gate`, `optional`, `status`, `effectiveStatus`, `size`, `assumedSize`, `tags`, `deps`, `desc`, `taigaSlug`, `ticketRef`; Warnungen als `{type, line, …}` **plus** englischer Klartext; Pfad als Liste der nötigen Knoten, Stationen in Dokumentreihenfolge, `assigneeLoads`, `overloadedAssignee`, `exact` (D42) | `parse`, `effectiveStatus`, `computeCheapPlan`, `assigneeLoads`, `taigaSlugs`, `warningText` | +| `werkbaum_set_status` | `source`, `id`, `status` (Code der §4-Tabelle), `base` | neuer Stand (Version, Prüfsumme), Warnungs-Delta | `setStatusBox` (parser.js), Ablage | +| `werkbaum_apply_ops` | `source`, `base`, `ops[]` (`insert`/`replace`/`delete` mit `index`, `count`, `lines` — **dasselbe Schema wie `LineOperation` der API**) | wie oben | `applyOps` (live.js), Ablage | +| `werkbaum_write` | `source`, `base`, `text` (Volltext) | wie oben | `computeOps` (live.js) → Diff → Ablage | +| `werkbaum_add_node` | `source`, `base`, `parent` (ID), `line` (die Knotenzeile ohne Einrückung, z. B. `- [ ] #auth.token: Token prüfen (S)`), optional `after` (ID eines Geschwisters) | wie oben | `addNodeLine` (edit.js) | +| `werkbaum_move_node` | `source`, `base`, `id`, `parent` (neue Eltern-ID), optional `after` | wie oben; der Teilbaum samt Beschreibungs- und Fortsetzungszeilen wandert mit, Einrückung wird angepasst | `moveSubtree` (edit.js) | +| `werkbaum_set_size` | `source`, `base`, `id`, `size` (`XS`…`XXL` oder `null` zum Entfernen) | wie oben | `setSizeToken` (edit.js) | +| `werkbaum_remove_node` | `source`, `base`, `id`, `discard: true\|false` | wie oben — `discard` setzt `[-]` (die Notation für „bewusst nicht“, §4), `false` löscht den Teilbaum samt seinen Blöcken | `setStatusBox` bzw. `removeSubtree` (edit.js) | + +Die **Knoten-Verben** (Nutzer-Entscheidung, §11) sind Bequemlichkeit für +das Modell: `apply_ops` könnte jedes davon ausdrücken, aber ein Agent, der +Zeilenindizes ausrechnen muss, verrechnet sich — ein Verb mit ID ist die +robustere Schnittstelle. Damit dabei **keine zweite Stelle mit +Zeilenformat-Wissen** entsteht, liegen die Text→Text-Regeln als +`frontend/src/edit.js` neben `setStatusBox`/`setFoldMark` (parser.js) und +`appendToken` (taiga.js) — headless, getestet, und später auch für +`#ai.dialog` da (§7.1). Das MCP-Paket verdrahtet sie nur. + +**`base` ist Pflicht bei jedem Schreiben** — `{version, checksum}` vom +letzten Lesen. Ohne `base` wird nicht geschrieben. Das ist die +Idempotenz- und Konfliktregel aus D76, unverändert übernommen. + +**Warnungen tragen Typ und Text.** Der Typ (`sizeConflict`, `unknownDep`, +…) ist für den Agenten das Verlässliche; der englische Text kommt dazu, +weil das Modell ihn ohne Nachschlagen versteht. Die Texte sind die +**Editor-Texte** (`warningText`, D33-Nachtrag) in Englisch — nicht +nacherzählt (§7.1). + +### 5.5 Schreib-Leitplanken + +Auf jedem der drei Schreib-Tools, vor dem Schreiben: + +1. **Keine beschädigte Notation.** Der Ergebnis-Text wird geparst; trägt + er **Struktur-Warnungen**, die der Ausgangstext nicht hatte — + `mixedGate`, `unknownStatus`, `descStray`, `duplicateId` —, wird + **nicht geschrieben**, und die Antwort nennt sie. Das sind die + Warnungen, bei denen der Text als Notation kaputt ist: eine Zeile, die + der Parser anders liest, als sie gemeint war. Schalter + `allowWarnings: true` je Aufruf erlaubt es ausdrücklich. **Inhaltliche + Widersprüche** — `sizeConflict`, `assigneeOverload`, `xorConflict`, + `unknownDep`, `unknownDesc` — werden **geschrieben und gemeldet**: Ein + Agent arbeitet in Zwischenschritten (das Ziel einer Abhängigkeit + entsteht oft erst im nächsten Zug), und im Diagramm sieht ein Mensch sie + als bernsteinfarbene Marke, genau wie bei einer eigenen Änderung + (Nutzer-Entscheidung, §11; die strengere Fassung „jede neue Warnung + blockiert“ war der Vorschlag). Verschwindende Warnungen sind immer + erlaubt, und jede Antwort trägt das vollständige Warnungs-Delta. +2. **Kein `[^]` von einem Agenten.** `in Produktion` ist die Aussage eines + Deploys (D30), nicht die eines Modells. `set_status` lehnt `prod` ab, + `apply_ops`/`write` lehnen ein Ergebnis ab, in dem ein Knoten neu `[^]` + trägt. Schalter `allowProd: true` je Aufruf — mit derselben Begründung: + ausdrücklich, nie still. +3. **Konflikt ist ein Fehler, keine Entscheidung.** Bei `409` (Server) oder + geänderter Datei kommt der **aktuelle** Text mit zurück; der Agent — und + im Zweifel der Mensch hinter ihm — entscheidet. Der Server rebased nichts + selbst über das hinaus, was das Backend ohnehin tut (D76: nicht + überlappende Ops verschiebt der Server; das bleibt). + +Alle drei sind reine Verdrahtung um vorhandene Regeln; der Parser selbst +bleibt fehlertolerant, wie SPEC §4 es verlangt. + +### 5.6 Identität und Sichtbarkeit + +Jeder Schreibvorgang an ein Server-Dokument geht mit `clientId` +`mcp-` (je Serverprozess, sessionStorage-Äquivalent: je Prozess +eine laufende `seq`, D76-Nachtrag 7) und einem `displayName`, der den +**Host nennt**: den Namen, den der Host im MCP-Handshake mitschickt +(`clientInfo.name`, etwa „Claude Code“), mit Rückfall **„Agent“**, wenn er +keinen nennt; `--name` übersteuert beides (Nutzer-Entscheidung, §11). In +jedem offenen Editor steht damit in der Historie „geändert von: Claude +Code“ (D86) — der Mensch sieht, welches Werkzeug es war, und kann es über +die Meilensteine zurückholen. Der Name bleibt eine Behauptung, kein +Nachweis — dieselbe Einordnung wie beim Anzeigenamen eines Menschen (D86). + +### 5.7 Geteiltes Dokument **und** Git — beides zugleich + +Die Frage, an der die Ablage-Wahl hängt: Ein Agent soll auf dem +**geteilten** Dokument arbeiten (dort sitzen die Menschen, dort greift das +Konfliktprotokoll), und derselbe Plan soll **unter Git-Kontrolle** stehen +(Diff, Blame, Review, ein Netz außerhalb des Servers — D89). Das sind zwei +Wahrheiten für einen Text, und die Antwort ist nicht „eine davon“, sondern +eine **Richtung**: Der Server ist die Quelle, Git ist das Archiv. + +**Der Weg dafür existiert schon:** `tools/pull-doc --git-commit` (D88, +`#col.git.pull`) holt ein Server-Dokument in ein Worktree und committet es +datiert, nur bei Änderung, mit Titel und Server-Version in der Nachricht. +Aus dem Cron heraus archiviert sich ein Plan damit selbst. Der MCP-Server +setzt genau darauf auf: + +- **Spiegel-Datei (`--mirror `):** Ist für ein Dokument eine + Spiegel-Datei konfiguriert, ruft der Server nach **jedem erfolgreichen + Agenten-Schreibvorgang** `pull-doc --git-commit` dafür auf. Die + Commit-Nachricht nennt zusätzlich den Urheber („via Agent: Claude Code“) + — die Git-Historie kann Agenten-Änderungen dann so auseinanderhalten, wie + es die Server-Historie über `displayName` tut (D86). Menschliche + Änderungen dazwischen fängt weiterhin der Cron; wer keinen hat, bekommt + sie spätestens mit dem nächsten Agenten-Zug ins Git, denn `pull-doc` + committet den **ganzen** Serverstand, nicht nur die Agenten-Zeilen. +- **Die Spiegel-Datei ist für den Agenten lesbar, aber nicht der + Schreibweg.** Ein Agent in Claude Code sieht die Datei im Repo und könnte + sie direkt editieren — beim nächsten `pull-doc` wäre das überschrieben. + Deshalb: `werkbaum_write`/`apply_ops`/`set_status` auf eine Datei, die + als Spiegel eines Dokuments konfiguriert ist, werden **umgeleitet** an + das Dokument (der Server kennt die Zuordnung) und die Antwort sagt es. + Ein Agent, der die Datei mit seinen eigenen Werkzeugen (Editor, `sed`) + anfasst, ist außerhalb des MCP-Servers — dagegen hilft nur die + D88-Regel, die schon da ist: Eine schmutzige Spiegel-Datei wird beim + nächsten Commit **trotzdem** vom Serverstand überschrieben, und der + Commit macht die Abweichung im Diff sichtbar statt sie zu verstecken. +- **Nicht gebaut wird die Umkehrung** — Git als Quelle und der Server als + Spiegel (`#col.git.pr` für Pläne, die sich wöchentlich ändern, oder + `#col.git.auto`, bei dem das Backend selbst committet). Beides sind + eigene Knoten mit eigenen Fragen (Konfliktmarker mitten in der Notation, + ROADMAP „Gemeinsam an einem Diagramm arbeiten“); der MCP-Server soll sie + weder vorwegnehmen noch ausschließen. Kommt `#col.git.auto`, wird + `--mirror` schlicht überflüssig — die Schnittstelle des Servers ändert + sich dadurch nicht. + +Im Plan steht das als `#ai.mcp.mirror` mit Abhängigkeit auf +`#col.git.pull`. + +### 5.8 Prompts (optional, Phase 6) + +Zwei vorgefertigte Anweisungen, die ein Host dem Nutzer anbietet: + +- `werkbaum/review` — „Prüfe diesen Plan: Warnungen, Größen, fehlende + Zerlegung ab M, unklare Zuständigkeiten“ (nutzt `inspect`, schreibt + nichts). +- `werkbaum/decompose` — „Zerlege Knoten `#id` in Teilpakete mit Größen“ + (endet in `apply_ops`, mit den Leitplanken). + +Beides sind Texte, keine Logik; sie leben im Paket und nicht in `llms.md` +(das bleibt Notation, D43). + +### 5.9 Konfiguration und Start + +``` +node mcp/server.js [--root ]… [--server ] [--name ] + [--mirror =]… +``` + +- `--root`: erlaubte Dateiwurzeln (mehrfach). Ohne Angabe: `cwd`. +- `--server`: Voreinstellung für relative Dokument-Angaben (`` statt + voller URL). Ohne Angabe muss die URL vollständig sein. +- `--name`: `displayName` für Server-Schreibvorgänge. +- `--mirror`: Spiegel-Datei je Dokument (§5.7); die Datei muss in einem + git-Worktree unter einer erlaubten Wurzel liegen — `pull-doc` prüft das + ohnehin. + +Für Claude Code: + +```bash +claude mcp add werkbaum -- node /pfad/zu/werkbaum/mcp/server.js --root . +``` + +Im Repository selbst liegt eine `.mcp.json`, damit Claude Code hier den +Server von selbst hat — der Plan `docs/examples/werkbaum.werkbaum` ist damit +das erste Dokument, an dem der Server benutzt wird (Dogfooding, dieselbe +Logik wie D27). + +## 6. Alternativen + +### A — Server im Kotlin-Backend (Spring AI MCP) + +*Pro:* ein Deployment, Streamable HTTP frei Haus, sitzt direkt an den +Dokumenten. +*Contra:* Jedes nützliche Tool braucht den Parser. Entweder entsteht ein +Kotlin-Parser — **genau die zweite Grammatik, die D14 verbietet** — oder +der Server bietet nur Dokument-CRUD an, und das kann ein Agent per REST +schon heute. Dazu die erste Spring-AI-Abhängigkeit im Backend. +**Verworfen** (`#ai.mcp.kotlin` als `[-]` im Plan). + +### B — Node-Paket, das die Frontend-Module importiert (Vorschlag) + +*Pro:* ein Parser, eine Semantik; die Module sind headless und getestet +(D54-Nachtrag 3 ist die Hausregel dafür); stdio ist der Transport, den alle +lokalen Hosts können; kein Backend-Umbau. +*Contra:* ein zweites Node-Paket im Repo; die Dependency-Frage (§7.4); +Remote-Zugriff erst mit Phase 6. +**Gewählt.** + +### C — Nichts bauen: Agenten lesen `llms.md` und editieren Dateien + +*Pro:* funktioniert heute mit Claude Code. +*Contra:* keine Semantik (der Agent rät Warnungen, Pfad, effektiven +Status), keine Server-Dokumente außer per `curl`, Schreiben an geteilte +Dokumente ohne Konfliktschutz. Das ist der Ausgangszustand aus §2. +**Bleibt als Rückfall bestehen** — der Server ersetzt `llms.md` nicht. + +### D — OpenAPI der REST-API den Agenten geben + +*Pro:* null neuer Code, die Spec existiert. +*Contra:* dieselbe Semantik-Lücke wie C, und die API spricht Volltext-`PUT` +oder Zeilen-Ops mit Prüfsumme — ein Modell, das die Prüfsumme selbst +rechnen soll, ist eine Fehlerquelle mit Ansage. +**Verworfen.** + +### E — `#ai.dialog` zuerst (Modell im Editor) + +*Pro:* der Nutzer bleibt im Werkzeug. +*Contra:* andere Frage (welches Modell, wessen Schlüssel, welche UI); bringt +den Plan nicht zu den Agenten, die Menschen heute schon benutzen. +**Nicht konkurrierend** — B liefert die Module, die E später auch braucht +(JSON-Baum, Leitplanken). + +## 7. Impact auf den bestehenden Code + +Grundsatz: **Das Frontend wird gelesen, nicht umgebaut.** Wo doch etwas zu +ändern ist, ist es eine Verschiebung ohne Verhaltensänderung. + +### 7.1 `frontend/src/` — Änderungen + +| Datei | Was | Warum | +|---|---|---| +| `app.js` → neu `i18n.js` | Das `I18N`-Objekt (ab `app.js:3287`) in ein headless-Modul verschieben; `app.js` importiert es. | Der Server braucht `warningText(w, t)` mit **englischem** `t`. Die Texte leben heute im UI-Modul, das DOM voraussetzt. Eine Kopie im MCP-Paket wäre die Drift, vor der D33-Nachtrag warnt. Reine Verschiebung; der Vite-Bundle bleibt gleich. | +| `warnings.js` | unverändert | importiert nur `esc` aus `render.js`; `render.js` ist headless bis zum Aufruf. | +| `parser.js` | unverändert | `parse`, `setStatusBox`, `STATUS_BY_CODE`, `SIZE_RANK` sind exportiert. | +| `model.js` | unverändert | `effectiveStatus`, `computeCheapPlan`, `assigneeLoads`, `overloadedAssignee`, `taigaSlugs`, `assumedSize` sind exportiert. | +| `live.js` | `checksum()` läuft in Node unverändert (`globalThis.crypto.subtle` gibt es ab Node 20). Prüfen, sonst Rückfall auf `node:crypto` **im MCP-Paket**, nicht in `live.js`. | Die Prüfsumme ist Pflichtfeld des Patches (D76). | +| `taiga.js` | `ticketRefOf`, `collectTicketRefs` nur lesend für `inspect` (`ticketRef`, `taigaSlug` je Knoten); `appendToken` für `set_size` | kein Taiga-Zugriff, nur die Auskunft, was im Text steht. | +| **neu** `edit.js` | Text→Text-Regeln der Knoten-Verben: `addNodeLine(text, parentId, line, afterId)`, `moveSubtree(text, id, parentId, afterId)`, `setSizeToken(text, id, size)`, `removeSubtree(text, id)`. Zeilenweise, zeichengenau, mit Tests wie `setFoldMark`/`expandShortIds`. Kennt Einrückung (§2), Fortsetzungs- und Beschreibungszeilen (§1: die wandern mit ihrem Knoten) und lässt Kommentare stehen. | Die eine Stelle für „Zeile eines Knotens umbauen“; `app.js` benutzt sie zunächst nicht, `#ai.dialog` später schon. Bewusst **nicht** in `parser.js`: Der wird sonst zum Sammelbecken. | + +Was **nicht** ins Frontend zurückfließt: die JSON-Serialisierung des Baums +(`mcp/inspect.js`) — sie ist eine Sicht für Agenten, keine Editor-Logik +(Nutzer-Entscheidung, §11). Sollte `#ai.dialog` sie später brauchen, +wandert sie dann. + +### 7.2 Neues Paket `mcp/` + +``` +mcp/ + package.json name: werkbaum-mcp, type: module, bin: server.js + server.js MCP-Rahmen: Resources, Tools, Prompts registrieren; stdio + stores/file.js lesen, Prüfsumme, atomar schreiben, Wurzel-Prüfung + stores/live.js GET / PATCH gegen /api/v1/documents (D76), clientId/seq + inspect.js Baum → JSON, Warnungen → {type, line, text}, Pfad → Stationen + guard.js Leitplanken (§5.5): Struktur-Warnungen, [^]-Sperre + verbs.js Knoten-Verben → Aufrufe von frontend/src/edit.js, dann Ablage + tests/*.test.js Vitest gegen einen In-Memory-Transport des SDK; Fixtures = SPEC §10 und der mitgelieferte Plan +``` + +Die Regeln in `inspect.js` und `guard.js` sind Text→JSON bzw. Text→Text und +damit headless testbar — die Hausregel aus D54-Nachtrag 3 gilt auch hier; +`server.js` verdrahtet nur. + +### 7.3 Backend + +**Keine Änderung nötig.** Genutzt werden `GET /documents/{id}`, +`PATCH /documents/{id}/content` und `GET /info` — alle vorhanden. Zwei +Dinge sind zu **prüfen**, nicht zu bauen: + +- Der Server sendet `displayName` — steht in der Historie (D86), gemessen + gegen ein lokales Backend. +- `clientId`-Präfix `mcp-`: Das Backend behandelt es wie jeden Client; ein + späterer Filter („nur menschliche Änderungen zeigen“) wäre ein eigener + Wunsch. + +Perspektivisch berührt: `#col.live.owner`. Sobald Verwaltungs-Aktionen an +ein Owner-Passwort gebunden sind, braucht der MCP-Server einen Weg, es zu +übergeben — **nie** als Tool-Parameter (Prozessliste, Transkript), sondern +als Umgebungsvariable des Serverprozesses. Das ist heute keine Arbeit, nur +eine Vormerkung. + +### 7.4 Abhängigkeit: `@modelcontextprotocol/sdk` + +CLAUDE.md: keine neuen Laufzeit-Abhängigkeiten ohne Rückfrage. Das ist eine. + +- **Für:** Das offizielle SDK trägt Protokollrevision, Capability-Handshake, + Schema-Validierung und beide Transporte; eine Handschrift des JSON-RPC + wäre ~200 Zeilen, die bei jeder Revision nachgezogen werden müssten. +- **Dagegen:** Es ist die erste Laufzeit-Abhängigkeit im Repo überhaupt. +- **Einordnung:** Sie liegt im **MCP-Paket**, nicht im Frontend — der + gebündelte Editor bleibt abhängigkeitsfrei (D11/D19/D20). Dieselbe + Grenze, die D76 für Spring Security gezogen hat: die Abhängigkeit dort, + wo sie den Kern nicht berührt. + +**Entschieden (Nutzer, §11): SDK** — als bewusste Ausnahme in D93 +festgehalten. Version wird beim Bauen gepinnt (`package-lock.json` +eingecheckt, wie im Frontend). + +### 7.5 Übriges + +| Ort | Änderung | +|---|---| +| `.mcp.json` (Repo-Wurzel) | Server-Eintrag für Claude Code (Dogfooding) | +| `README.md` / `README.de.md` | Abschnitt „Für KI-Agenten: der MCP-Server“ — Installation, die drei Quellen, die Leitplanken | +| `docs/CHANGELOG.md` | je Phase eine Zeile | +| `.github/workflows/*` | `npm --prefix mcp test` neben dem Frontend-Test; kein Deploy (lokales Werkzeug) | +| `tools/pull-doc` | **unverändert im Verhalten**; ein neuer Schalter `--author ` für den Urheber in der Commit-Nachricht (§5.7) — der Schalter kommt ins Skript, nicht in den Aufrufer (D77-Nachtrag) | +| `scripts/deploy-*.sh`, `tools/remote` | **unverändert** — nichts davon läuft auf dem Server | +| `frontend/public/llms.md` | **unverändert** (Notation, D43); ein Verweis auf den Server gehört in `llms.txt` (Wegweiser, D43-Nachtrag 2) | + +## 8. Sicherheit + +- **Plan-Text ist Fremddaten.** Beschreibungen (`---`-Teil) können + Anweisungen enthalten („ignoriere die Leitplanken“). Der Server führt + nichts aus, was im Text steht; Resources sind als Inhalt, nie als + Anweisung deklariert. Der Host trägt die Prompt-Injection-Frage — der + Server macht sie nur nicht schlimmer: keine Shell, kein Netz außer den + zwei konfigurierten Zielen (Dateiwurzeln, Backend). +- **Kein Geheimnis im Transkript.** Master-Passwort (D76-Nachtrag 6) geht + **nie** über MCP — `GET /documents` (die Liste) wird deshalb nicht + angeboten; der Agent bekommt Dokument-URLs vom Menschen. Ein späteres + Owner-Passwort kommt als Umgebungsvariable (§7.3). Taiga-Token ebenso + (§9). +- **Dateizugriff nur unter erlaubten Wurzeln**; Pfade werden aufgelöst + (`realpath`) und gegen die Wurzeln geprüft — Symlinks nach draußen + zählen als draußen. +- **Schreiben nur mit `base`**; kein Volltext-`PUT`. Was der Editor an + Netzen hat (Konflikt-Band, Rettungs-Sicherung, D89), hat der Agent in + Form des zurückgelieferten aktuellen Textes — er verliert nichts, er + muss neu ansetzen. + +## 9. Abgrenzung — was ausdrücklich nicht gebaut wird + +| Nicht gebaut | Warum | Wo es hingehört | +|---|---|---| +| Modellaufrufe, API-Schlüssel, Provider-Wahl | Der Host hat das Modell; ein Server mit eigenem Schlüssel wäre `#ai.key` unter falschem Namen | `#ai.key`, `#ai.dialog` | +| Taiga-Tools (Ticket anlegen, Status schreiben) | Braucht das Taiga-Token — das lebt im Browser (D91) und dürfte nicht durch ein Transkript; außerdem eine eigene Entscheidung, ob ein Modell Tickets anlegen darf | eigener Nachtrag, wenn gewünscht: über den vorhandenen Proxy, Token aus der Umgebung | +| Dokumentenliste (`GET /documents`) | Master-Passwort | — (der Mensch nennt die URL) | +| Anlegen/Löschen/Umbenennen von Server-Dokumenten | Verwaltung; wartet auf `#col.live.owner` | nach dem Owner-Passwort | +| Falten (`fold`/`unfold`) als Verb | Faltmarken sind Darstellung für Menschen (§9); ein Agent liest den ganzen Text ohnehin | — | +| Änderungsfeed / Long Polling | Ein Agent arbeitet in Zügen, nicht live; `read` vor jedem Schreiben genügt | — | +| Git als **Quelle** (Server folgt dem Repo) | Umkehrung von §5.7; Konfliktmarker mitten in der Notation, eigene Fragen | `#col.git.pr`, `#col.git.auto` | +| `?sourceUrl=`-Quellen | nur lesend; der Agent kann die URL selbst holen | Nachtrag bei Bedarf | +| Streamable HTTP | Phase 6, hängt an der Authentifizierungsfrage | `#ai.mcp.http` | +| Ein Kotlin-Server | D14 | `#ai.mcp.kotlin` (`[-]`) | + +## 10. Umsetzungsreihenfolge + +Jede Phase ist für sich abgeschlossen und bekommt ihre CHANGELOG-Zeile; +Plan-Knoten gehen beim Mergen auf `[x]`. + +1. **Lesen** (`#ai.mcp.node`, `#ai.mcp.read`): Paket, stdio, Resources + für Guide und Datei, `werkbaum_read`. Nachweis: Claude Code liest den + mitgelieferten Plan über die `.mcp.json`. Vorher: SDK-Entscheidung + (§7.4). +2. **Befragen** (`#ai.mcp.inspect`): `i18n.js`-Verschiebung im Frontend, + `werkbaum_inspect` mit Baum, Warnungen, Pfad. Nachweis: Für den + mitgelieferten Plan liefert das Tool dieselbe Stationszahl und dieselben + Warnungen wie der Editor (Vergleich gegen die Zahlen, die die + DECISIONS-Einträge ohnehin nennen). +3. **Schreiben** (`#ai.mcp.write`, `#ai.mcp.guard`): Server-Ablage mit + `PATCH /content`, Datei-Ablage atomar, die drei Basis-Schreib-Tools, die + Leitplanken. Nachweis gegen ein lokales Backend: Agenten-Änderung + erscheint im offenen Editor mit „Claude Code“ in der Historie; ein + Konflikt (Mensch tippt dieselbe Zeile) kommt als Fehler mit aktuellem + Text zurück, nichts wird überschrieben; ein `[^]` wird abgelehnt; ein + `mixedGate` wird abgelehnt, ein `sizeConflict` geschrieben und gemeldet. +4. **Knoten-Verben** (`#ai.mcp.verbs`): `frontend/src/edit.js` mit Tests + (Gegenprobe per Mutation wie bei `setFoldMark`), dann die vier Verben + im Paket. Nachweis: Ein `move_node` nimmt Beschreibungsblock und + Fortsetzungszeilen mit und lässt den Rest des Texts zeichengenau stehen + (Vergleich der übrigen Zeilen vorher/nachher). +5. **Spiegel ins Git** (`#ai.mcp.mirror`): `--mirror`, Aufruf von + `pull-doc --git-commit` nach jedem Agenten-Schreibvorgang, Umleitung + von Schreibzugriffen auf die Spiegel-Datei. Nachweis in einem + Wegwerf-Worktree: ein Agenten-Zug ergibt genau einen Commit mit + Serverstand und Urheber; ein unveränderter Zug keinen; eine von Hand + verschmutzte Spiegel-Datei wird vom nächsten Commit überschrieben und + die Abweichung steht im Diff. +6. **Prompts und HTTP** (`#ai.mcp.http`, optional): die zwei Prompts; + Streamable HTTP erst nach `#col.live.owner`. + +## 11. Entscheidungen (Multiple-Choice-Runde, 2026-09-02) + +| Frage | Entschieden | Anmerkung | +|---|---|---| +| SDK-Abhängigkeit `@modelcontextprotocol/sdk` (§7.4) | **Ja, SDK** | erste Laufzeit-Abhängigkeit, isoliert im MCP-Paket; D93 | +| Strenge der Warnungs-Leitplanke (§5.5) | **Nur Struktur-Warnungen blockieren** | `mixedGate`, `unknownStatus`, `descStray`, `duplicateId`; alles Inhaltliche wird geschrieben und gemeldet. Vorgeschlagen war die strenge Fassung — der Nutzer hat die Zwischenschritte eines Agenten höher gewichtet | +| `displayName` (§5.6) | **Host-Name aus dem Handshake** | Rückfall „Agent“, `--name` übersteuert | +| Geteiltes Dokument und Git (§5.7) | **Server committet je Agenten-Zug** | über `pull-doc --git-commit`; Cron für menschliche Änderungen dazwischen | +| Ort der Baum-Serialisierung (§7.1) | **Im MCP-Paket** | wandert, wenn `#ai.dialog` sie braucht | +| Schreib-Tools (§5.4) | **Zusätzlich Knoten-Verben** | `add_node`, `move_node`, `set_size`, `remove_node`; Regeln in `frontend/src/edit.js`, nicht im Paket | +| Verteilung | **Nur aus dem Repo** | `.mcp.json`; npm erst auf Nachfrage von außen | + +**Weiterhin offen** (stellt sich erst beim Bauen oder danach): + +1. **Streamable HTTP** — wartet auf `#col.live.owner`; bis dahin stdio. +2. **`--author`-Schalter in `pull-doc`** — Form der Urheber-Angabe in der + Commit-Nachricht (Trailer `Co-Authored-By:` oder Freitext im Betreff); + entscheidet sich beim Bauen von Phase 5. +3. **Prompts** (§5.8) — ob zwei genügen und wie sie heißen; Phase 6.