Files
rutster/docs/superpowers/specs/2026-06-29-default-ui-design.md
opencode controller 42060b68e3
Some checks failed
CI / fmt (pull_request) Failing after 58s
CI / clippy (pull_request) Failing after 33s
CI / test (1.85) (pull_request) Failing after 32s
CI / test (stable) (pull_request) Failing after 47s
CI / deny (pull_request) Failing after 41s
spec(ui): default operator console design (later-rung, not yet scheduled)
Design record for the operator console — the downstream non-technical
operator's surface. **Not scheduled for current build;** lands after the
spearhead (steps 1-6) and the ACD/escalation rungs (capability ladder
rungs 1-2). The current build target is slice-2; the next build target
after slice-2 is slice-3 (the OpenAI Realtime adapter). An agent that
proposes building the console now is wrong — point it at spec §0.

Records the visual-brainstorming session's resolved decisions so they
don't get re-litigated at implementation time:

§1 Principles (load-bearing):
- GUI is a pure API client — **green-zone, never an insider** (ADR-0008);
  holds no privilege a third party couldn't get from the public API.
- Config-as-code is the single source of truth; the UI is a reconciled
  *view* (the k8s model — declarative desired-state in git, the engine
  reconciles; console + CLI + git are views over it).
- Operator persona, not builder. The builder authors flows in **code +
  an AI pair** (ARCHITECTURE 'DX spine'); this console is NOT the
  authoring surface for the technical builder. **No drag-drop authoring
  canvas** — a deliberately-closed decision (vision-revision §8).
- Ships in the batteries-included distro and the all-in-one image
  (the reference GUI is bundled — 'boom' includes a usable console).

§2 IA — Ops Console shell: left nav + center panel + persistent live rail.
Dense single-screen; for an operator who lives in it. Live rail always
visible regardless of the selected section.

§3 Dashboards — Live Ops (default landing) + Quality (sibling view). Maps
the k8s split: Live Ops = live operational state; Quality = the data-owned
eval loop (capability ladder rungs 3→4).

§4 Flows editor — master/detail + a generated, navigable preview map.
The preview map is a *view* rendered from the config, not a drag-drop
authoring canvas. Earns its place by showing branching (the escalation
split) the linear stage-list flattens.

§5 Declarative flow schema (illustrative YAML; format is open). The config
the console edits via the API; the builder edits in git; the engine
reconciles. The map is generated from this structure.

§6 Other sections (conventional): Agents · Numbers · Queues · People ·
Recordings · Settings.

§7 Architecture: separate app, public API only; never reaches into the FOB.
Config writes go through the reconcile path. Live data rides the event
stream off Valkey (ADR-0005); never the 20 ms media loop.

§8 v1 vs. later scoping. §9 open decisions (flow config format, map
rendering depth, quality metrics, live transport, framework).

Cross-refs ADR-0002 (fused vertical + composable platform), ADR-0006
(WebRTC ingress / escalation UX), ADR-0007 (rented trunk / Numbers
config), ADR-0008 (FOB / green-zone — the UI is green-zone),
ARCHITECTURE.md 'DX spine' + 'GUI & extension architecture', PORT_PLAN §5
(contact-center domain).
2026-06-29 20:27:25 -04:00

14 KiB
Raw Permalink Blame History

Default UI — Design (the operator console)

  • Status: Design accepted (direction). Not yet scheduled — a later-rung surface.
  • Date: 2026-06-29
  • Origin: Visual brainstorming session (the deployability + default-UI thread of the 2026-06-29 strategic review).
  • Related: ADR-0002 (fused vertical + composable platform), ADR-0006 (WebRTC ingress / escalation UX), ADR-0007 (rented trunk / Numbers config), ADR-0008 (the UI is green-zone), ARCHITECTURE.md "DX spine" + "GUI & extension architecture", PORT_PLAN.md §5 (contact-center domain).

0. Scope & sequencing — READ THIS FIRST (esp. agents)

Do not implement this yet. This is a design record, not an implementation plan. The UI is a later-rung surface that lands after the spearhead (steps 16: media → tap → brain → barge-in → rented-transport PSTN → spend cap) and the ACD/escalation rungs (capability ladder rungs 12). The current build target is slice-2 (the agent tap). An agent that proposes building the console now is wrong — point it here, at this section.

When the UI is built, it gets its own slice spec + implementation plan at that time. This document records what it should be and why, so those decisions don't get re-litigated.

This UI is also not the authoring surface for the technical builder. The builder authors flows in code + an AI pair (config-as-text, git-versioned — ARCHITECTURE "DX spine"). This console is for the downstream non-technical operator. There is no drag-drop authoring canvas (a deliberately-closed decision — vision-revision §8). These two facts are load-bearing; do not blur them.


1. Principles (load-bearing)

  1. The GUI is a pure API client — green-zone, never an insider. A separate application, outside the FOB trust boundary (ADR-0008). It holds no privilege a third party couldn't get from the public API. No backdoors, no coupling to internal config files (FreePBX's mistake). This guarantees API completeness — if the console can do it, the API can.
  2. Config-as-code is the single source of truth; the UI is a reconciled view. The Kubernetes model (ARCHITECTURE "GUI & extension architecture"): declarative desired-state lives in git and is reconciled by the engine; the API/CLI/console are views over it. The operator edits in the console or the builder edits in git — same source of truth, reconciled. The console is the dashboard, never a side-channel.
  3. Operator persona, not builder. See §0. The console serves the person running the contact center day-to-day, exactly as integrators built operator UIs on top of Asterisk.
  4. Ships in the batteries-included distro and the all-in-one image (the reference GUI is bundled — "boom" includes a usable console). The ecosystem can build rival GUIs on the same public API.

2. Information architecture — the Ops Console shell

Chosen shell: left nav + center panel + a persistent live rail. Dense, single-screen; for an operator who lives in it.

┌─────────────────────────────────────────────────────────────────────┐
│ rutster ▸ Acme Support                                    ◴ on shift  │  top bar (tenant, session)
├───────────┬─────────────────────────────────────────┬───────────────┤
│ Dashboard │                                         │  LIVE          │
│ Flows     │                                         │  12 active     │
│ Agents    │   main panel (selected section)         │  87% contained │
│ Numbers   │                                         │  $4.10/hr      │
│ Queues    │                                         │  ⚠ 1 escalation│
│ People    │                                         │                │  persistent
│ Recordings│                                         │  (always in    │  live rail
│ Settings  │                                         │   view)        │
└───────────┴─────────────────────────────────────────┴───────────────┘
   left nav              center panel                    live rail
  • Left nav sections: Dashboard · Flows · Agents · Numbers · Queues · People · Recordings · Settings.
  • Live rail (right, persistent): active calls, containment %, spend rate, escalation alerts. Fed by the live event stream (§7). Always visible regardless of the selected section.

3. Dashboards

Two dashboards. Live Ops is the default landing; Quality is a sibling view (a nav/tab sibling of the dashboard, one click away). This maps the k8s split: Live Ops = live operational state, Quality = the data-owned eval loop.

3.1 Live Ops (default)

Leads with working the floor:

  • Compact KPI strip: containment · calls · AHT · spend · escalations (today).
  • Live calls table: caller · flow · who (🤖 agent persona / queue / 🧑 human) · state · duration · actions. Actions include listen and take over — the escalation gesture (capability rung 2), which joins a WebRTC leg via the audiohook/barge primitive (ADR-0006, PORT_PLAN §2 audiohook).

3.2 Quality (sibling)

Leads with watching the AI:

  • Containment trend (today / 7d / 30d) on calls you own.
  • "Where AI handed off" — escalation reasons ranked ("asked for refund" ×8, "couldn't find order" ×5, "wanted a human" ×4), each drilling into the calls/transcripts. This is the data-owned failure signal that feeds the self-improvement loop (capability rungs 3→4) — the differentiation, made visible. Beware the containment-vs-resolution metric trap: surface resolution, not just deflection.

4. Flows editor — the "call-flow builder"

The console's flagship surface, and the answer to "what is a call-flow builder in the AI era." It is a structured config editor, not a drag-drop IVR canvas. A flow = what happens on an inbound call.

Shape: master/detail editor + a generated, navigable preview map.

┌─ Flows ▸ Acme Support ───────────────────────────────────────────────┐
│ PREVIEW — generated from config · click a node to edit               │
│  📞 Number → 🤖 Agent → ↗ Escalation? ─┬─ ✓ contained → 📝 Post-call  │  generated map
│                                        └─ ✗ stuck → 🧑 Queue → Human  │  (read-only, navigable)
├──────────────┬───────────────────────────────────────────────────────┤
│ STAGES       │  AGENT — selected                                      │
│ 📞 Inbound   │   persona [ Support Bot ▾ ]                            │  master / detail
│ 🤖 Agent ◂   │   knowledge base [ Acme Docs ▾ ]                       │  editor
│ 🕐 Hours     │   greeting [ "Hi, Acme support…" ]                     │
│ ↗ Escalation │   [ + tool ]  [ + guardrail ]                          │
│ 📝 Post-call │                                                        │
└──────────────┴───────────────────────────────────────────────────────┘
  • Master/detail: the stage list (left) + the selected stage's structured form (right).
  • Generated preview map (top): a horizontal pipeline rendered from the config — read-only and navigable (click a node → selects that stage below; edits regenerate the map). It is a view, not an authoring canvas. It earns its place by showing branching the linear stage-list flattens (the escalation split). Map and editor stay in sync; the config is the truth.
  • Flow spine (the stages): Inbound → Agent → Hours → Escalation → Post-call, branching at escalation (contained → Post-call / stuck → Queue → Human).
  • Agent stage fields: persona (ref) · knowledge base · greeting · tools · guardrails.

Why this is "genuinely new design space, not dialplan 2.0": the conversation half-dissolves into the agent (the model improvises the dialogue), so what's left to author is the routing / escalation / business scaffolding around the agent — which is mostly structured config, not a node graph.


5. The declarative flow schema (the source of truth the console edits)

The console reads/writes this through the public API; the builder edits the same files in git; the engine reconciles. Illustrative (format — YAML/TOML/typed — is an open decision; it must be typed, validated, and LSP-friendly per ARCHITECTURE "DX spine"):

# flows/acme-support.yaml  — reconciled desired-state; console edits this via the API
flow: acme-support
inbound:
  numbers: ["+15550100", "+18005550111"]      # → Numbers section maps these (ADR-0007 rented transport)
agent:
  persona: support-bot                         # ref → agents/support-bot.yaml (reusable)
  knowledge_base: acme-docs
  greeting: "Hi, Acme support — how can I help?"
  tools: [order-lookup, refund-status]
  guardrails: [no-pii-readback, max-attempts-3]
hours:
  timezone: America/Los_Angeles
  open: { mon-fri: "09:00-17:00" }
  closed_action: voicemail
escalation:
  when: [ai_stuck, caller_requests_human, sentiment_negative]
  to: queue:support                            # → Queues / People (rung 2 takeover)
post_call:
  - transcript: { to: crm }
  - summary_email: { to: owner }
spend:
  cap_per_call_usd: 0.50                        # ENFORCED in-boundary (rutster-spend), not advisory

Agent personas (agents/*.yaml), knowledge-base refs, queues, and number inventory are separate reusable objects referenced by flows. The preview map (§4) is generated from this structure.


6. Other sections (conventional — described, not mocked)

  • Agents — reusable AI agent definitions (persona, KB, prompts, tools, guardrails) referenced by flows. The brain itself is green-zone/external; this configures how it's invoked.
  • Numbers — phone-number inventory and number→flow mapping; rented-transport provider config (ADR-0007: CPaaS keys / out-of-tree SBC endpoint).
  • Queues — ACD config (skills, overflow, SLAs) — PORT_PLAN §5 domain core.
  • People — human agents (skills, presence, state); the escalation targets for rung 2.
  • Recordings — calls / transcripts / CDR; the drill-down target from Quality. Data the operator owns.
  • Settings — trunk/rented-transport, spend caps, brain/tap config, tenancy, RBAC, secrets refs.

7. Architecture & data flow

  • Separate app, public API only. The console talks to the rutster control API (REST/gRPC) for config CRUD and to the event stream (WebSocket/SSE) for live data (the rail + Live Ops). It never reaches into the FOB; it has no privileged channel (ADR-0008).
  • Config writes go through the reconcile path, not direct mutation — the console PUTs desired-state; the engine reconciles (k8s model). Concurrent git edits and console edits converge on the same store.
  • The preview map is generated client-side from the fetched flow config — no separate "map" data model; the config is the model.
  • Live data (rail, live-calls table, containment) rides the event stream off Valkey (ADR-0005) — never the 20 ms media loop.
  • Auth: SSO + RBAC + per-tenant scoping (this is legitimate server ingressADR-0006 "tap ≠ ingress"). Multi-tenant isolation is enforced server-side; the console is just a scoped client.

8. Scope when built — v1 vs. later

v1 (when scheduled): the Ops Console shell; Live Ops dashboard; Flows editor (master/detail + preview map) over the flow schema; Numbers, Agents, Settings enough to stand up a flow. Read-only Recordings.

Later: Quality dashboard depth (trend analytics, eval-set export — rung 3→4); rich Queues/People management; rival-GUI ecosystem docs; theming.

Non-goals (ratified, do not add): a drag-drop authoring canvas; the builder's authoring surface (that is code+AI); any privileged/backdoor channel; coupling to internal config-file formats.


9. Open decisions

  • Flow config format — YAML vs TOML vs a typed schema with generated bindings (must be LSP-friendly).
  • Map rendering — depth of branching shown; how sub-flows / shared fragments render.
  • Quality metrics — exact containment/resolution definitions (avoid the deflection-gaming trap).
  • Live transport — WebSocket vs SSE for the event stream to the console.
  • Framework — out of scope here; an implementation-time decision for the future slice spec.