Reference Settings — full reverse-engineer (2026-06-23)

Archived on 2026-07-13. This reverse-engineering snapshot is provenance, not the current Settings contract.

Cross-checked by 4 parallel Explore agents on the extracted bundle at /tmp/qoder-asar/out/renderer/assets/.

This note captures the reference's Settings module so future Maka PRs can align without re-doing the dig. Naming hygiene applies: do not surface the reference product name in code, commits, or end-user copy.


1. Shell shape

Settings is a full-pane modal that takes over the workspace area. It is NOT a small overlay sheet.

  • role="dialog" + aria-modal="true"
  • Marker attributes: data-modal="agents-settings", data-canvas-dialog="true", data-settings-layout="page"
  • Outer shell:
    flex h-full min-h-0 w-full flex-col overflow-hidden bg-background select-none
    
  • The rest of the chat surface stays visible behind a subtle backdrop; the modal does not float over a blurred mask — it occupies the canvas.

Two-rail layout

RegionWidth / sizingNotes
Nav railw-[256px] shrink-0Left side, bg-transparent, full height
Contentflex-1 min-w-0 overflow-hiddenRight side, scrolls on the inner column
Gapvar(--agents-content-area-gap) 4pxMargin between rail and content plate

Content pane class: agents-settings-wide-content:

.agents-settings-wide-content {
  background: var(--agents-content-area-bg);
  margin: var(--agents-content-area-gap)
          var(--agents-content-area-gap)
          var(--agents-content-area-gap) 0;
  border-radius: var(--agents-content-area-radius); /* 6px */
}

Content body inner wrapper (where the page lives):

mx-auto min-h-[200px] max-w-3xl pb-16 pt-10

max-w-3xl = 48rem / 768px. That's the optical reading column for any settings page body.

Responsive

BreakpointBehavior
≥ 1200pxTwo-rail (256px rail + content)
900–1199Two-rail, tightened
< 900pxCompact: rail collapses; header shows back-arrow + title

2. Nav rail

The rail is a flat vertical list (no group headings — purely flat).

Items shown to the end user (in order)

  1. preferencesPreferences (the big aggregator)
  2. profile — Profile / account
  3. systemSystem (intentionally near-empty placeholder)
  4. keyboard — Keyboard shortcuts
  5. vm — Secure workspace / VM mode
  6. experimental — Experimental flags
  7. permissions — System capability toggles
  8. connector — Integrations / connectors
  9. appshot — App snapshot (macOS only, gated by platforms: ["darwin"])

Hidden / dev-only tabs

appearance (handled via the Preferences page itself), privacy, debug, hiddenConnector, awareness, appUpdate, models, customModels, commands, agents, worktrees, quickpick, voiceInput, wechat, beta, channels, legokit, archived — all exposed: false.

Tab registry lives in index-C02cm0ok.js around offset ~213400 (look for Su=[]).

Nav-row recipe

<!-- inactive -->
<button class="squircle-md text-text-secondary/80
               hover:bg-[var(--settings-nav-row-selected-bg)]
               hover:text-text/80">
  <Icon size= />
  <span>Label</span>
</button>

<!-- active -->
<button class="squircle-md
               bg-[var(--settings-nav-row-selected-bg)]
               text-text/80"></button>
  • Icon library: Lucide
  • Active state is a fill (not border / left-bar), with --settings-nav-row-selected-bg = var(--color-fill-secondary)
  • Typography: text-sm (14px), normal weight at rest; no weight bump on active (color/background carry the state)
  • Padding (educated from sibling rows): px-4 py-3
  • Gap between glyph + label: gap-3
  • Border radius: squircle-md (custom corner, not pure rounded-md)

3. Per-tab content inventory

3.1 Preferences (the kitchen sink)

Globals offset ~76380–80000. This single tab carries the bulk of the end-user controls:

ControlTypeNotes
LanguageselectUI locale
Extended ThinkingswitchBigger reasoning budget, disables streaming
Launch at Login (autoLaunch)switchAuto-start
Close Window Behaviorradio / selectAsk / Minimize-to-tray / Quit
Desktop NotificationsswitchNative OS notifications
Sound NotificationsswitchAudio on task completion
Include Co-Authored-ByswitchAdds Co-authored-by: trailer to git commits
Quick Switch (Ctrl/Cmd+Tab)radioWorkspaces vs Agents
Auto-advance after archiveradioNext / Prev / Close
Default Mode (new agent)radioAgent / Plan
Preview Mode (artifactPreview)radioNew window / Right sidebar
Expand tool calls by defaultswitchTool-block collapsed vs expanded
Show tool steps in IM channelsswitchWhether bot-reply surfaces include tool-call sub-steps
Tool execution limitnumber inputSoft pause when one turn exceeds N tool calls
Keep System Awake (preventSleep)switchWhile Agent works
Network Proxyproxy blockSystem / Manual; URL input + test button + scheme validation
Chat Settings (sub-section)compositeTheme brightness, interface style, glass effects, font face, font size, chat width

Key insight: reference does NOT split “system-level” toggles (autoLaunch / preventSleep / notifications / proxy / closeWindowAction) into a separate System tab. They live alongside chat/agent toggles in ONE long Preferences page.

3.2 System

Title only. No fields. Placeholder for future use. The page exists in the nav but its body is intentionally empty / “to be defined.” Confirmed by walking the bundle.

3.3 Profile

Two sections:

  • Avatar: glyph (first char or emoji) + background color (preset palette of ~11 tones)
  • Account & Subscription: email (copy), Account UID (copy), product UUID (copy), subscription tier (read-only), pricing-page link, logout

3.4 Appearance (appearance i18n key — actually rendered inside

Preferences in production)

ControlTypeOptions
Interface themeselectSystem pref / Light / Dark / Light Glass / Light Clear (win) / Dark Glass / Dark Clear (win) / Classic Dark / Parchment Light / Parchment Dark / From editors
Light variantselectPer-mode theme
Dark variantselectPer-mode theme
Workspace icon in sidebarswitchProject glyph in the sidebar workspace list
Always expand to-do listswitchFull vs compact to-do view

3.5 Keyboard

  • Search field across all shortcuts
  • Per-action row with primary + alternative binding
  • “Reset all to defaults”
  • Categories: General / Chats (workspaces) / Agents
    • General: Show shortcuts / Open settings / Toggle sidebar / Undo archive
    • Chats: Quick switch
    • Agents: Create new task / Search all tasks / Search in current task / Prev tab / Next tab / Focus input / Toggle input focus / Send / New line

3.6 VM (Secure workspace)

Brief description: “dedicated space on your computer for running tasks — faster, more reliable, on-device.” Enable/disable toggle.

3.7 Experimental

Beta feature toggles. Per-flag rows; roster managed in the renderer component, not visible as a literal array in the bundle.

3.8 Permissions

“System permissions QoderWork needs on this Mac.” Capability rows (filesystem / network / mic / screen recording / accessibility) with “granted / not granted” status and a “request” CTA.

3.9 Connector

Integrations with external apps. Builtin connectors / market connectors / custom connectors. Each row: brand glyph, status, enable toggle, “configure” button.

3.10 App Snapshot

macOS-only. Frontmost-app screenshot capture for chat context. Needs Accessibility + Screen Recording perms. Permission status row + capture preview.


4. Repeating visual patterns inside a page

Reference does NOT use bordered card containers around groups of controls. The default presentation is a flat row list inside the max-w-3xl column.

4.0 Content-column padding — WAWQAQ msg 2c810f2d 2026-06-23

WAWQAQ called out the left/right whitespace as visibly wider in reference than in Maka. Concrete numbers from a second RE pass:

  • The content column is mx-auto max-w-3xl pt-10 pb-16 (= 768px wide, 40px top, 64px bottom). No explicit px-N is applied inside the column — the side whitespace comes from the column NOT filling the right pane.
  • At the typical desktop window width (~1280px viewport, 256px nav rail), the right pane is ~1024px. A 768px centered column leaves ~128px of whitespace on each side. That's the “wider padding” effect.
  • Inside each row, padding is px-5 py-4 (20px / 16px). Rows do NOT carry their own border, background plate, or shadow — separation is pure spacing.

Maka delta found 2026-06-23:

  • .settingsStructuredPage had gap: 16px but NO max-width / margin: 0 auto — rows stretched to fill the right pane. Fixed to max-width: 768px; margin: 0 auto; padding: 40px 24px 64px.
  • .settingsFormRow had border-bottom: 1px solid var(--border) and padding: 6px 0 — both wrong. Reference uses spacing-only and px-5 py-4. Fixed to padding: 16px 20px, no border-bottom.
  • .settingsRow was sharing .providerCard chrome (bordered, tinted, lifted). Provider cards keep their chrome (they ARE cards); .settingsRow flattened to a flex row.
  • Label was 12px / 600 weight; bumped to 14px / 500. Sub-text 11px → 12px. Matches reference text-sm font-medium + text-xs text-text-quaternary.

4.1 Row

flex items-center gap-3 px-4 py-3   /* group */
  ├── label column
  │   ├── truncate text-sm font-medium text-text     (title)
  │   └── mt-0.5 truncate text-xs text-text-quaternary (hint)
  └── control (right-aligned)
  • No border / no card background per row by default
  • Visual separation between rows is achieved by spacing alone (no border-bottom)
  • Hover state moves via the parent .group (e.g., shows a kebab menu)

4.2 Sub-section heading inside a tab

text-sm font-semibold text-text
mb-4

4.3 Switch

  • ~20×20px wrapper, rounded-md
  • On: bg-primary/20 ring-1 ring-primary/40 scale-[0.97]
  • Off: subtle gray fill (bg-gray-100 dark:bg-neutral-600) with inset shadow
  • Transition: transition-all duration-200

4.4 Input

w-full px-3 py-2 text-sm bg-background border rounded-md
border-border-tertiary/80
focus:outline-none focus:ring-2 focus:ring-primary/50
  • Error: border-error-border
  • Password / icon suffix: pr-9

4.5 Button

  • Primary: bg-primary text-primary-foreground
  • Secondary: bg-muted text-foreground
  • Outline: border border-border text-foreground hover:bg-muted
  • Destructive: text-error hover:bg-error-bg
  • Icon-only sizes: size-7 rounded-md (28px square), size-8 rounded-full (32 round)

4.6 Chip / badge

rounded bg-fill-tertiary px-1.5 py-0.5 text-[10px] font-medium text-text-tertiary

4.7 Content scroll

The page body owns its scroll:

min-h-0 flex-1 overflow-y-auto scrollbar-none

Custom scrollbar is hidden. The inner content column has pb-16 bottom padding so the last row never hugs the modal edge.


5. Tokens used inside Settings

TokenValue
--agents-content-area-bgvar(--color-bg-container)
--agents-content-area-gap4px
--agents-content-area-radius12px
--agents-layout-bgvar(--surface-canvas) (flat neutral shell — DO NOT paint a 172deg gradient here, see warning below)
--settings-nav-row-selected-bgvar(--color-fill-secondary)

⚠️ DO NOT paint a 172deg gradient on the layout/shell background.

The RE notes here historically said --agents-layout-bg is linear-gradient(172deg, var(--color-fill-tertiary) 19.61%, var(--color-bg-container) 81.35%). That value was an artifact of the bundle CSS we copied, not what the live reference product actually paints. WAWQAQ has called this out four times in a row (msgs 1e693dee / 5d3b10e5 / 486b5611 / 4a1b8c13) — “谁让你他妈的用渐变的啊? 参考实现就没有啊”. Every time we re-added the gradient because some atlas/RE note claimed it was canon.

Source-side enforcement: apps/desktop/src/main/__tests__/chat-chrome-no-gradient-contract.test.ts fails if any of .appFrame, html[data-os="darwin"] .maka-session-panel, or the floating panel reintroduces a gradient / border-right / smaller-than-12px radius. If a future RE iteration finds a new place where the reference product genuinely does paint a gradient, please update the contract test with the new exception in the same PR, don't silently lift the assertion.

Use a flat neutral shell (var(--surface-canvas)) behind the white content surface. Do not collapse the shell to the same white as the content card: that removes the visible lower radius and lets the bug come back even without a border or gradient.

Rendered-pixel enforcement: after capturing sidebar-long-sessions/light-1280-motion, run npm --workspace @maka/desktop run screenshots:chat-chrome:check. It verifies the actual PNG has a visible shell/content delta, no dark one-pixel seam, and readable bottom surface corners.

Surface radius is 12px (was historically noted as 6px). 6px was geometrically there but optically invisible — bottom corners of the floating content card didn't read against a same-color shell.

Color tokens consumed inside settings:

  • --color-text (primary text)
  • --color-text-secondary
  • --color-text-tertiary (hints)
  • --color-text-quaternary (de-emphasized)
  • --color-border (strong divider)
  • --color-border-tertiary (input borders)
  • --color-fill-secondary (active row fill)
  • --color-fill-tertiary (chip background)
  • --color-bg-container (page surface)
  • --color-primary, --color-primary/20, --color-primary/40 (focus, switch on, ring)

6. Routing, state, behaviors

  • Active tab is stored in the URL: ?view=settings&tab=preferences. No localStorage for the active tab — round-tripping the URL restores the page.
  • Deeplink scheme: external triggers can deep-link to a specific tab: qoder-work://settings/preferences. Maka's equivalent could be maka://settings/<tab>.
  • Default tab when opened with no tab param: preferences.
  • Modal close is escape-key + click-outside backdrop; focus is trapped inside [role="dialog"].
  • Telemetry: settings_tab_view fires when a tab is selected; settings_heartbeat ticks every 300s with a feature-flag snapshot.
  • Saves: per-control, no explicit batch / “save” button visible. Renderer dispatches IPC writes per change; toasts surface failures.

7. Implications for Maka

This RE matters because WAWQAQ's ask — “add a 系统设置 section” — is ALMOST CORRECT but the deeper truth from the reference is:

Reference does NOT scatter system-level toggles into their own narrow pages. It collapses them into ONE long Preferences page, and reserves a near-empty system tab for future expansion.

Maka today has 17 nav items in Settings (some of them — 网络, 健康, 开放网关, 语音模型, 每日回顾, 记忆 — are single-purpose pages that mirror exactly the “wasteful single-purpose page” pattern WAWQAQ flagged for 网络).

The closer-to-reference move is to consolidate, not add another section. Concrete proposal:

Proposed consolidated Maka Settings nav (target: ~9 items)

GroupItemHolds
基础通用Aggregator: 隐身模式, 启动行为, 新对话模式, 默认模型, 通知, 网络代理, 保持唤醒, 自动更新, 关闭窗口行为
基础外观个性化 + theme + palette + font (merge 主题 + 个性化)
AI模型Provider connections + OAuth + per-model config
AI记忆与回顾Merge 记忆 + 每日回顾
AI语音与网关Merge 语音模型 + 开放网关
集成机器人对话Telegram / WeChat / Slack bot config
集成联网搜索Tavily provider config
数据/系统数据Export / import / wipe
数据/系统权限与能力Capability toggles + filesystem allowlist
其他健康Diagnostic / status / logs
其他关于Version + license + acknowledgements

Specifically: drop the standalone 网络 page; move proxy into 通用. That‘s the minimum WAWQAQ asked for, but ride the same PR to merge 主题 + 个性化 into 外观 per reference, since 外观 is reference’s canonical name for that grouping.

Settings page-body recipe to copy

For ANY settings page body, switch to:

  • max-w-3xl mx-auto pt-10 pb-16 inner column
  • Flat row list (flex items-center gap-3 px-4 py-3 per row)
  • text-sm font-medium title + text-xs text-text-quaternary hint
  • No bordered card around row groups
  • Sub-section heading: text-sm font-semibold mb-4
  • Switches / inputs / chips per §4 above

This is the visual “reference 真好看” pattern WAWQAQ asked us to study — the page is uncluttered because rows have NO chrome, only spacing.


8. PR plan suggestion

Two PRs, ship in sequence:

PR-SETTINGS-ALIGN-IA-0 — Information architecture consolidation

  • Drop standalone 网络 page; fold proxy into a “网络代理” sub-section of 通用
  • Merge 主题 + 个性化外观
  • Merge 记忆 + 每日回顾记忆与回顾
  • Merge 语音模型 + 开放网关语音与网关
  • Update SETTINGS_NAV + section render switch + all deeplinks (maka://settings/...)
  • Pin via contract test: nav id allowlist + deeplink mapping

PR-SETTINGS-PAGE-BODY-0 — Visual pattern conversion

  • Convert every page body from settingsStructuredPage / SettingRow card chrome to the flat-row + max-w-3xl recipe
  • Add .maka-settings-row, .maka-settings-page primitives in styles.css
  • Sweep all SettingsPage components to use them

Tackle them in this order so the IA stops shifting while we're polishing the bodies.