Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/dwarves

.nornir/three-pane-shell.md

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:

Diagram: assets/three-pane-shell.svg.