THE PRODUCT FACE

War Room

War Room is the operator surface and the product face: where you convene, steer, pause, and read the record. Every view, every control, every transport. The browser UI and the macOS desktop shell share one backend.

The views

Twelve views in one War Room. Each view names its controls and exactly what they do. Nothing here hides a second backend: the browser tab and the desktop shell are two windows into the same services.

Deliberate

Streams a multi-seat session over /ws/deliberate.

Between rounds, when the server reports awaiting_input, the operator can send an intervention into the proceeding. The stream speaks in typed events, so the UI always knows which act it is in:

session_started round_started seat_started seat_chunk seat_complete convergence_scored round_divergence round_complete awaiting_input intervention_received synthesis_started synthesis_complete session_saved done error

Every control on the convene desk, and everything you can do at the pause, is spelled out in the two sections below.

Direct Fire

One seat, one shot, no rounds.

A single model answers a single prompt with a chosen lens: contrarian tears down the framing, munger inverts the assumptions, kiss strips to essentials, specops hunts the adversarial signal, and the experimental premortem assumes the plan already failed and works backward. CLI parity: --contrarian, --munger, --kiss-review, --specops, --premortem. The stream skips straight from session_started to synthesis: no rounds, no convergence, no pause.

History

The record of proceedings.

Saved sessions, their synthesis, their lineage, and their exports. What the council said stays findable.

Outbox

Reads signed Gateway directives.

This is where signed directives surface. An empty Outbox means there is no signed directive from the configured Gateway. It is not an error; nothing has been signed yet.

Watch

Sentinels, fires, and the watch plane.

Shows registered Sentinels, their fires, and watch-plane status. It stays readable while action production is disabled, because observing is not acting.

Discover

Scans exact transports, nothing more.

Three probes: non-empty API-key environment variables (names only, never values, no billable call), supported local CLI binaries, and reachable local runtimes. Unavailable rows stay visible for setup guidance but are disabled in selectors. Rescan refreshes the browser-cached result. There is no background polling.

Cabinets

Reads and edits local cabinet YAML.

The server is the YAML-validity authority, and it refuses to overwrite built-ins. Cabinet keys must match ^[a-z0-9][a-z0-9_-]{0,63}$.

Patterns

Your intervention habits, counted.

Every pause decision you make is logged, and this view plays it back: counts per action (Continue, End early, SpecOps, Munger, Contrarian, KISS, Inject context, Swap seat) over a chosen window, default 30 days, plus the full paginated intervention log from /api/interventions with copyable session ids. The council audits you a little, too.

Drift

Compares normal versus blind reruns.

Re-runs normal sessions in blind mode and measures how much precedent injection actually shaped the ruling. Weekly drift history feeds the dashboard card and Meta-review. Notifications are delivered via COUNCIL_WEBHOOK_* environment variables.

Meta-review

The self-audit loop.

Reads the weekly drift history plus your intervention history and recommends one parameter to tune. One, not ten: a self-audit that produces a single next move is one you might actually run.

Librarian

An optional tab, never a dependency.

Proxies a separately configured local Librarian service. If that service is offline, Council and Gateway carry on untouched. Memory is a guest here, not a load-bearing wall.

Settings

The bases and the token.

API base, WS base, Gateway base, Librarian base, auth token, and Council root, all stored in local storage. Prefer loopback: a non-loopback endpoint can leak the token.

Deliberate or Direct Fire

Two ways to ask, one honest split. Deliberate convenes a cabinet: assigned seats, counted rounds, convergence scoring, an operator pause, and a chair ruling filed at the end. Direct Fire sends one prompt to one model through one lens and returns one answer.

Choose Deliberate when

The question deserves disagreement: a decision with stakes, a design worth attacking from several blind spots, anything where you want positions challenged across rounds and a ruling with the dissent still attached. It costs more seats, more tokens, and more of your attention at the pause.

Choose Direct Fire when

You want one mind and one move: tear down this framing, invert these assumptions, strip this to essentials, run a premortem. No rounds, no convergence, no pause, one saved result. If the answer surprises you, promote the question to a full proceeding.

Convene: every control on the desk

This is the full Deliberate start panel, control by control. Nothing on it is decorative.

Control
What it actually does
The matter
The topic textarea. As you type, a debounced precedent search reports how many prior rulings match, unless Blind mode is on.
Cabinet
Which room deliberates. Chips show seat count, round count, and any providers the cabinet needs that Discover did not find. See the Council page for the full roster and why to pick each one.
Deliberation mode
TearDown (default, kill bad ideas), Pathfind (no dead ends), Pathfind then tear-down (two-phase CLI parity), Harden (stress plus fix).
Budget cap
Optional USD ceiling for the run. Thought is rare and also metered.
Routing tier
best, sovereign, or strict_sovereign.
Governed via Gateway
Off by default: Direct provider and CLI calls, explicitly bypassing Gateway governance. On: all model calls fail closed through Gateway, with a sensitivity level sent as X-Sensitivity-Level. The start is blocked if the cabinet references a Direct-only transport.
Blind mode
No precedent injection. Used honestly, this is how Drift measures what memory buys.
Pause after each round
Default on: the session halts between rounds so you can steer mid-flight. Off means continuous to the chair.
Frame check
Default on. A round-1 prompt framing pass: a small utility model scans the prompt for embedded assumptions before seat fan-out, so one poisoned premise cannot quietly steer every seat. Hidden for local_code_only cabinets. Details on the Council page.
Max rounds
Override the cabinet default, 1 to 6.
Sheldon Validate
Between-round claim verification with web evidence, plus a validator provider picker and a Gate mode that redacts CONTRADICTED claims. First-class explanation on the Council page.
Scope Auditor
Steering and boundary review beyond frame check: detect operator steering, framing, and scope creep. Preview: the toggle is real and the flag is parsed, but engine wiring is not yet implemented; a run logs that the flag was ignored. Exact caveat on the Council page.
Advanced
Auto SpecOps threshold (default 0.8) and an optional worker_provenance JSON blob.

The pause: the round ends, you speak

With the default pause on, the stream stops at awaiting_input after each round, which means the operator gets a word in before round 2 even exists. The panel shows the convergence score of the round just finished and waits for your call. These are the controls, exactly as they appear.

Control
What it does
Continue
Resume as-is into the next round.
End early
Skip remaining rounds and send the proceeding to the chair now.
Operator note
Inject and resume: your note is fed verbatim into every seat next round. If a note is pending, it also rides along with the next escalation.
SpecOps
Escalation lens: hunt the adversarial signal. A prior SpecOps result is shown at the next pause for review before you continue, and feeds the next round when you resume.
Munger
Escalation lens: invert the assumptions.
Contrarian
Escalation lens: tear down the framing.
KISS
Escalation lens: strip to essentials.
Swap a seat
Replace a seat for the next round: pick the seat, optionally change provider and model, optionally override its system prompt. Swap and resume.

Why the pause is load-bearing

The pause is the Reality slot expressed as UI. Convergence is scored every round, an intervention predictor may hint when an escalation looks warranted, and nothing proceeds past a paused round until you choose. Turning the pause off is a choice too, and it is yours.

The transport matrix

A seat is bound to exactly one transport, and that binding is never silently switched. These are the built-in transport IDs and what each one actually talks to.

Transport ID
What it carries
grok_build
Grok Build CLI, the authenticated grok CLI.
grok_hermes
Grok via the Hermes adapter.
grok_api
xAI API, keyed by XAI_API_KEY.
claude_code
Claude Code CLI.
claude_api
Anthropic Messages API, keyed by ANTHROPIC_API_KEY.
codex_cli
Codex CLI.
openai_api
OpenAI Responses API, keyed by OPENAI_API_KEY.
gemini_agy
Gemini via the agy CLI.
gemini_vertex
Vertex AI, via Google ADC plus VERTEX_PROJECT, VERTEX_LOCATION set to global, and VERTEX_GEMINI_MODEL.
gemini_cli
Legacy Gemini CLI.
nvidia/nim
Keyed by NVIDIA_API_KEY.
nous
Keyed by NOUS_API_KEY.
deepseek
Keyed by DEEPSEEK_API_KEY, or a configured NIM or Nous model.

Seat ID rules

  • One seat ID equals one transport. The binding is never silently switched.
  • Legacy IDs stay readable: grok, grok_cli, hermes_cli, claude, gpt, gemini, agy_cli.
  • Custom slugs via ~/.config/council/providers.toml cannot redefine reserved built-in IDs.
  • Gateway adapters exist only for grok_api, claude_api, claude_code, openai_api, codex_cli, gemini_vertex, gemini_cli, and nvidia/nim. Everything else is Direct-only.

The REST surface

The whole spoken surface of the Council backend, plus the one WebSocket. Authentication is a bearer token when COUNCIL_AUTH_TOKEN is set; the WebSocket carries that token via a negotiated subprotocol, and Gateway may require X-Gateway-Auth.

Route
Purpose
GET /api/health
Liveness and health of the backend.
GET /api/discover
The transport discovery scan behind the Discover view.
GET /api/cabinets
List local cabinets.
POST /api/cabinets/save
Save cabinet YAML, validated by the server.
POST /api/deliberate
Start a deliberation over plain HTTP.
GET /api/sessions
Saved sessions for the History view.
GET /api/precedent
Precedent lookup.
/api/drift/*
Drift comparison routes.
/api/mapmaker/*
Mapmaker routes.
/api/meta-review/*
Meta-review routes.
/api/librarian/*
Proxy routes to the optional local Librarian service.
GET /ws/deliberate
The streaming deliberation WebSocket behind the Deliberate view.

Real receipts

Not mockups. These frames come from an actual proceeding on the actual UI.

Animated capture of a real War Room deliberation session with three seats across one round, ending in a filed ruling.
A three-seat, one-round starter-nvidia proceeding completed for $0.0051.
Poster frame of the same War Room session.
Poster frame of the same session.
The filed chair ruling shown beside the seats in the War Room.
The filed chair ruling, beside the seats.

Persistence caps

Storage has hard edges, and the edges are numbers. Chat patches use optimistic concurrency via If-Match, so two writers cannot silently trample each other.

Field
Cap
Chat file
2 MiB per file.
Assistant message
64 KiB.
Source snippet
1 KiB.
Sources per turn
20.
User content
8192 B.
Title
120 B.
Cabinet name
64 B.
client_msg_id
64 B.

Fine print, read before trusting

  • A detected CLI binary is not proof its login is still valid. The first real seat call is.
  • Discovery and routing YAML never prove model entitlement.
  • The War Room blocks a Governed start when the cabinet references a Direct-only transport.
  • COUNCIL_DEV_NO_AUTH=1 must never run on a network-accessible service.
  • Do not delete or rewrite historical sessions without a migration plan. New fields need serde defaults.