| 1 | <!-- English translation of adr/0029-configuration-toml-canonical-ui-facade.md. Canonical Russian: ../../adr/0029-configuration-toml-canonical-ui-facade.md --> |
| 2 | |
| 3 | # ADR 0029: Configuration — **TOML-First** (On-Disk Canon); **Holistic** Settings UI — **Deferred**; Point UI — **Canon Facade**, Not a Second Truth |
| 4 | |
| 5 | **Status:** Accepted · Implemented (TOML-first on disk; holistic settings UI — deferred; point UI — facade) |
| 6 | **Date:** 2026-04-08 |
| 7 | **Updated:** 2026-04-08 — holistic center deferred; subsection “Why point UI”; dynamic UI from model perspective; point UI = code weight. Details — [§ History](#adr0029-history). |
| 8 | |
| 9 | ## Related ADRs |
| 10 | |
| 11 | | ADR | Role | |
| 12 | |-----|------| |
| 13 | | [0028](0028-user-settings-toml-localappdata-and-secrets.md) | Path and format of `settings.toml` | |
| 14 | | [0010](0010-ui-modes-toml-configuration.md) | Modes and `workspace.toml` merge | |
| 15 | | [0015](0015-editor-toml-syntax-highlighting.md) | TOML in built-in editor; external editor with rich tooling — conscious option | |
| 16 | | [0013](0013-command-surface-and-discoverability.md) | Palette, hotkeys in separate file | |
| 17 | | [0027](0027-small-team-focus-vs-public-maturity.md) | Axis B: standalone settings app and heavy onboarding — deferred backlog until triggers | |
| 18 | | [0026](0026-markdown-preview-surfaces-and-placement.md) | Some keys in merged `workspace.toml` — team canon in repo | |
| 19 | |
| 20 | ## Summary |
| 21 | |
| 22 | - **TOML-first** configuration; holistic settings UI — deferred. |
| 23 | - Point UI is a **facade** over the same file, not a second source of truth. |
| 24 | |
| 25 | --- |
| 26 | |
| 27 | ## Context |
| 28 | |
| 29 | Three facts hold at once in the product: |
| 30 | |
| 31 | 1. **Files** are the accepted storage canon: user `settings.toml`, bundle/repo for modes and chrome ([0010](0010-ui-modes-toml-configuration.md), [0028](0028-user-settings-toml-localappdata-and-secrets.md)). |
| 32 | 2. **UI** already changes some preferences (panel visibility, UI mode, providers, LSP, etc.) via model and save to disk. |
| 33 | 3. Discussion oscillates between **“TOML only”** and **“full settings screens”** — without a dedicated ADR it is easy to mix expectations: what is “real” truth, must every key have UI, is living in one file alone allowed. |
| 34 | |
| 35 | We need **one priority model**: disk and file format **define canon**; any UI that touches settings **must not** create a second truth — but **how much** screen UI (one button vs full “settings center”) is a separate product decision aligned with [0027](0027-small-team-focus-vs-public-maturity.md). |
| 36 | |
| 37 | --- |
| 38 | |
| 39 | ## Decision |
| 40 | |
| 41 | ### 1. Canon — **text configs on disk** (TOML where already adopted) |
| 42 | |
| 43 | - User preferences — **`settings.toml`** and related files under `%LocalAppData%\CascadeIDE\` ([0028](0028-user-settings-toml-localappdata-and-secrets.md)). |
| 44 | - Layout/metrics/mode presets — **`UiModes/`** and merge with **`.cascade/workspace.toml`** ([0010](0010-ui-modes-toml-configuration.md)). |
| 45 | - **Secrets** — separate file **`ai-keys.toml`**, not in `settings.toml` ([0028](0028-user-settings-toml-localappdata-and-secrets.md)). |
| 46 | |
| 47 | Extending keys — **model + file + serialization first**, then (as needed and on axis B) UI elements. |
| 48 | |
| 49 | ### 2. **Holistic** settings UI — **deferred** ([0027](0027-small-team-focus-vs-public-maturity.md)) |
| 50 | |
| 51 | **Holistic** means: **single page/center “all settings”**, separate **settings application**, large wizards — what [0027](0027-small-team-focus-vs-public-maturity.md) puts in deferred backlog until triggers (external contributor, RC, explicit pain, etc.). |
| 52 | |
| 53 | - This is **not** a ban on **point** toggles in the main window that exist or appear with features. |
| 54 | - This is **not** a ban on documenting “edit `settings.toml`” as a primary path for part of the audience. |
| 55 | |
| 56 | Net: **we do not invest now** in a full-screen discoverability settings product; **we do** live on TOML + docs + examples ([0027](0027-small-team-focus-vs-public-maturity.md)) until the queue says otherwise. |
| 57 | |
| 58 | ### 3. Point UI — when present, **facade of canon** (not a parallel database) |
| 59 | |
| 60 | When a control in the app changes a preference stored in `settings.toml` (or other canonical file): |
| 61 | |
| 62 | - it uses the **same** model (`CascadeIdeSettings`, etc.) as serialization; |
| 63 | - save goes through **`SettingsService.Save`** (and equivalents), **without** a shadow in-memory-only registry as source of truth; |
| 64 | - **no** policy “settings live only in UI and sometimes export” — see rejected alternatives. |
| 65 | |
| 66 | **Facade** in this ADR = **architectural rule** for existing or point-added UI: it reflects the file, does not replace it with a hidden copy. It is **not** a promise to **collapse** all config into rich UI in the next release (see §2). |
| 67 | |
| 68 | #### Why point UI if everything can be edited in TOML? |
| 69 | |
| 70 | Canon remains the **file**; point UI **does not** add a second truth and is **not** required for every user. |
| 71 | |
| 72 | - **Friction:** frequent actions (panel visibility, UI mode, etc.) are cheaper with a cockpit click than opening `%LocalAppData%\CascadeIDE\`, finding a snake_case key, saving, and sometimes restarting. |
| 73 | - **Rare one-off setup** is fine: e.g. enable external agent (ACP), set `cursor-agent` path — convenient from UI **or** the same key in `settings.toml` per docs; both entries hit one canon ([0016](0016-agent-client-protocol-external-agent.md)). |
| 74 | - “I never open settings UI, everything in TOML” is **valid and expected** for part of the audience; “I only opened UI once for one option” **does not** contradict TOML-first — alternative **entry**, not canceling the file. |
| 75 | |
| 76 | ### 4. **TOML-only** mode is first-class |
| 77 | |
| 78 | - Editing `settings.toml` (and other canonical files) manually, in the **built-in** editor or **external** ([0015](0015-editor-toml-syntax-highlighting.md)), is a normal workflow including for agents and machine diffs. |
| 79 | - Missing **holistic** settings UI (§2) is **not** a gap by itself. Missing UI for individual keys is also OK; a checkbox per model field is **not** mandatory ([0027](0027-small-team-focus-vs-public-maturity.md)). |
| 80 | |
| 81 | ### 5. When to add/extend **point** UI on top of TOML |
| 82 | |
| 83 | - High **frequency**, **safety** (secret masking), **live validation** — natural **point** control candidates (still §3 rules). |
| 84 | - Complex structures (MCP server JSON lists, etc.) — **as** UI if they reduce hand-editing errors; serialized result still lives in the canonical file field. |
| 85 | - **Holistic** “settings center” — only after [0027](0027-small-team-focus-vs-public-maturity.md) triggers or explicit pain, not default queue. |
| 86 | |
| 87 | ### 6. Session limitation (implementation honesty) |
| 88 | |
| 89 | - **`SettingsService.Load()`** typically runs at app start; **direct** edits to `settings.toml` on disk during a session **may** need restart for all subsystems to pick up values (unless a key gets explicit reload). This is **not** an argument against TOML-first; “reload settings” or a watcher is a **separate** task, not mixed with canon question. |
| 90 | |
| 91 | --- |
| 92 | |
| 93 | ## Consequences |
| 94 | |
| 95 | - New settings: design **key in model and file** first; **holistic** UI — not required and not default queue; point UI — as needed. |
| 96 | - Docs for users and agents: “how to change X” may start with **file path and key**; screens are optional convenience and alternate entry (§3, “Why point UI”). |
| 97 | - [0027](0027-small-team-focus-vs-public-maturity.md): deferred **settings app/center** aligns with this ADR: on-disk canon exists, rich UI later per triggers. |
| 98 | - Point UI **increases code volume** (bindings, VM, tests) — add consciously; alternative to form sprawl when a holistic center appears — see “Perspective” below. |
| 99 | |
| 100 | --- |
| 101 | |
| 102 | ## Perspective (not a implementation commitment) |
| 103 | |
| 104 | When a **holistic** settings center is no longer deferred per [0027](0027-small-team-focus-vs-public-maturity.md), consider **not** a pile of hand-built screens but a **dynamic form** built from the **same model** as `settings.toml` serialization (e.g. reflection/generator on `CascadeIdeSettings` + **metadata** layer). |
| 105 | |
| 106 | **Plus:** new model/TOML field — with metadata, appears in UI **without** N manual bindings; one canon. |
| 107 | |
| 108 | **Not “CLR type only”:** need labels, order, groups, hidden fields, localization; **secrets** stay outside this form ([0028](0028-user-settings-toml-localappdata-and-secrets.md)); **JSON blobs** and nonstandard fields — separate templates or multiline editor. |
| 109 | |
| 110 | This is **not** “build now” and **does not** cancel §2 (holistic layer still not default queue); recorded as **future direction** if a trigger pulls settings center from backlog. |
| 111 | |
| 112 | --- |
| 113 | |
| 114 | ## Rejected alternatives |
| 115 | |
| 116 | - **UI only, TOML as hidden export** — rejected: breaks transparency, diffs, agent workflow, “fixed in Notepad”. |
| 117 | - **Two sources of truth** (part registry, part TOML) without explicit canon — rejected: duplication and drift. |
| 118 | - **Mandatory UI for every `CascadeIdeSettings` field** — rejected: excessive for current axis B ([0027](0027-small-team-focus-vs-public-maturity.md)); TOML-only remains valid forever for advanced users. |
| 119 | |
| 120 | --- |
| 121 | |
| 122 | ## Change history |
| 123 | |
| 124 | <a id="adr0029-history"></a> |
| 125 | |
| 126 | | Date | Change | |
| 127 | |------|--------| |
| 128 | | 2026-04-08 | Holistic center deferred; subsection “Why point UI”; dynamic UI from model perspective; point UI = code weight. | |
| 129 | |