Every Agents view marks each agent as working, alive, sleeping, suspending, unreachable or dead with an animated symbol; a Status menu hides states and switches the 3D faces, kept through a reload. The hub's container sees neither ~/.claude/sessions nor host processes, so the host timer kvb-orchestrator-sessions.timer runs client/sessions.py every 15 seconds while the page polls: it reads the session records without following symlinks, only regular files up to 64 KiB, keeps name, status and statusUpdatedAt within type and length bounds, checks the pid's process start, and writes agent-sessions.json atomically. The hub ignores a snapshot that is missing, malformed, older than five minutes or dated in the future. make orchestrator-install enables the timer and orchestrator-check reports it.
🎯 Fix: 90 %
💥 Break: 5 %
💸 Cost: 100 %
⏱️ Time: 100 %
🛡️ Security: 100 %
🏆 Score: 86
🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 %
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The header radio button opens the radio spot above the main area of the current tab. The Send button, the toolbar radio button and the Radio tab are gone, the mayday clears inside the spot without a Cancel mayday label, and the radio station probe waits for a visible row.
🎯 Fix: 92 %
💥 Break: 4 %
💸 Cost: 100 %
⏱️ Time: 100 %
🛡️ Security: 100 %
🏆 Score: 88
🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 %
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Requirement 001 decisions 52 to 58 (operator 2026-11-09):
- Radio spot: the Agents toolbar radio button expands inline with the one
composer (every channel, post and call recipients, Record, Send), a gear
with the radio settings (tones, squelch, read aloud, moved out of the
general settings) and Cancel mayday, which leaves the toolbar; the Radio
tab keeps speakers, stations and the log plus a jump to the spot.
- Day/Night menu: the badge and Drain, Suspend and Resume only; each
explanation is the button's tooltip.
- Tasks toolbar: views, filter, estimation, sort and business value in one
wrapping row with a Request choices dropdown; the status chips stay the
second row.
- Burndown and burnup: a trend selector (off, linear regression, velocity
over N days) stored in the hub settings, the trend lines and the forecast
date on the chart, and a tooltip per point with the work packages that
started, ended or joined there.
- ETA: every list row shows its ETA (end when done, else start or now plus
the forecast length behind its predecessors), sharing one predecessor
walk with the Gantt.
- Tasks 3D: a sixth view on the 3D engine with the dependency edges in the
Gantt colours, layouts Force and Time.
- Steady 3D camera: the view fits once per graph build, refreshes keep the
operator's camera.
- e2e: Firefox runs with its profile as cwd, so its crashreporter no longer
drops core dumps into the repository.
- A forecast beyond the last second a Date can hold is no forecast, so a
nearly flat regression no longer aborts the Tasks render.
Evidence: make test Ran 717 OK, ruff clean, markdownlint 0 errors; e2e 30 of
30 OK in Chromium and Firefox at 1920, 1366 and 390 px; MEDUSA 0 findings
after one skeptic-accepted lexical EXA006.
🎯 Fix: 93 %
💥 Break: 4 %
💸 Cost: 100 %
⏱️ Time: –
🛡️ Security: 100 %
🏆 Score: 89
🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 %
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Requirement 001 phase 6, S2:
- Agent popup: a click on an agent opens one fading <dialog> with face,
name, earlier names, offices, tasks, claims, subagents, history and
the composer; Escape or a click outside closes it. The agent drawer
and the Details side panel are gone.
- Node popup: a click on a node in a graph view enlarges it and marks it
red, and an SVG leader line ties it to the translucent popup; a click
elsewhere restores the node. popup.js places the popup right, left,
below or above the node, caps its height to the room there and
returns the line.
- Search: in the 3D views a search field with suggestions replaces the
list of every node, one chip per distinct label.
- Fit: body.fit now applies at every width; without the side panel the
orbit view otherwise grew a page scrollbar at 390 px.
- Two page modules had silently shadowed each other's functions of the
same name while this was built; test_no_two_page_modules_declare_the_same_function
now guards that. Artifact ids carry NUL, which CSS.escape turns into
U+FFFD, so the node lookup compares dataset values.
- Composer: a message goes to the agent whose popup it was written in.
deliver() read the global ui.agent after awaiting the upload, so
closing the popup or opening another agent during an upload sent the
signed message to null or to the other agent (found by the security
skeptic, present before, easier now that a backdrop click closes).
Limits: the 3D leader line is placed when the popup opens and does not
follow the camera while the layout settles; the search keeps the first
node per label, so a second repository's main branch is found in the
graph, not through the search.
Evidence: make test 667 OK, ruff and markdownlint clean
(/tmp/s2-make-test-1.log); e2e 19 OK in Chromium and Firefox at 1920,
1366 and 390 px, none skipped, rerun after the composer fix
(/tmp/s2-e2e-4.log); screenshots in /tmp/orchestrator-phase4-shots/;
MEDUSA 22 files, 6 findings (a "PLA" pattern in "templates", the UI
names openAgent and drawAgent) accepted after an independent skeptic
that also found no XSS or selector injection in the popup code.
🎯 Fix: 93 %
💥 Break: 4 %
💸 Cost: 100 %
⏱️ Time: –
🛡️ Security: 100 %
🏆 Score: 89
🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 %
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Requirement 001 phase 6, S0:
- Speech: the security class shows as "Sécurité" and is spoken as in
maritime radio, "say-cure-ee-tay" three times. A hex run of 7 or more
characters with a letter and a digit (commit, session, message ids) is
spelled in the NATO alphabet; every other digit is spoken on its own
in ICAO pronunciation (42305: four two tree zero fife). The spelling
runs inside clip() before the length cut, so a phrase still fits
SPEECH_LIMIT; the displayed text keeps its digits and hashes.
- English: every orchestrator label, tooltip, message, error, script
output, document and test string is English (Regeln -> Firewall,
Hierarchie -> Hierarchy, Steuerung -> Controls, Ausführen -> Run, ...);
the page declares lang="en" and formats dates as en-GB. Task filter
ids are English. German stays only in the skill trigger phrases that
quote the operator, and as identifiers: the view keys (view=) and the
leitstand id.
- tests/test_english.py scans every tracked text file for umlauts and
German words, with an allowlist of the quoted trigger phrases.
BREAKING CHANGE: the Stream search tokens art: and seit: are now kind:
and since:; an old art: or seit: token counts as a plain word.
Evidence: make test 657 OK, ruff and markdownlint clean
(/tmp/s0-make-test-1.log); e2e 17 OK, none skipped (/tmp/s0-e2e-1.log);
MEDUSA 86 files, 24 findings on reworded strings accepted after an
independent skeptic (21 path:line, 0 rejected, no behaviour change in
signing, approving, rules, denying, offices, events), rescan 0 open.
🎯 Fix: 93 %
💥 Break: 4 %
💸 Cost: 100 %
⏱️ Time: –
🛡️ Security: 100 %
🏆 Score: 89
🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 %
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Agents views gain a Hierarchie view: an org chart of the chair and
the line offices read from the council claims. The operator appoints,
hands over and recalls an office there; the page signs each change with
the passkey and a host unit (client/offices.py, offices path unit)
verifies the signature, removes a live holder itself and runs a plain
council.py claim for the successor. council.py loses the --operator
flag, so no agent can override a live holder.
The agent order is now separate from task priority: rasci.py agents
order stores it in agent-order.json beside the register through the
nofollow helpers and never writes a --prio pin. It only breaks ties of
equal task rank, also among the queue grants. The Hierarchie view edits
it as a drag list.
Host units run the installed skill scripts, so orchestrator.sh keeps the
offices unit off while the installed council.py, nofollow.py or rasci.py
differ from the tree. Job files, council files and hub records are read
with O_NOFOLLOW and O_NONBLOCK and size caps; nofollow.rewrite replaces
a claim without creating directories, so a beat never revives a released
office.
🎯 Fix: 92 %
💥 Break: 4 %
💸 Cost: 100 %
⏱️ Time: 79 %
🛡️ Security: 100 %
🏆 Score: 100
🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 %
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phase 4 of requirement 001. Agents and Artifacts each offer Orbit, Chord, Swimlane, Tree and 3D: the spawn tree (page-spawn.js) and the artifacts orbit (page-artifacts.js, kvb_orchestrator/artifacts.py) replace the "folgt" placeholders, 3D runs on the vendored 3d-force-graph and three.js (MIT, LICENSE files kept, served from the image under the unchanged CSP), and a Bootstrap Icons sprite (icons.py, MIT) replaces the emoji glyphs, also in the meditation page.
Signed branch deletes: the Tree view offers a delete only for merged-clean branches without a gc skip reason; the operator signs the exact item with the passkey, the hub writes a job without any command (kvb_orchestrator/cleanup.py), and the host path unit runs client/cleanup.py, which verifies the signature, dry-runs pkgmgr branch cleanup for that exact branch, refuses patterns, option names, changed tips, other worktrees and plans naming other branches, deletes, and rewrites the branch tree. pkgmgr runs with core.hooksPath=/dev/null, core.fsmonitor=false and the config hook events disabled through GIT_CONFIG_COUNT, because the cwd is a repository agents can write and pkgmgr releases before 4c8b137 delete without scan mode (test with a positive control that both hook kinds fire without it).
3D labels go into the tooltip as a text node: the vendored tooltip renders a string label as HTML.
Tests: 503 OK, Chromium (CDP) and Firefox (BiDi) walks over every screen at three widths.
MEDUSA acceptances (kvb-think-criticize skeptic 2026-11-07): WEB-FLASK-004 view.py:135 (file template, autoescape on, state via tojson), MEDUSA-MM-SCAN-058 server.py:69/:85 (substring pla in --templates and Places), RH005 client/cleanup.py:199 (raise SystemExit(main())), B704 icons.py:45 (sprite baked into the image, names checked against it), EXA002 page-artifacts.js:221 (openAgent only opens the drawer), STG002 page-constants.js:64 (U+2212 in a static label), PL002 page-graph3d.js:44 (CSS class space-tools; the real tooltip sink fixed), B603 client/cleanup.py:75 (argv without shell; hook hole closed).
🎯 Fix: 92 %
💥 Break: 5 %
💸 Cost: 100 %
⏱️ Time: –
🛡️ Security: 100 %
🏆 Score: 87
🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 %
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Surface (requirement 001 phase 2): navigation Stream (Inbox, Regeln) / Agents / Artifacts with keys 1-3 and hash routes (#graph and #tree redirect), header with title, command palette and settings only, server-side badges (unsnoozed inbox, beats within 900 s, open jobs), a Mayday banner with "aufheben", four stream chips with agent:/art:/seit: search, Filter and time menus, the inbox in main, an agents toolbar (Funk an alle with Newsletter, Broadcast, Pan-Pan, Security, Mayday; Priorität; Tag/Nacht), Post or Call in the agent panel, Ambiente in the settings and read-aloud over the seven classes with Mayday locked.
Rename (decision 9): hub/ is orchestrator/, the package kvb_orchestrator, the unit kvb-orchestrator-runner.service, scripts/orchestrator.sh, environment KVB_ORCHESTRATOR_*, make targets orchestrator-*, the MCP server, image and compose project kvb-orchestrator, the guard header X-Kvb-Orchestrator and the message marker [kvb-orchestrator msg <id>]. install runs migrate first: it stops the old container, removes its image and code, moves state, approvals and pinned keys, swaps the MCP registration, the PermissionRequest hook and the runner unit, and changes nothing on a second run (scratch-HOME test with stub docker, claude and systemctl). Saved views fall back to the old localStorage key once.
MEDUSA acceptances carried to the renamed paths: 82 rows whose lines are unchanged (reason prefixed "renamed from <old path>, line unchanged"), and 7 rows whose text changed only in the product name, the package name, a temp prefix or a new class argument, each upheld by one kvb-think-criticize skeptic (approval.py:60, messaging.py:53, server.py:56, tests/hub_support.py:64, passkey.py:205, page-agent.js:75, language.py:46).
Cost 101 %: the longer name adds 15 tokens of skill text; the operator approved it with the commit.
🎯 Fix: 92 %
💥 Break: 4 %
💸 Cost: 101 %
⏱️ Time: –
🛡️ Security: 100 %
💰 Value: ?
🏆 Score: 87
🚦 Gate: ⚠️ cost 101 % > 100: ask the operator before the commit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>