Dialogue · Design notes · Room dials
← Design notes

The room dial — Character vividness

One dial set at room creation: how vividly each persona plays itself (True to life → Larger than life). It lives in the cached system prefix beside model + language, so it costs nothing per turn. This is the thinking behind it and how it's built. Live in the new-chat modal of lib/room-ui.html.

updated 2026-06-28 — one dial nowThis page first documented two dials. The Temperament (panel-debate) dial has been RETIRED: panel conflict is now the floor producer's per-turn call — it reads the room and stages contention, steered in plain language (with Cues teaching it). And Intensity → Vividness — labelled Character vividness in the new-chat dialog (renamed 2026-06-29): a 3-notch segmented control (True to life · Turned up · Larger than life), each notch carrying a plain-language caption that names its effect (faithfulness · distinctness · drama). The 4th notch — Extreme — was dropped: its directive spent itself fighting parody, and "Larger than life" already means amplitude-not-parody. The Temperament sections below are kept as design history; the temperature-not-quota thesis and the guardrails still hold for Vividness. The internal field/keys stay intensity.
A dial sets the format of the room, not a quota. It changes how pronounced each voice is — it never tells a host to fabricate a position or tip into parody. That guardrail rides every notch.

The dial — Character vividness

3 notches now (was 4). True to life is the floor — you only ever dial up. At the floor it emits nothing, so a default room is byte-identical to a room with no dial at all. (The Temperament slider pictured just below is kept for the design record — it's no longer in the app.)

Room Temperament  — how the panel argues with itself
NaturalProbingCombativeExtreme
shown at Combative · lead with disagreement; let the split stand
Character Intensity  — how loud each voice is
NaturalHeightenedTheatricalExtreme
shown at Heightened · full strength; no two hosts alike

The load-bearing decision: a temperature, not a quota

The first ask was an "agree ↔ disagree" dial. Taken literally — force the hosts to disagree — that breaks the whole instrument. The project exists to kill manufactured conversation; a dial that makes hosts disagree regardless of what they believe is exactly the contamination the audits hunt for.

the reframeSo the dial is a format temperature, not a quota. It moves the threshold and vigour at which a host voices a genuine divergence — collegial fireside chat at one end, debate-show at the other — the same people, a different room. It never manufactures a position. Same logic on the other dial: intensity is amplitude on the real person, never a caricature of them.

The guardrail rides every notch

Because the risk grows as you turn it up, the no-fabrication clause is written into each notch's directive, hardest at the top:

Why Natural is the floor (no dial-down)

An earlier cut of Temperament also went below natural — harmonious, collegial. We dropped them. Dialling down toward harmony pushes the panel toward the chorus-flattening failure: everyone agreeing in the same accommodating register, the second-speaker who only confirms the first. That's the other thing this instrument is built to avoid. Making Natural the floor sidesteps it entirely — and matches Intensity, which never had a reason to go below "as written."

Room Temperament — the notch ladder

Modulates the confer and the response gate — the threshold and vigour of surfacing a real divergence. Verbatim directive text per notch (centre/floor emits nothing):

Naturalfloor · default

No directive emitted. Honest positions, however they fall — the panel agrees where it agrees and diverges where it diverges, sized to substance. (Identical to a room created before the dials existed.)

Probing+1

"This panel is probing. The hosts test each other's claims rather than nod them through — they ask the hard follow-up, name the assumption they doubt, and surface the divergences they would otherwise let pass. Press on the weak points in each other's reasoning.Guardrail — never manufacture a disagreement: a host argues only a position they would actually hold, and concedes a point that is genuinely right."

Combative+2

"This panel runs hot. The hosts come in looking for where they differ and lead with it — they challenge each other directly, say plainly what is wrong with another host's case before granting anything right in it, push back hard, and hold their ground instead of drifting to consensus. Disagreement is not resolved for the sake of tidiness: if they still do not agree, the split stays open and unsoftened.Guardrail — a host contests only a position it genuinely rejects and never invents one — but short of that, nothing is left politely unsaid, and a real objection is never softened to keep the peace."

Extremetop · peak risk

"This panel treats the conversation as a clash to be won. The hosts hunt out every fault line, press each disagreement to its limit, give no ground, and would rather leave the guest holding two openly contradictory answers than anything that reads as agreement. No concession for comfort, no rounding toward a shared line.Guardrail (hardest here) — even at full heat a host argues ONLY what it genuinely believes and never fabricates a stance, a grievance, or an objection it does not hold — the intensity is in how hard REAL differences are fought, never in inventing differences that aren't there. Where two hosts do in fact agree, they say so in a single curt line and drive straight back to where they don't."

Character Intensity — the notch ladder

One dial for the whole panel. Amplifies each host's diction, mannerisms, and stance — never adds a trait they lack.

Naturalfloor · default

No directive emitted. Each host voiced as written in their profile.

Heightened+1

"Voice each host at full strength. Lean into what makes them distinct — their diction, their characteristic moves, the stance they take — so no two hosts could be mistaken for each other. This sharpens who they already are; it adds no trait they lack, and it never tips into caricature or repeats a signature move past the point a real person would."

Theatrical+2

"Voice each host at their most pronounced — the boldest, most vivid version of themselves, the way they'd come across at their most fully expressed, with the contrast between them turned up.Guardrail — this is amplitude, not parody. Heighten the real person; never flatten them into a catchphrase or a single mannerism on repeat."

Extremetop · peak risk

"Voice each host at the absolute extreme of themselves — every defining trait, cadence, and conviction turned to its maximum, the version of this person that would be unmistakable from a single line, with the contrast between hosts pushed as far as it goes.Guardrail (hardest here) — it must still be THEM at full volume, never a parody OF them. Invent no catchphrase, tic, or trait the person does not have, and never let a host collapse into one repeated mannerism. Maximum amplitude, zero fabrication."

Where a dial lives: the frozen, cached prefix

A dial is just text appended to the system block at room creation — right beside the language directive. The system block is the big, stable prefix that caching re-reads nearly free every turn, so a dial costs one-time tokens at creation and nothing thereafter.

a Combative room — the dial rides in the frozen system block
system · SP · profiles · + temperament: combative the dialog so far new user line

Set at creation, baked into the prefix → from turn 2 on it's a cheap cached read like the rest of the system block.

Why creation-time, not a live mid-chat control? The dial sits before the dialog. Editing it mid-conversation rewrites the system block, which (per the caching rules) moves the first-differing byte ahead of the whole conversation and re-reads all of it. So the dial is strong + cache-safe at creation; to change it you fork or start a fresh chat. At Natural it emits nothing — so an untouched room never pays for a dial it didn't set.

Reading a room's dials back

Once set, a dial is informational — so the chat-info panel echoes both as read-only sliders. To make "you can't change this here" obvious, the scale fades into the background and only the current notch pops: the editable modal sliders are coral, these are not.

Room Temperament (read-only)
NaturalProbingCombativeExtreme
Character Intensity (read-only)
NaturalHeightenedTheatricalExtreme

Faded scale = --line (lighter in light themes, darker in dark — it always recedes toward the background); the current notch = --ink (maximum contrast in every theme). Editable sliders keep the coral fill + thumb.

Implementation

Backend — lib/run_room.py

Each dial is a value → directive lookup; the centre/floor maps to the empty string, which appends nothing. build_system_blocks threads both into the cached materials block, right after the language directive.

# value → directive; "natural"/unknown → "" (no directive) DYNAMICS_OPTS = ["natural", "probing", "combative", "extreme"] INTENSITY_OPTS = ["natural", "heightened", "theatrical", "extreme"] def build_system_blocks(cast, language="", dynamics="", intensity=""): materials = roster_intro + profiles \ + language_directive(language) \ + dynamics_directive(dynamics) + intensity_directive(intensity) return [ {SP}, {materials, cache_control} ] # dials live in the cached prefix (BP1)

Persisted in both persist() and _load_state (a per-room field forgotten in load silently reverts on resume); carried by create() / fork(); normalised + validated at POST /api/rooms; the option lists ship in /api/config; the chosen values echo back in /state.

Frontend — lib/room-ui.html

Open question — Extreme is unvalidated (still the one caution)

to testThe dials are live; what's not proven is whether Extreme reads as hosts fighting real differences hard, versus the model quietly manufacturing conflict — the exact failure this instrument audits for. The guardrail is written to prevent it, but only a real run + a fresh-session audit can confirm it holds. Treat the first Extreme room as a deliberate test, not a default.