11 KiB
DOM Reference: Settings, Profile & Dock Rail
Box is the main surface. All operator work goes through Box (box.muse-dev.online). The web UI,
boxCLI, and agents share the same API endpoints. No UI-only powers.
Inspected live via CDP on the opm browser (warp-opm netns, CDP 9440), 2026-10-04. Re-verified 2026-10-04 across all three fleet nodes (muse 9410, pip 9420, opm 9440). Structure only — no credential, token, or personal values are recorded here.
Related: DOM-CHAT-PANEL.md (chat panel), DOM-MESSAGES.md (messages),
DOM-PAGE-STRUCTURE.md (page states).
1. Dock rail
The left vertical nav rail. Container:
<div data-testid="hatch-dock-rail" class="relative flex h-full">
Rail items (top to bottom)
| # | Selector | Tag | aria-label |
data-pel-click |
Notes |
|---|---|---|---|---|---|
| 1 | [data-testid="hatch-nav-chat"] |
<a href="/"> |
Chat (unstable — see notifications doc) |
chat_tab_click |
The chat/message button from the user's screenshot. Navigates /thread/new → https://muse.ai/. See "chat activation" below. |
| 2 | [data-testid="hatch-nav-search"] |
<button> |
Search |
quick_search_nav_click |
Opens quick-search dialog [data-testid="hatch-quick-search-frame"] (heading "Search Muse"). |
| 3 | (none) | <button> |
Get the Muse app |
mobile_app_upsell_click |
App download upsell. No data-testid. |
| 4 | [data-testid="hatch-dock-more"] |
<button> |
Settings |
settings_menu_open_click |
Opens the settings menu (radix menu). Bottom of rail (div.mt-auto). |
Mid-rail system items (verified 2026-10-04, all three nodes) — DIVs, not
buttons, between the search button and the app upsell:
data-testid |
aria-label |
|---|---|
hatch-nav-system-item-66656564 |
Feed |
hatch-nav-system-item-6964656173 |
Ideas |
hatch-nav-system-item-676f616c73 |
Goals |
hatch-nav-system-item-6c696272617279 |
Library |
(The hex suffixes decode to ascii: feed, ideas, goals, library.)
Parent chain of the settings button (4 levels):
div[data-testid="hatch-dock-rail"].relative.flex.h-full
> div.relative.z-10.flex
> div.mt-auto.flex.flex-col
> button#radix-_[data-testid="hatch-dock-more"].hatch-dock-reveal-item.group.relative
Key attributes on the button:
<button type="button"
aria-label="Settings"
data-testid="hatch-dock-more"
aria-haspopup="menu"
aria-expanded="false" <!-- RELIABLE after 2026-10-04 re-verify: "true" when menu open -->
data-state="closed" <!-- unreliable: stays "closed" even when menu is open -->
data-pel-click="settings_menu_open_click">
Automation note (updated 2026-10-04):
data-statedoes NOT reflect the real open state (stays"closed").aria-expanded, however, does: verified"true"on opm with the menu open (earlier claim that it stays"false"was wrong — possibly a timing artifact). Belt and braces: detect the open menu by counting[role="menuitem"]elements (> 0means open). Synthetic.click()does not open the radix menu; use real mouse events via CDPInput.dispatchMouseEvent(mousePressed+mouseReleasedat the button center). The button toggles, so click only when[role="menuitem"]count is 0.
Chat activation via hatch-nav-chat
Clicking [data-testid="hatch-nav-chat"] from the stripped /thread/new state
navigates to https://muse.ai/ and the chat switcher appears (~1s). This is
the reliable "activate chat" primitive — see the _ensure_chat_active()
logic in muse-chat-api.py (priority: compose → switcher → nav-chat).
aria-label on this link is unstable ("Chat" vs "Chat, N notification");
always match on the data-testid.
2. Settings menu (dock "more" menu)
Radix menu rendered in a popper. Items are DIVs with role="menuitem"
(verified 2026-10-04 — not buttons), no data-testid:
| Text | data-pel-click |
Action (observed) |
|---|---|---|
| Keyboard shortcuts | keyboard_shortcuts_nav_click |
No dialog under automation (see §5) |
| Download apps | mobile_app_upsell_menu_click |
— (not opened) |
| Report an issue | bug_report_nav_click |
— (not opened) |
| Settings | settings_nav_click |
Opens the Settings dialog (§3) |
Menu container selectors (either may match):
document.querySelector('[role="menu"]')
document.querySelector('[data-radix-popper-content-wrapper]')
Find a menuitem reliably:
[...document.querySelectorAll('[role="menuitem"]')]
.find(m => m.getAttribute('data-pel-click') === 'settings_nav_click')
3. Settings dialog
A radix dialog (div[role="dialog]", id like radix-_r_10g_; the id suffix
is random per render — do not hardcode it).
div#radix-_<role=dialog>
- Heading is an
H2with textSettings(noth1). - Layout: left nav column + right content column.
3a. Left nav (section buttons)
Plain <button> elements, no data-testids. In order:
General
Connectors
Wallet
Secure store
Permissions
Messaging channels
Devices
Data controls
Help & support
Legal info
Log out ← the sign-out control; no confirmation dialog observed at open
Close
3b. General section
Headings (all h2, in order): General, Meta Account, Usage, Appearance.
Meta Account — row labeled Password, security, personal details
(structure only; not opened).
Usage — plan and quota rows (structure only, values not recorded):
| Row | Notes |
|---|---|
| Plan name + weekly reset line | e.g. plan tier + "Weekly limit resets on " |
| Usage bar(s) with percentage | at least two bars observed (weekly + additional) |
Upgrade button |
data-pel-click="settings_general_upgrade_click" |
Language |
control follows the usage block |
Appearance — theme + accent color:
| Control | Label source | Selection state |
|---|---|---|
<button aria-label="Light"> |
aria-label (icon-only, no text) |
aria-pressed |
<button aria-label="Dark"> |
aria-label |
aria-pressed |
<button aria-label="System"> |
aria-label |
aria-pressed="true" on opm (verified) |
9× <input type="radio"> |
aria-label, not innerText |
checked |
Radio aria-labels in order: Match my avatar (checked on opm), Default,
Blue, Purple, Pink, Orange, Green, Beige, Monochrome.
All share one radio group (name is random per render, e.g. _r_184_).
3c. Profile / avatar
- Avatar image:
<img>with emptyalt,srcpresent (value not recorded). Nodata-testidon the img. Edit avatar and namebutton (aria-label="Edit avatar and name",<button>, nodata-testid, id is a randomradix-_R_…value).
Correction 2026-10-04: the button is not a descendant of
div[role="dialog"]. While the settings dialog is open it renders as a sibling overlay inside[data-testid="hatch-status-panel-sliding-surface"](nearest testid ancestor at depth 10; button rect ≈ (622,141), 32×32 on a 780px-wide viewport). It appears only while the dialog is open and is gone after Escape. Match it byaria-label, never by dialog containment. The 3-level parent chain below is still accurate:
div.pointer-events-auto.absolute.z-20
div.group-has-data-hatch-avatar-media-loading/status-avatar:hidden > span.contents > button[aria-label="Edit avatar and name"].inline-flex.shrink-0.cursor-pointer
### 3d. Other sections (not opened)
`Connectors`, `Wallet`, `Secure store`, `Permissions`, `Messaging channels`,
`Devices`, `Data controls`, `Help & support`, `Legal info` were not opened
during mapping (each is a left-nav `<button>`; clicking one swaps the right
content column). `Secure store` / `Wallet` likely contain credential-adjacent
UI — map with care, structure only, never values.
---
## 4. Account switching
**No multi-account switcher was observed** in the settings dialog or dock
rail. The only account control found is the `Log out` button in the settings
left nav. Each Muse account runs in its own isolated browser profile
(`muse`, `pip`, `646`, `opm` nodes), so in this fleet account switching
happens at the profile level, not inside the app UI.
---
## 5. Keyboard shortcuts modal
Menu item exists:
```javascript
[...document.querySelectorAll('[role="menuitem"]')]
.find(m => m.getAttribute('data-pel-click') === 'keyboard_shortcuts_nav_click')
Clicking it via automation (menuitem .click() after opening the dock menu
with real mouse events) produced no [role="dialog"] within 3s and no
URL change. Re-tested 2026-10-04 with real mouse events
(Input.dispatchMouseEvent press+release on the menuitem): still no dialog
within 3s; the menu simply closes. The menuitem carries no kbd hint in its
markup (icon SVG + text "Keyboard shortcuts" only).
Status: selector documented, modal content not captured — needs a headed/manual pass.
6. Quick reference: reliable selectors
// Dock rail
'[data-testid="hatch-dock-rail"]'
'[data-testid="hatch-nav-chat"]' // chat button (stable; aria-label unstable)
'[data-testid="hatch-nav-search"]' // search
'[data-testid="hatch-dock-more"]' // settings menu trigger
// Settings menu (after real mouse click on hatch-dock-more)
'[role="menuitem"]' // count > 0 => menu open
'[data-pel-click="settings_nav_click"]'
'[data-pel-click="keyboard_shortcuts_nav_click"]'
'[data-pel-click="bug_report_nav_click"]'
'[data-pel-click="mobile_app_upsell_menu_click"]'
// Settings dialog
'div[role="dialog"]' // id is random per render
'button[aria-label="Edit avatar and name"]'
// Search dialog
'[data-testid="hatch-quick-search-frame"]'
7. Automation recipes
Open the settings menu:
// 1. real mouse click at button center (synthetic .click() does NOT work)
const b = document.querySelector('[data-testid="hatch-dock-more"]');
const r = b.getBoundingClientRect();
// CDP: Input.dispatchMouseEvent mousePressed + mouseReleased at (r.x + r.width/2, r.y + r.height/2)
// 2. verify: document.querySelectorAll('[role="menuitem"]').length > 0
// (the button toggles — only click when count is 0)
Open the Settings dialog:
[...document.querySelectorAll('[role="menuitem"]')]
.find(m => m.getAttribute('data-pel-click') === 'settings_nav_click')
.click();
// dialog appears in ~2s: document.querySelector('div[role="dialog"]')
// heading: [...document.querySelectorAll('h2')].find(h => h.innerText.trim() === 'Settings')
Close any dialog: Escape keydown (works for the settings dialog).