Skip to content

Browser pane

The browser pane is a pinned widget (Browser, view browser). It embeds a native CefBrowserViewnot an iframe. The pane’s HWND sits as a child window of the AgentMux frame, which is why links, popups, OAuth flows, and DRM content all behave like they would in a regular Chromium tab.

  • Click the Browser widget in the top bar (pinned by default).
  • Right-click any pane header → Browser.
  • Programmatically: pane.open with view: "browser", meta.url: "https://example.com".

Blank-spawned browser panes default to https://agentmux.ai. To get a literally blank pane, pass meta.url = "about:blank" explicitly.

ControlAction
← / →Back / forward — enabled state syncs from the backend
Reload current page
Address barEnter URL or search query — defaults to a search if it doesn’t parse as a URL
GoNavigate to the address-bar value

Title and favicon update from the embedded page automatically. Title is fetched from the page’s <title>; favicon falls back to the globe icon if the page doesn’t expose one.

The host exposes the browser pane’s lifecycle via these CEF commands (invoked through invokeCommand from the renderer):

CommandPurpose
browser_pane_createInstantiate the CefBrowserView; called on first mount
browser_pane_navigateLoad a URL
browser_pane_resizePropagate Solid layout changes to the HWND
browser_pane_reloadReload the current page
browser_pane_focusExplicit focus handoff after a click
browser_pane_closeTear down on pane close

The frontend BrowserViewModel shows the canonical sequencing.

The address bar (a DOM input) and the embedded CefBrowserView (a child HWND) compete for keyboard focus. The pane’s HWND intercepts clicks at the Win32 level, so the renderer does not see DOM click events from inside the page. Two consequences:

  • Clicking the address bar releases pane focus to the input. IME state is preserved.
  • Clicking back into the pane fires browser_pane_focus to hand keyboard focus back to the embedded HWND.

The address-bar input uses onMouseDown (not onMouseEnter) for the click-to-focus handoff. Hover-focus loops were the original failure mode this design corrects.

When you click inside the browser pane, the host fires browser-pane-clicked over the JS bridge. The frontend’s browser-pane reducer (slice #9) dispatches a Clicked command, which emits a focus-block event. A saga turns the event into refocusNode(blockId), updating the layout’s focus state so keyboard shortcuts and split commands target the clicked pane.

DOM clicks don’t bubble out of the embedded HWND, so the explicit IPC is necessary. See Reducer stack for the broader pattern.

When a page in the browser pane requests HTTP Basic Auth (or similar challenges), the credential prompt appears as a modal scoped to just this pane, not the whole app. Other panes stay interactive; you can keep typing in a terminal next door while the auth challenge is up. The pane that’s locked is the only one that goes modal.

This is the same ModalLayer primitive the agent launch modal uses, parameterized over scope — the browser pane wraps its embedded CefBrowserView in a per-pane ModalLayer, so the lock region matches the pane bounds exactly. See SPEC_MODAL_LAYER_SCOPING for the underlying design.

Each browser pane owns its own:

  • URL and navigation history (back/forward stack)
  • Title, favicon
  • Loading / error state
  • Scroll position (restored across pane moves)

State persists across pane moves between tabs and windows — drag a browser pane to a new tab and the page keeps loading.

The browser pane is the subject of the in-flight reducer slice migration (frontend slice #9). Recent commits (e3173631, ba843501, 4cd960b2, 540b1f4a) move per-pane state cells (closed/loading/error → canGoBack/canGoForward → title) into the reducer model. See Reducer stack for the slice list and migration plan.