# hatch_menu — Modular Settings-Menu Navigation + Toggles `bin/hatch_menu/` drives the muse.ai Settings menu in the agent browsers. One module per part: a site change means patching one file. Exposed as `box chromebox permissions ...`; `bin/invite.py` usage reads ride the same tree. ## Layout ```text bin/hatch_menu/ __init__.py package surface (dialog + mouse + toggles fns) mouse.py trusted input: real_click, escape, close, MouseError dialog.py open_settings (retried), goto_tab, click_row, describe_rows, go_back, dialog_text, TAB_NAMES controls.py radio/switch list + set (verify, else trusted click, verify again) toggles.py toggle registry + sessions: resolve/get/set/list, describe_tab, MenuError tabs/ __init__.py TAB_MODULES (10 tabs, uniform describe(ws)) permissions.py defaults radios, website modes, protocols, advanced switches, counts, tasks general.py usage parse, theme, redeem entrypoint data_controls.py model-improvement switch (rest read-only) connectors|wallet|secure_store|messaging|devices| help_support|legal.py read-only inventories ``` Dependency order (no cycles): `mouse` <- `dialog` <- `controls` <- `tabs/*` <- `toggles`. Tab modules own their contracts (headings, labels, slugs, modes); `toggles.py` only addresses them. ## Toggle addresses Static: `permissions.connector_defaults`, `permissions.web_access` (`auto_allow`/`always_ask`); `permissions.advanced.transparent_proxy|tls_interception| sni_mismatch_rejection`, `data_controls.ai_improvement` (`on`/`off`); `general.theme` (match/default/blue/purple/pink/orange/green/ beige/monochrome). Families: `permissions.websites:` (`Allow`/`Ask`/`Deny`), `permissions.protocols:` (`on`/`off`; slugs discovered live, e.g. `mcp-sse`, `mcp-streamable`, `agent-skills`, `mcp-apps`, `mcp-oauth`). Every `set` verifies in place and reads back through a fresh session; readback mismatch reports failure, never partial success. Caller errors (unknown node/toggle/tab/value) raise `MenuError` before any CDP traffic. Transport failures return `{"ok": False}`. ## CLI ```bash box chromebox permissions list [--tab TAB] [--json] box chromebox permissions get [--json] box chromebox permissions set [--json] box chromebox permissions describe # JSON inventory ``` Exit 2 on caller errors, 1 on transport/unreadable toggles. ## Patch guide | Site change | Patch | |---|---| | Dock button / dialog open flow | `dialog.py` (`open_settings`) | | Radio/switch mechanics | `controls.py` | | Permissions headings, modes, slugs, adv labels | `tabs/permissions.py` | | Usage text, theme values | `tabs/general.py` | | Data-controls switch label | `tabs/data_controls.py` | | New settable toggle | tab module contract + `toggles.py` registry row | | Trusted-click transport | `mouse.py` | `describe ` dumps a tab's live inventory for debugging. ## Provenance Contracts come from live read-only DOM recon (2026-10-06): Permissions radios `auto_allow`/`always_ask`, Websites Allow/Ask/ Deny chooser (real click to open), 8 protocol switches, Advanced section (Transparent proxy off, TLS interception off, SNI mismatch rejection on), Data-controls single switch, General theme radios. Radix menus need real `Input.dispatchMouseEvent` press+release with monotonic CDP ids; synthetic clicks fail. Recon never touches Reset. ## Tests `tests/test_hatch_menu.py` (mocked CDP, per-module): mouse/trusted-clicks, dialog open-retry/tab/row flows, control verify-then-fallback, registry resolution + readback mismatch, tab contracts on live-captured fixtures. `tests/test_invite.py` covers the invite shims + flat usage parse.