From 50315a8bdb770c9c2c89f8a7b7ebeabf237719b5 Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Fri, 6 Nov 2026 17:15:59 +0000 Subject: [PATCH] docs(requirements): add 001 Agent Orchestrator and 002 Cosmos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 001 fixes the radio and post model, the orchestrator surface and rename, the pkgmgr branch tree with gc states and delete-by-click, the Agents and Artifacts views with 3D, Bootstrap Icons and kvb-org-update. 002 plans the cosmos extraction as an Infinito.Nexus custom role after 001. 🎯 Fix: 97 % 💥 Break: 1 % 💸 Cost: – ⏱️ Time: – 🛡️ Security: 100 % 🏆 Score: 96 🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 % Co-Authored-By: Claude Opus 5.5 --- docs/requirements/001-agent-orchestrator.md | 397 ++++++++++++++++++++ docs/requirements/002-cosmos.md | 143 +++++++ docs/requirements/README.md | 8 + 3 files changed, 548 insertions(+) create mode 100644 docs/requirements/001-agent-orchestrator.md create mode 100644 docs/requirements/002-cosmos.md create mode 100644 docs/requirements/README.md diff --git a/docs/requirements/001-agent-orchestrator.md b/docs/requirements/001-agent-orchestrator.md new file mode 100644 index 0000000..02b3f20 --- /dev/null +++ b/docs/requirements/001-agent-orchestrator.md @@ -0,0 +1,397 @@ +# 001 - Agent Orchestrator + +## User Story + +As the operator of many parallel agents, I want one simple Agent Orchestrator +surface and a radio that only interrupts for urgent calls, so that agents +spend few tokens on talk, urgent news reaches them at once, and I can drill +from three views down to any agent, branch or artefact. + +## Decisions (operator-confirmed 2026-11-06; do not re-litigate) + +1. **One document**: radio model, surface, pkgmgr branch tree and views live in + this one requirement as phases. Rejected: one document per feature (the + operator wants the whole picture in one place). +2. **Location**: `docs/requirements/NNN-slug.md`, numbered per repository. + Rejected: a file next to the code (no index, no numbering). +3. **Radio classes**: `post`, `call`, `newsletter`, `broadcast`, `mayday`, + `pan-pan`, `security`. Rejected: `broadcast` only as the umbrella of the + three alarms (the operator wants an immediate call to all without alarm). +4. **Mailbox**: `post` (one agent) and `newsletter` (all agents) are + delivered only when the agent ends its turn and goes idle, batched; an + agent already idle is not woken and sees its mailbox at the end of its next + turn. Rejected: next prompt, next tool step (interrupts work), batched + wake-ups (one turn per wake). +5. **Immediate classes**: `call`, `broadcast`, `pan-pan`, `mayday` and + `security` reach the agent at its next tool step and wake an idle agent. +6. **Call receipt**: the caller gets a delivered/read receipt and does not + wait; an answer is a call of its own. Rejected: the caller blocks until + the answer (costs the caller), delivery without feedback. +7. **Mayday pause**: while a mayday holds, a PreToolUse hook blocks every + writing action until `radio.py clear`; reading, the radio and teardown + stay allowed. The sender and every agent that joins with `radio.py + assist` to help keep working. Rejected: an instruction only (not + enforced), heavy jobs only (today's behaviour, too weak), a full blockade + that also stops the helpers. +8. **Radio and post**: two channels. `radio.py send` is the radio and always + immediate (`call`, `broadcast`, `pan-pan`, `mayday`, `security`); + `radio.py post` is mail and always delayed (`post` with `--to`, + `newsletter` without). `send direct` stays as an alias so running peers + keep working: with `--wake` it becomes `call`, without it `post`. Rows + stored before the change carry no version mark and are read as before: + `direct` as `post`, `broadcast` as `newsletter`. Rejected: `send + broadcast` as an alias of `newsletter` (makes the immediate broadcast + unreachable). +9. **Name**: kvb-hub is renamed in full, with a one-time migration: visible + "Agent Orchestrator", technical `kvb-orchestrator` / `kvb_orchestrator` + (directory, module, container, systemd unit, MCP server, environment + `KVB_ORCHESTRATOR_*`, make targets). Rejected: visible name only (two names + for one thing). +10. **Navigation**: Stream (sub-items Inbox and Regeln) · Agents (ex Graph) · + Artifacts (ex Tree). Agents and Artifacts each offer Orbit, Chord, + Swimlane, Tree and 3D. +11. **Header**: title · ⌘K · ⚙ only. The status pills become navigation + badges (Inbox: waiting items, Agents: active agents, Artifacts: runner + jobs); Mayday shows only as a red banner with "aufheben" while active; the + background shows day and night. Rejected: one status dot with a popover + (an extra click), a status block in a side bar, a "Lage" screen (effort), + no header at all. +12. **Tools**: Steuerung (Funk an alle, Mayday aufheben, Priorität, Tag/Nacht) + moves to the Agents toolbar, Regeln under Inbox, Himmel, Musik, + Leitstand and Benachrichtigungen to ⚙ "Ambiente"; ⌘K reaches every one. + Rejected: one ⋯ menu (hides instead of ordering). +13. **Stream**: four category chips Für dich · Funk · Arbeit · Transkripte; + one search line with `agent:`, `art:`, `seit:`; sub-filters, saved views + and a custom range under "Filter ▾"; the time bar becomes "24 h ▾" with + the replay inside; transcripts are off by default. Rejected: a + self-grouping stream, a Kibana-like query language (effort), preset + chips only. +14. **3D**: `3d-force-graph` 1.80.1 on `three` 0.186.1, vendored as in + meta.infinito.nexus; the Canvas depth axes Zeit and Spawn-Tiefe become 3D + options. Rejected: keeping the Orbit-only Canvas depth. +15. **Artifacts scope**: git (repositories → branches → worktrees with their + agents and reviews) plus the kvb-org-rasci register artefacts (images, + volumes, logs) as leaves of the task or worktree that owns them. + Rejected: git only. +16. **Artifacts views**: Orbit: repository sun, branch planets (size = commits + ahead), worktree moons, agent satellites. Chord: branch overlap (same + files touched, merges) as conflict risk. Swimlane: one lane per branch + with commits, reviews, gates and pushes. Tree: the pkgmgr branch tree. +17. **Tree data**: the scan moves from `hub/kvb_hub/tree.py` into pkgmgr as + `pkgmgr branch tree --format json|yaml --output FILE`, rewritten by a + systemd user timer every minute and after every pkgmgr branch action; the + orchestrator only reads the file, no git runs in its container. Rejected: + the hub keeps scanning (pkgmgr is not the single source, git runs in the + container), a live websocket daemon (effort). Hardened through + kvb-think-dialectic before it is built. +18. **Order**: 1 radio → 2 surface and rename → 3 pkgmgr branch tree → 4 views + and 3D; one bundle per phase, each change set through kvb-code-refactor. +19. **Icons over text**: every HTML surface a skill renders (the + orchestrator, the review pages, the meditation page) shows Bootstrap + Icons instead of text labels wherever an icon carries the meaning, each + with a tooltip and an `aria-label`; terminal output and `SKILL.md` keep + emoji. Rejected: Font Awesome Free (icons under CC BY 4.0, core loads it + from a kit CDN), emoji in HTML (look differs per platform). +20. **Branch state**: `pkgmgr branch tree` covers every repository pkgmgr + manages and gives each branch and worktree the classification of + `pkgmgr branch gc` (one implementation, no second copy): merged and by + what, clean or uncommitted changes, unpushed commits, gone upstream, + locked, stale, protected and the gc skip reason. The Artifacts Tree shows + it as icons. Phase 3 builds the data, phase 4 the icons. +21. **Delete from the tree**: merged, orphaned branches are deleted by click + in the Artifacts Tree (phase 4), per item and as "Alle gemergten + löschen": + - **Credentials**: only while KeePassXC is unlocked; it hands pkgmgr the + GitHub token through the Secret Service and the SSH key through its SSH + agent, and no secret passes the orchestrator container. Rejected: the + master password typed into the dialog (secret crosses container and + browser), a token-only, local-only delete. + - **Scope**: exactly what `pkgmgr branch gc --apply` deletes for a + `merged-clean` item (worktree, local and remote branch, compose stack, + images); a gc skip reason locks the button. Rejected: local only. + - **Confirmation**: the click shows the gc dry-run lines of the chosen + items, and "Löschen" needs the operator signature (`/api/sign`). + Rejected: a second click without signature, one click without preview. + - **Execution**: the orchestrator writes a signed job into a host + directory; a systemd user path unit runs `pkgmgr branch gc --apply` for + exactly those items and writes the result back. Rejected: an + `operator.py` row (not direct). +22. **Organisation update**: a new skill `kvb-org-update` tells every agent + and client which skills changed and how to use them, as one + `newsletter` per update; phase 1 announces the radio change through it. + +## Approach + +```mermaid +flowchart TD + subgraph P["🧭 0 · Preparation"] + P1["📋 Write requirement"] --> P2{"✅ Operator approves?"} + P2 -- "✏️ corrections" --> P1 + end + P2 -- "🤖 yes" --> R1 + subgraph R["📻 1 · Radio model"] + R1["🔴 Red tests: classes, mailbox, receipt, mayday block"] --> R2["🛠️ radio.py, Stop mailbox hook, PreToolUse mayday hook, SKILL.md"] + R2 --> R3{"🧪 Tests and make test green?"} + R3 -- "🔴 no: fix" --> R2 + R3 -- "🟢 yes" --> R4["🧹 kvb-code-refactor"] + R4 --> RF{"💬 Operator feedback?"} + RF -- "✏️ changes" --> R2 + end + RF -- "👍 commit word" --> S0 + subgraph S["🧭 2 · Surface and rename"] + S0["🔀 Rebase feature/kvb-hub onto origin/master"] --> S1["🔴 Red tests: nav, header, badges, stream, migration"] + S1 --> S2["🛠️ Nav, header, badges, banner, stream, inbox, tools, rename + migration"] + S2 --> S3{"🧪 Tests green?"} + S3 -- "🔴 no: fix" --> S2 + S3 -- "🟢 yes" --> S4["📸 Screenshots 1920 / 1366 / 390 px"] + S4 --> SF{"💬 Operator feedback?"} + SF -- "✏️ changes" --> S2 + end + SF -- "👍 commit word" --> T0 + subgraph T["🌳 3 · pkgmgr branch tree"] + T0["⚖️ kvb-think-dialectic on the data path"] --> T1["🔴 Red tests on fixture repositories"] + T1 --> T2["🛠️ pkgmgr branch tree with gc states, timer, orchestrator reads the file"] + T2 --> T3{"🧪 Tests green, no git in the container?"} + T3 -- "🔴 no: fix" --> T2 + T3 -- "🟢 yes" --> TF{"💬 Operator feedback?"} + TF -- "✏️ changes" --> T2 + end + TF -- "👍 commit word" --> V1 + subgraph V["🪐 4 · Agents and Artifacts views"] + V1["🔴 Red tests: five views per tab, artefact leaves, delete job"] --> V2["🛠️ Orbit, Chord, Swimlane, Tree with state icons and delete, 3D (3d-force-graph), host gc unit"] + V2 --> V3{"🧪 Tests green?"} + V3 -- "🔴 no: fix" --> V2 + V3 -- "🟢 yes" --> V4["📸 Screenshots of every view"] + V4 --> VF{"💬 Operator feedback?"} + VF -- "✏️ changes" --> V2 + end + VF -- "👍 fits" --> D1["🏁 Full gate, commit with operator OK, push hand-over"] +``` + +## Acceptance Criteria + +### Radio model + +- [ ] `radio.py send` accepts exactly `call`, `broadcast`, `pan-pan`, + `mayday`, `security` and the alias `direct`; `post`, `newsletter` and + any other class exit 2. +- [ ] `radio.py post --to X` stores `post`; `radio.py post` without `--to` + stores `newsletter`. +- [ ] `call` and `send direct` require `--to`; `broadcast`, `pan-pan`, + `mayday` and `security` exit 2 with `--to`. +- [ ] `send direct --wake` is stored as `call`, `send direct` as `post`. +- [ ] New rows carry a version mark; rows without it are read as before: + `direct` as `post` (as `call` when it woke), `broadcast` as + `newsletter`. +- [ ] The UserPromptSubmit hook (`radio.py hook`) and the PostToolBatch hook + (`radio.py tool`) never print a `post` or `newsletter` row. +- [ ] A new Stop hook `radio.py mailbox`, registered in + `scripts/enable-plugins.js`, prints the unseen `post` and `newsletter` + rows of the session at most 10 at a time with a "N more" line, marks + them seen and exits 2; with nothing unseen it exits 0 and prints + nothing. +- [ ] `radio.py listen` wakes an idle session only for `call`, `broadcast`, + `pan-pan`, `mayday` and `security`, never for `post` or `newsletter`. +- [ ] `radio.py tool` delivers `call` (to its addressee), `broadcast`, + `pan-pan`, `mayday` and `security` at the next tool step. +- [ ] When a call reaches the callee's context, a receipt row (callee, call + time, read time) is stored; the caller's mailbox shows + "CALL read