ADR 0170: Ship the work-panel browser as a bundled plugin over public CDP
- Status: Accepted
- Date: 2026-09-06
- Deciders: PI-Desktop core
- Related: ADR 0019 · ADR 0104 · ADR 0105 · 07-plugins
Context
The work-panel browser was a host-built launcher row (HEADER_TOOLS) plus a Main-owned WebContentsView guest. Files already proved that a first-party surface can ship as a bundled plugin on the public contributes.views channel. Users also need the whole browser — chrome, preview, and agent CDP — to be optional the same way: enable/disable on the Plugins page, never uninstallable.
The plugin page cannot be the browser. Plugin views are sandboxed, have webviewTag: false, and are confined by net.domains. Arbitrary http(s) and workspace files, plus Chrome DevTools Protocol, have to stay on a host-owned guest.
Decision
pi.browseris a bundled plugin inapps/desktop/resources/plugins/, enabled by default, disableable, not uninstallable. It contributes viewbrowser(icon tokenbrowser, order 10) and registers the agent toolBrowser.- The guest
WebContentsView(persist:work-browser) and debugger stay host-owned. Plugin chrome is a normal plugin view. The guest is stacked on a content-relative hole the chrome reports throughpi.browser.setBounds. browser.cdpis a public permission (high).pi.browser.*is a public host API. Any plugin that declares the permission may call it. Bounds are clamped to the calling plugin view so a guest cannot cover chat/composer.- Raw CDP is allowlisted and deny-by-default. Cookie, storage, target, and network-interception methods are refused. No DevTools websocket is exposed.
- Host
BrowserPreviewremains a thin facade (Plan/subagent name stability). It errors ifpi.browseris disabled; otherwise it loads the workspace file into the guest when that session's chrome is visible and reveals the plugin view. Plugin CDP stays Agent-only (plugin_*). - v1 is a singleton guest. Session locations are remembered and rebound when the originating conversation's plugin tab is shown (D142). Background sessions do not steal the visible guest.
This supersedes ADR 0105 clause 4 (Browser remains a host-built launcher) and the host-launcher clause of ADR 0019. Guest ownership and navigation policy are unchanged. ADR 0108's "Browser as the host-built tool" clause is likewise superseded: the panel's launchable surfaces are plugin views.
Consequences
- Disabling
pi.browserremoves the launcher row, agent CDP, and guest. URL chips fall back toopenExternal.BrowserPreviewfails closed. - Third-party plugins with
browser.cdpshare the same guest; last chromesetBoundswins. - Plan still sees
BrowserPreview. The Browser plugin tool is also visible in Plan/Goal for the fourplanSafeActions(navigate,snapshot,screenshot,console); click/fill/evaluate/cdp stay Agent-only (ADR 0211).
Alternatives considered
Load the web page inside the plugin view
Rejected: would require webviewTag, a wildcard net.domains, and attaching CDP to the wrong WebContents.
Private host APIs only pi.browser may call
Rejected: the Files bar is that first-party features prove the public channel.
Keep React BrowserTab chrome and only plugin-ize the launcher
Rejected: that is not “the whole default browser is a plugin.”