| 1 | <!-- English translation of adr/0010-ui-modes-toml-configuration.md. Canonical Russian: ../../adr/0010-ui-modes-toml-configuration.md --> |
| 2 | |
| 3 | # ADR 0010: UI Mode Data (Focus / Balanced / …) in TOML |
| 4 | |
| 5 | **Status:** Accepted · Implemented |
| 6 | **Date:** 2026-04-02 |
| 7 | **Updated:** 2026-04-25 — in `[capabilities]`, **IDE Health** keys: `ide_health_*`. Details — [§ History](#adr0010-history). |
| 8 | |
| 9 | ## Summary |
| 10 | |
| 11 | UI behavior is driven by **TOML mode definitions** (`UiModes/`) — capabilities, layout metrics, and family (`UiModeFamily`) — not hard-coded booleans in the ViewModel. The shipping product uses **Flight** as the primary mode id. Older Focus/Balanced/Power names in docs refer to historical presets; the catalog and loader remain the extension point for future presets. |
| 12 | |
| 13 | ## Related ADRs |
| 14 | |
| 15 | | ADR | Role | |
| 16 | |-----|------| |
| 17 | | [0003](0003-debug-ui-mode-separate-from-power.md) | Separate Debug UI mode (not Power cockpit) | |
| 18 | | [0006](0006-presentation-layers-and-feature-slices.md) | Layers, vertical slices, MainWindowViewModel role | |
| 19 | | [0017](0017-multi-window-workspace-and-agent-surfaces.md) | Multi-window and topology | |
| 20 | | [0022](0022-workspace-health-lexicon.md) | Canonical names and evolution for **IDE Health** (intersects `ide_health_*` table below). | |
| 21 | |
| 22 | ### Outside ADR |
| 23 | |
| 24 | | Document | Role | |
| 25 | |----------|------| |
| 26 | | [`attention-zone-panel-playbook-v1.md`](../../design/attention-zone-panel-playbook-v1.md) | Zone ↔ panel ↔ topology | |
| 27 | |
| 28 | ### Implementation snapshot |
| 29 | |
| 30 | | Element | Value | |
| 31 | |---------|----------| |
| 32 | | — | TOML loader, `UiModeCatalog`, capabilities, bundle `UiModes/` | |
| 33 | | — | Override and `docs/ui-ux` — as needed | |
| 34 | |
| 35 | --- |
| 36 | |
| 37 | ## Context |
| 38 | |
| 39 | Today **mode specs** (panel visibility, editor groups, theme slot, expanded chat width, etc.) are **hard-coded in C#** (`UiModeLayoutRegistry`, related constants). Global chrome metrics (splitters, minimum row heights, etc.) live in **`UiWorkspaceLayoutDimensions`** and apply via **`UiWorkspaceLayout`**. |
| 40 | |
| 41 | Need: **change mode layout without rebuild** (design, presets, experiments), consistent with **`settings.toml`** (Tomlyn already a dependency). |
| 42 | |
| 43 | **JSON is not proposed** as the primary format: user settings are already TOML; duplicating a second “official” text format for mode configs is undesirable. |
| 44 | |
| 45 | ## Decision |
| 46 | |
| 47 | <a id="adr0010-p1"></a> |
| 48 | 1. **Mode data source** — **multiple TOML files**: an **index** defines **order and the full list of mode ids** in the menu (built-in and **additional**, see below) + **one file per mode** (`Focus.toml`, `Balanced.toml`, …; shipped set mirrors defaults from `UiModeLayoutRegistry` / `DefaultsForFamily`) so diffs and “one mode — one file” stay obvious. If a mode file is missing — loader uses the same code defaults. **Shipped set location** — **`UiModes/`** next to exe (same pattern as **`Themes/`**: copy to build output beside exe). Separate **user settings path** for override — possible later extension, **not required in v1**. |
| 49 | |
| 50 | <a id="adr0010-p2"></a> |
| 51 | 2. **Global chrome metrics** (default tree width, splitter thickness, bottom-zone minimums, collapse policy, etc.) — **once** in **`workspace.toml`** beside the index and modes (not copied into each `Debug.toml`). |
| 52 | |
| 53 | <a id="adr0010-p3"></a> |
| 54 | 3. **Window schema (invariants):** `MainGrid` column count, column meaning, control-to-column binding — **intentionally remain in code/XAML** in this ADR. TOML describes **modes on that frame** (visibility, metrics, theme slot, etc.), not an alternate window markup. Moving window schema to data — **separate ADR** if product needs it (multiple frames, plugins, etc.). |
| 55 | |
| 56 | <a id="adr0010-p4"></a> |
| 57 | 4. **Load at startup:** deserialize into a model aligned with `UiModeLayoutSpec` (+ numbers like expanded right-column width for the mode when it stays in data). |
| 58 | |
| 59 | <a id="adr0010-p5"></a> |
| 60 | 5. **Fallback:** missing, corrupt, or invalid file — **built-in code defaults**, IDE does not crash. See below on role of those defaults. |
| 61 | |
| 62 | <a id="adr0010-p6"></a> |
| 63 | 6. **Schema version:** field **`schema_version`** — **only at root of the index file** (first file read in the set). It versions the **whole** `UiModes/` bundle — index, **`workspace.toml`**, per-mode files. **`workspace.toml` has no separate `schema_version`** (avoid two numbers drifting). Format migrations — one number from the index. |
| 64 | |
| 65 | <a id="adr0010-p7"></a> |
| 66 | 7. **Load validation (minimum):** unknown **`theme_slot`** → fallback; shipped set missing spec for a **required** id → warning + built-in spec from code. **Minimum required ids** (product must not “lose” in data) — **defined in code** — today matches **`UiModeLayoutRegistry.OrderedModeIds`**. Index may list **more** ids than that minimum (**extra user/preset modes**). See inheritance and separate menu entry without replacing `Debug`. |
| 67 | |
| 68 | <a id="adr0010-p8"></a> |
| 69 | 8. **Capabilities** — type **`UiModeCapabilities`** (`Features/UiChrome/UiModeCapabilities.cs`). In **`UiModes/<id>.toml`** keys are **semantic** (what appears in UI), **snake_case**; deserialization via **`CascadeTomlSerializer`** (PascalCase model properties → snake_case). Merge: explicit value → on **`inherits`** from parent → else **`DefaultsForFamily`**. API: **`GetCapabilities`**, **`GetWindowTitleOverride`**. |
| 70 | |
| 71 | | TOML key | Meaning | |
| 72 | |----------|---------| |
| 73 | | `active_task_strip` | Active task / Task Cockpit strip under toolbar | |
| 74 | | `main_window_title` | Full main window title | |
| 75 | | `quick_actions` | Quick actions at task | |
| 76 | | `agent_operations_panel` | Agent operations block in chat (Balanced) | |
| 77 | | `agent_trace` | Agent trace panel (Power) | |
| 78 | | `autonomous_agent_telemetry` | Power cockpit: explicit access to output (terminal and hints); **not** IDE Health channel | |
| 79 | | `ide_health_on_terminal_tab` | IDE Health duplicate on Terminal tab (Power) | |
| 80 | | `ide_health_main_column_span` | IDE Health area column span in main grid (Power) | |
| 81 | | `ide_health_strip` | Show IDE Health strip under editor | |
| 82 | | `ide_health_surface` | `bottom_strip` or `dedicated_page` — IDE Health presentation layer | |
| 83 | | `instrumentation_tabs` | Events/tests/debug tabs in bottom dock | |
| 84 | | `hypotheses_tab` | Hypotheses tab | |
| 85 | | `risk_summary_card` / `result_summary_card` | Risk and result cards in chat | |
| 86 | |
| 87 | ### Model layers (cheat sheet for `UiModes/*.toml` authors) |
| 88 | |
| 89 | To avoid confusing **mode id**, **layout**, **family**, and **capabilities**: |
| 90 | |
| 91 | | Layer | What it is | Source | |
| 92 | |-------|------------|--------| |
| 93 | | **Mode id** | Stable string (menu item, catalog key, `Id.toml` filename) | `index.toml` → `modes`, plus built-in id table in code for fallback | |
| 94 | | **Layout** | Panel visibility, editor group count, theme slot, flags like “select terminal tab” | Base: `UiModeLayoutRegistry` for built-in ids; merge with current `*.toml`; on **`inherits`** — base = resolved parent | |
| 95 | | **`workspace.toml`** | Shared chrome numbers (splitters, chat widths per Power / AgentChat / others rule, row minimums, etc.) | One file per bundle; not copied per mode | |
| 96 | | **`family`** | Product role: Focus, Balanced, Power, AgentChat, Debug — affects **capability defaults** and code branches (`UiModeFamily`) | Order: explicit **`family`** in mode file → on **`inherits`** from resolved parent → built-in id table → else **Balanced** | |
| 97 | | **Capabilities** | What to show (hypotheses, quick actions, Power cockpit chrome, etc.) | Base: on **`inherits`** — **resolved parent capabilities**; without **`inherits`** — **`DefaultsForFamily(family)`**. Overlay — explicit keys in `*.toml` | |
| 98 | |
| 99 | Narrow key in the same **`workspace.toml`** about **where to mount Markdown preview** (not to be confused with future general multi-`TopLevel` topology) — [0026](0026-markdown-preview-surfaces-and-placement.md). |
| 100 | |
| 101 | **End users** in the “UI mode” combo mostly see **preset id**; **`family`** / **capabilities** axes are optional in UI until separate toggles exist. |
| 102 | |
| 103 | ### Zone presentation topology (future extension) |
| 104 | |
| 105 | Today code has one topology — **`MainWindowDockedGrid`** (`AttentionLayoutSurfaceKind`, single main window, `MainGrid` columns). When **alternatives** appear (multiple `TopLevel`, scenarios in [0017](0017-multi-window-workspace-and-agent-surfaces.md)), **link** chosen topology with merge layers from [0010](0010-ui-modes-toml-configuration.md) and separate **per-monitor personal** layout (see next paragraph). **Without writing** dynamic window resize back into shipped files (see runtime subsection below). |
| 106 | |
| 107 | **Do not mix** with panel→zone map (`attention_zone_panels` / `AttentionZonePanelRuntime`): that is “which panel in which zone”; here — **in which geometry** (one window vs several) regions appear. Details: [`attention-zone-panel-playbook-v1.md`](../../design/attention-zone-panel-playbook-v1.md). |
| 108 | |
| 109 | **`presentation` / `zone_screen_layout` (root `settings.toml`) and grammar tokens in **`[presentation_grammar]`** (`screen_markers`, `screen_separator`, `zone_separator`, anchor literals `pfd_zone_identifier` / `forward_zone_identifier` / `mfd_zone_identifier`) — screen layout string from [0017](0017-multi-window-workspace-and-agent-surfaces.md) (“Multiple monitors”), e.g. `(PFD+Forward) (MFD)` or **`(P+F) (M)`** with short identifiers in TOML ([table](0017-multi-window-workspace-and-agent-surfaces.md#adr0017-presentation-grammar)); **between anchors inside one parenthesis pair** only literal **`zone_separator`** (**`Z`**, default **`+`**); if **`Z = "|"`** the string uses **only** `|`. **EBNF** — [0017](0017-multi-window-workspace-and-agent-surfaces.md#adr0017-presentation-ebnf). **Storage:** primarily **`settings.toml`** ([0028](0028-user-settings-toml-localappdata-and-secrets.md)). Repo **`.cascade/workspace.toml`** ([0021](0021-pfd-mfd-cockpit-attention-model.md) §2.1) — team panel/zone conventions, **not** mandatory monitor layout for everyone; on merge **user** `presentation` and tokens **override** bundle/repo. **Alternate key name** — **`zone_screen_layout`**; only one of the two per config. `AttentionLayoutSurfaceKind` enumeration and validation — in implementation; separate TOML-schema ADR **not required** while rules fit this subsection. |
| 110 | |
| 111 | **`inherits = "BaseId"`** — one parent: inherit the **full** resolved mode (layout, capabilities, chat width, task strip, window title — per merge rules in code). Child file sets **only deltas**. No separate `[inherits]` section listing “which fields inherit”: with this model the delta list in the file is already shorter than enumerating slices. |
| 112 | |
| 113 | ### Formal `family` resolution order |
| 114 | |
| 115 | 1. If **`Id.toml`** has **`family = "…"`** (case insensitive) — use it. |
| 116 | 2. Else if **`inherits`** — take **`family`** of the resolved parent (recursive). |
| 117 | 3. Else — for known built-in ids (`Focus`, `Balanced`, …) — **`BuiltinFamily(id)`** in code. |
| 118 | 4. Else — **Balanced** (unknown id without explicit family). |
| 119 | |
| 120 | ### Examples: `inherits` and optional `family` |
| 121 | |
| 122 | **Extra mode like Debug but with task strip and custom title** — without copying full spec: |
| 123 | |
| 124 | `index.toml` (fragment; full index see shipped `UiModes/index.toml`): |
| 125 | |
| 126 | ```toml |
| 127 | schema_version = 1 |
| 128 | modes = [ "Focus", "Balanced", "Power", "AgentChat", "Debug", "MySuperDebug" ] |
| 129 | ``` |
| 130 | |
| 131 | `MySuperDebug.toml`: |
| 132 | |
| 133 | ```toml |
| 134 | inherits = "Debug" |
| 135 | |
| 136 | active_task_strip = true |
| 137 | main_window_title = "CascadeIDE — my debug preset" |
| 138 | ``` |
| 139 | |
| 140 | **`family` not needed:** family stays **Debug** (resolved parent), hypothesis/instrumentation behavior as debug. |
| 141 | |
| 142 | **Two-level chain:** each file only deltas; chain root — built-in id with full spec (or another resolved mode). |
| 143 | |
| 144 | ```toml |
| 145 | # DeepWork.toml — branch from Focus |
| 146 | inherits = "Focus" |
| 147 | editor_group_count = 1 |
| 148 | main_window_title = "CascadeIDE — Deep work" |
| 149 | |
| 150 | # MyDeep.toml — branch from DeepWork |
| 151 | inherits = "DeepWork" |
| 152 | chat_expanded_width_pixels = 400 |
| 153 | ``` |
| 154 | |
| 155 | Both new ids must appear in **`modes`** in `index.toml`. |
| 156 | |
| 157 | **Rare case: `inherits` from `Debug` and explicit `family`** (UiModeFamily axis differs from parent; see note after example): |
| 158 | |
| 159 | ```toml |
| 160 | inherits = "Debug" |
| 161 | family = "Balanced" |
| 162 | ``` |
| 163 | |
| 164 | Layout — merge **Debug** spec with file fields. **`family`** for code (`UiModeFamily`, predicates like **`IsDebugFamily`**) becomes **Balanced**. Important: on **`inherits`**, capability base layer in the loader comes from **resolved parent** (`parentResolved.Capabilities`), not **`DefaultsForFamily(family)`** — UI flags stay “as Debug” until overridden in the same `*.toml`. If capabilities should start from **`DefaultsForFamily`** of the chosen family while inheriting layout — that is a **separate loader contract** change. |
| 165 | |
| 166 | *See also subsection **`inherits` and `family`: not the same thing** below — modular merge and chat width.* |
| 167 | |
| 168 | ### Dynamic resize after startup and TOML (source of truth) |
| 169 | |
| 170 | **`UiModes/*.toml`**, **`workspace.toml`**, and the mode index are **presets**: layout and metrics **at config load** (app start and, if added later, explicit “reload config”). They are **not** a live geometry journal. |
| 171 | |
| 172 | **Splitter drag, panel width/height changes, and any dynamic chrome resize after launch** are **in-memory runtime state**. They are **never written back** by default to shipped **`UiModes/*.toml`** and **`workspace.toml`** beside exe — not on every splitter move, not on mode change, not on IDE exit. Repo diffs stay **design presets**; accidental window drift does not corrupt preset files. |
| 173 | |
| 174 | If **persisting** geometry between sessions is needed later — **separate channel** (e.g. fields in **`settings.toml`**, user override under `%LocalAppData%` — see “Boundaries” below), **not** reverse write into distributable mode TOML. |
| 175 | |
| 176 | **MCP (`ide_set_panel_size` and analogs)** and UI snapshots for tests/agent change **current** layout at runtime; same contract: **do not** assume the call overwrites TOML on disk unless documented as a separate “export preset to file” operation. |
| 177 | |
| 178 | ### Same `Debug` vs separate `MySuperDebug` (inheritance) |
| 179 | |
| 180 | - **Editing `Debug.toml` or override on `Debug`** changes **Debug** for that config set: **stock Debug as shipped does not live beside** — expected when the goal is to override Debug. For “stock Debug **and** my variant in the menu” you need **two different ids**. |
| 181 | - **Extra id** (e.g. `MySuperDebug`), debug-like but different layout: listed in **index** (separate menu line, separate saved setting), file **`MySuperDebug.toml`**. **`inherits = "Debug"`** merges resolved Debug spec with overrides — no copy-paste of dozens of fields, no C# change per new id — index + mode file (and code rules for unknown ids: allowed bases, fallback). |
| 182 | - **UI label** for id (display name instead of raw `MySuperDebug`) — optional fields in index/TOML or localization; **not** mixed with required minimum ids from [§7](#adr0010-p7). |
| 183 | |
| 184 | ### Semantics for code: `family` and legacy `Is*Mode` flags |
| 185 | |
| 186 | **Context (problem before one axis):** checks like “is this Debug for hypotheses?” via **`UiMode == "Debug"`** or **`IsDebugMode`** break for derived ids (**`MySuperDebug`**): id string differs, product meaning “debug family” is the same. |
| 187 | |
| 188 | **Current code** already uses **`UiModeFamily`** and extension predicates — see **“Implementation in code”** below. Table of options and **`family` in TOML** — about **data after loader**; **`family`** after merge must land on the same axis as today’s `UiModeFamily`. |
| 189 | |
| 190 | Additionally, **`NormalizeUiMode`** currently maps unknown mode to **`Balanced`**. **New ids** from the index must **be preserved** (after “id exists in loaded list” check), or user `MySuperDebug` silently becomes Balanced without warning. |
| 191 | |
| 192 | **Discussion history (context; approach A implemented):** |
| 193 | |
| 194 | | Approach | Idea | Pros | Cons | |
| 195 | |----------|------|------|------| |
| 196 | | **A. Family (`family`) in data** | After merge, model has **`family`** (enum or string: `debug`, `power`, …). Optional **`family = "debug"`** in TOML; if unset — **from base** on `inherits`. Code moves **`IsDebugMode`** to **`family == debug`** (or **`IsDebugFamily`**). | Explicit semantics; `MySuperDebug` gets “debug” via inheritance; easier tests. | Migrate existing id checks; finite `family` list still in code. | |
| 197 | | **B. `inherits` chain only** | “Debug-ness” from walking inherits to built-in id (**`ResolvesToBuiltIn("Debug")`**). | No duplicate `family` in TOML. | Harder to reason/debug; depth/cycles; unclear cutoffs for UX. | |
| 198 | | **C. Explicit `family` in every TOML** | Every mode including derivatives writes `family` by hand. | Maximally explicit. | Duplication; easy to omit `family` on `MySuperDebug`. | |
| 199 | | **D. Exact id match only** | `IsDebugMode` stays `== "Debug"`; derivatives **not** Debug for hypotheses etc. | Minimal code. | Contradicts “MySuperDebug as Debug”; misleading. | |
| 200 | |
| 201 | **Implemented:** approach **A** — after load, **`UiModeFamily`**; optional **`family`** in TOML; VM/view checks use family and capabilities, not raw id where product role matters. |
| 202 | |
| 203 | #### `inherits` and `family`: not the same thing (separation of concerns) |
| 204 | |
| 205 | - **`inherits`** picks a **resolved parent**: **`UiModeLayoutSpec`** and base **`UiModeCapabilities`** (not “frame only”); child file applies **modular** overrides. For **`chat_expanded_width_pixels`**: explicit in file → else parent on `inherits` → else root mode — **`workspace.toml`** (via **`UiWorkspaceLayoutRuntimeMetrics`**) and Power / AgentChat / others rule. |
| 206 | - **`family`** is **product role** in code: which tabs/tools/policies count as “debug mode”, “power”, etc. **Different dimension** from `inherits`: you could inherit Debug layout but override family (rare). |
| 207 | |
| 208 | Default rules so TOML does not look like two knobs for one thing: |
| 209 | |
| 210 | 1. **Built-in** ids — **`family`** from **code table** (same meaning as today’s ids). |
| 211 | 2. With **`inherits`**, **`family` in TOML optional**: default **`family` = parent’s family** (e.g. `MySuperDebug` → `inherits = "Debug"` → **Debug**). File can be **`inherits` only** without `family` while semantics match base. |
| 212 | 3. **Explicit `family` in TOML** — when you need to **override** computed family for **`UiModeFamily`** (rare; see capability-base note in example above). |
| 213 | |
| 214 | So **`inherits` does not “set family” by itself** — it sets **parent chain** for layout/capability merge; **family** is explicit, inherited from parent, from built-in table, or **Balanced** for unknown id. Split: file/parent merge vs family axis for code. |
| 215 | |
| 216 | **Related places (non-exhaustive):** `MainWindowViewModel.Presentation` (**`UiModeFamily`**, instrumentation), **`UiChromeViewModel.NormalizeUiMode`**, bloom by mode string, **`GetChatPanelExpandedWidthPixels`**, MCP handlers with special debug rules. |
| 217 | |
| 218 | #### Do not multiply `Is*Mode` in VM |
| 219 | |
| 220 | Booleans **`IsFocusMode`**, **`IsPowerMode`**, **`IsDebugMode`**, etc. were a typical **smell**. Code **removed** them in favor of **`UiModeFamily`** and predicates (see **“Implementation in code”**). After TOML loader, prefer **one computed context**: enum **`UiModeFamily`** and/or compact **capabilities** from resolved spec and defaults. **Do not** add another `IsNewThingMode` or raw id comparisons where **family** is needed. |
| 221 | |
| 222 | #### Implementation in code (fixed before TOML loader) |
| 223 | |
| 224 | Not a separate doc: mode-axis agreements live **here** in the modes/TOML ADR. |
| 225 | |
| 226 | | Element | Role | |
| 227 | |---------|------| |
| 228 | | **`UiModeFamily`** + **`UiModeFamilyResolver.FromNormalizedMode`** | One axis after **`NormalizeUiMode(UiMode)`**; derived ids map like built-in strings. | |
| 229 | | **`UiModeFamilyExtensions`** (`IsFocusFamily`, `IsBalancedFamily`, `IsPowerFamily`, `IsAgentChatFamily`, `IsDebugFamily`) | Symmetric predicates instead of scattered **`== UiModeFamily.*`**. | |
| 230 | | **Domain names where enum is not enough** | e.g. private **`AutonomousCockpitActive`**: “autonomous agent cockpit”, inside — **`IsPowerFamily()`**. | |
| 231 | | **XAML** | Bindings to **`UiModeFamily`** via converters **`UiModeFamilyEq` / `UiModeFamilyNe`** (parameter — enum member name). | |
| 232 | | **After TOML** | Loader merges spec, **`family` → `UiModeFamily`**, **`UiModeCapabilities`** (optional **`main_window_title`**), no return to **`Is*Mode`**. | |
| 233 | |
| 234 | ### Fallback and built-in defaults (code vs TOML) |
| 235 | |
| 236 | Built-in fallback **does not claim** to be the main source of pretty layout: it **predictably boots IDE** when disk data is missing or broken. **Normal path** — shipped TOML beside exe; fallback is rare (clean install, broken directory, dev without file copy). |
| 237 | |
| 238 | Quality of current code constants (including around **Power**) may be **average** — **separate** work: polish defaults, align with design, maybe align built-in with shipped files. **Does not block** “TOML + code fallback” mechanics: reliable load and tests first, polish parallel or later. |
| 239 | |
| 240 | ### Panel visibility vs “0 px” |
| 241 | |
| 242 | In mode config and product meaning, **visibility semantics are primary** (`visible` / `hidden` for a panel; later maybe “collapsed with strip” if non-zero strip policy appears). **Hidden should not be defined mainly as `width = 0`** in mode TOML: zero column width and hidden splitter are **derived** from visibility rules and global metrics from `workspace.toml` (and code invariants). One idea covers **any** collapsible column/zone, not only chat. |
| 243 | |
| 244 | ## Boundaries (explicitly out of this ADR) |
| 245 | |
| 246 | - **Window schema** (MainGrid frame, new columns/zones from data) — see [§3](#adr0010-p3); out of scope. |
| 247 | - **`.toml` syntax highlighting in editor** — separate ([EDITOR-LANGUAGES.md](../../EDITOR-LANGUAGES.md): no TOML grammar in bundle yet); does not affect config load. |
| 248 | - **User override** in `%LocalAppData%\…` over shipped file — possible extension **after** base schema, not required in first commit. |
| 249 | |
| 250 | ## Consequences |
| 251 | |
| 252 | - **Pros:** one human-readable format with settings; mode edits without compiler; easier layout diff review; extra modes with **inheritance** without duplicating spec or mandatory C# per new id. |
| 253 | - **Cons:** parsing, on-disk errors, fallback tests; TOML field docs for contributors; loader with **`inherits` merge**; mode combo in UI from **loaded index** (code keeps **minimum** for validation and fallback); **`family`** and **capabilities** must stay aligned with **`UiModeFamily`** and **`UiModeCapabilities.DefaultsForFamily`**; **`NormalizeUiMode`** preserves user ids from index; **VM `Is*Mode` booleans removed** (see “Implementation in code”). Main **`docs/ui-ux`** aligned to **`UiModeFamily`** / capabilities (overview: **`docs/ui-ux/ui-modes-overview-v1.md`**). |
| 254 | - **MCP link:** `ide_set_panel_size` and UI snapshots must not break; disk contract — runtime/MCP **do not** rewrite `UiModes/*.toml` / `workspace.toml` by default (see “Dynamic resize after startup and TOML”). |
| 255 | |
| 256 | ## Documentation (in scope) |
| 257 | |
| 258 | Navigation and UX docs should describe **`UiModeFamily`**, **capabilities**, and TOML when needed — not legacy **`Is*Mode`**. Reader overview: **`docs/ui-ux/ui-modes-overview-v1.md`**; window layout and concept→code — **`docs/ui-ux/cascade-ide-ui-layout-v1.md`**, **`docs/ui-ux/concept-to-implementation-map-v1.md`**. Historical ADRs (e.g. approaches A–D) may mention old names in past tense — normal. |
| 259 | |
| 260 | ## Rejected alternatives |
| 261 | |
| 262 | - **JSON only** — diverges from `settings.toml` and Tomlyn stack for user configs. |
| 263 | - **Code only** — leaves current state; rejected as main path given “mode file without release” goal. |
| 264 | |
| 265 | ## Next step (optional) |
| 266 | |
| 267 | User override of `UiModes/` catalog from `%LocalAppData%` when product needs it; targeted **`docs/ui-ux`** updates when mode behavior changes in code. |
| 268 | |
| 269 | --- |
| 270 | |
| 271 | ## Change history |
| 272 | |
| 273 | <a id="adr0010-history"></a> |
| 274 | |
| 275 | | Date | Change | |
| 276 | |------|--------| |
| 277 | | 2026-04-08 | Intent to define **zone presentation topology** in TOML after alternatives to single `MainGrid` ([0017](0017-multi-window-workspace-and-agent-surfaces.md)); see subsection above. | |
| 278 | | 2026-04-11 | **`presentation`** / **`zone_screen_layout`:** primarily **`settings.toml`**, not team repo — [0017](0017-multi-window-workspace-and-agent-surfaces.md#adr0017-presentation-grammar), [§4](0017-multi-window-workspace-and-agent-surfaces.md#adr0017-p4); grammar tokens — **`[presentation_grammar]`** (no separate **`pfd_zone_alias`** — short names via **`pfd_zone_identifier`** etc.); **`screen_markers`** / **`screen_separator`** / **`zone_separator`**, **EBNF** — [0017](0017-multi-window-workspace-and-agent-surfaces.md#adr0017-presentation-ebnf). | |
| 279 | | 2026-04-11 | Anchors `adr0010-p1`…`p8` in Decision and links to [§3](#adr0010-p3), [§7](#adr0010-p7); convention — [ADR README](README.md#adr-anchors-policy). | |
| 280 | | 2026-04-25 | In **`[capabilities]`**, **IDE Health** contour keys in TOML: **`ide_health_*`** (`UiModeCapabilities` properties — `IdeHealth*`). | |
| 281 | |