dwarves-gui — the tabbed shell
The dwarves UI is a tabbed egui/wasm app (dwarves-gui/src/tabbed.rs TabbedView, itself a Facet) hosting one Box<dyn Panel> per tab. It began as the three panes Rickard first asked for — Forge · Funnel · Claude — and has since grown into the full forge cockpit. The native shell (dwarves-gui/src/main.rs::build_native_app) ships 17 tabs:
| # | Tab | Pane / source | Data path |
| 1 | Warehouse | nornir-warehouse-nav |
the landing view — constellation→repo→crate depgraph navigator (shared nornir-depgraph model on facett-graphpan; nordisk fixture) |
| 2 | Forge | dwarves-embed::panel |
live thin gRPC → running dwarves-server run-history + selected-run DAG; auto-polls (honest connected/idle/offline states) |
| 3 | Pipeline | pipeline::pipeline_view |
the build-pipeline DAG on the reused facett-pipeline viewer (dwarves' ForgePipelineAdapter) |
| 4 | CI/CD | dwarves-embed::cicd_wizard_panel |
the human-mode quick-setup wizard — BUILD·TEST·DEPLOY·TRIGGER → a typed dwarves_runa::Pipeline + live stage DAG (same generator/runner as the dwarves pipeline CLI) |
| 5 | Builds | dwarves-embed::holger_build_panel |
holger's 3 deployment tiers (embedded·mini·full) via the ResolveHolgerBuild RPC (compile-free plan check) on facett-table |
| 6 | Funnel | nornir-funnel-embed |
always embedded / in-process over the local workspace — renders with nornir-server DOWN, no network dial (host-only: the UI knows no nornir address, so there is no $NORNIR_SERVER thin path) |
| 7 | Claude | facett-claude::ClaudePane via ClaudeTab |
hosted over the shared nornir-claude edda leaf's transport — OFFLINE stub by default; live HTTP behind --features claude-http (no dwarves-local Claude client) |
| 8 | Jera | jera::JeraTab (facett_zoneui::JeraCentral) |
dwarves' one jobs/zones surface — the jera ledger read live (fixture fallback), per-job zone column; auto-polls |
| 9 | Tools | zone_tools::zone_pane (facett_zoneui::ZonePane) |
pick a zone (demo/test/prod), Generate the zone forge infra, watch live inline status |
| 10 | Status | status::StatusPane |
pipeline-health badge wall — the UI surface of dwarves badge, reusing brokkr::badge |
| 11 | Release | release::ReleaseTab (facett-releaseview) |
the release convergence: the constellation DAG in three planes (LOCAL · SPARRING · CRATES_IO) a release drives to converge |
| 12 | Benches | benches::BenchesTab (facett_matrix::MatrixView) |
the selected workspace's testmatrix + its mimir populate/search bench trend (nornir_bench read API) |
| 13 | Binary | binview::BinaryTab (facett_binview::BinaryPane) |
binary-analysis story (size + hardening) from the four Mimir binary tables over the dyn Warehouse gRPC read seam |
| 14 | Coderoom | coderoom::CoderoomTab (facett_coderoom_view::CoderoomPane) |
the WORLD coderoom — symbol/semver/call-edge tables from the dedicated coderoom warehouse ($DWARVES_CODEROOM_WORKSPACE, default coderoom) |
| 15 | Saga | saga::SagaTab (nornir_saga::ui::Player) |
the session tape-recorder — recorded user journeys with a painful-first rail + transport bar, fed the .jsonl dwarves saga import lands |
| 16 | Settings | settings::SettingsPane |
workspace (mirrors the selector) · fat/thin backend · theme (facett_core::look presets) · vault unlock/lock |
| 17 | Profile | profile::ProfilePane |
the shared Identity About uses + the vault's credential NAMES (via the vault seam — never values) |
Above the tabs sits a warehouse selector header (nornir parity: many registered, ONE selected — options come from the running nornir-server's Workspaces.List over the SAME gRPC seam the Add/Populate form uses, unioned with $DWARVES_WAREHOUSES/nordisk so it is never empty). Changing the selection re-binds every warehouse-bound tab (broadcasts {"set_workspace":…}). An About popup (the shared facett-about card) shows at startup. Every pane body is single-sourced in a shared facett-*/edda crate (Law #1) — dwarves-gui only hosts them, and all drive over the same remote seam (state_json out / update_json in), so the robot harness exercises them headless.
The web/wasm build (start()) mounts the same panels minus the gRPC-only tabs (no server in the browser).
The Claude tab — host loop over a pure leaf
facett-claude::ClaudePane is a pure facett-Elm leaf: its Send emits a ClaudeEffect::Send (data) that a host runs through a transport. The impl_facet_via_elm! macro deliberately drops effects, so ClaudeTab is that host — it owns the pane + an injected transport and pumps view → update → deliver → reply, making Send drive end-to-end as a plain Box<dyn Panel>.
The transport is the shared nornir-claude edda leaf (Law #1 — no dwarves-local Anthropic client): ClaudeTab::offline() wires the leaf's clearly-labelled OFFLINE stub (NO live Anthropic call); --features claude-http swaps in the leaf's live HTTP transport (credential resolved at send time — see claude-token-path.md).
Coverage (in code)
dwarves-gui/src/tabbed.rs::tests:
robot_pipeline_funnel_panes_matrix— Forge|Funnel over the seam + testmatrix cell.robot_claude_pane_drives_over_the_seam— drives Claude set-tab→prompt→send→reply overstate_json/update_json(offline transport does the reply in code, no AI in the loop) +nornir-testmatrixcelldwarves-gui/claude_pane_drivable.
Diagram: assets/three-pane-shell.svg.