Skip to content

[Architecture] Use one protected browser surface for users and agents #236

Description

@fettpl

Audit metadata

  • Priority: P1
  • Estimated effort: M
  • Implementation risk: MED
  • Category: bug
  • Evidence baseline: 07be5be7ce69bea0c3118744ab90d148b010fce0 (origin/main on 2026-07-17)

Dependencies

  • P1 proposal 040 — Enforce DNS-pinned browser policy across redirects and subresources. Included in the current P1 issue wave.

Description and impact

On desktop, the visible browser is an Electron <webview>, while agent browser
tools drive a separate server-side Chromium page. The user can be looking at one
URL/state while the agent reads or clicks another, contradicting the UI promise
that they share a surface. The web build already uses the CDP screencast; using
it everywhere removes duplicated state and makes the security policy auditable.

Current state

  • frontend/src/features/agent/ui/agent-browser.tsx:31-45 defines a custom
    Electron webview type and lines 122-166 dispatch desktop navigation to it.
  • agent-browser.tsx:281-311 renders <webview> in Electron and
    ScreencastSurface on web, despite describing one agent-driven surface.
  • services/agent-runtime/src/browser-host/browser-host.ts:1-7 identifies the
    CDP host as the replacement for the old webview.
  • frontend/desktop/logic/window-manager.ts:20-34 enables webviewTag: true;
    frontend/desktop/logic/security.ts contains guest-attachment hardening needed
    only while webviews exist.
  • agent-browser-panel.tsx and tools/browser-url.ts accept file:// for the
    desktop webview. The server browser must not inherit arbitrary disk access;
    project files already have Files/canvas viewers.

Steps to reproduce

  1. Launch the packaged desktop app and navigate the visible browser pane to a
    loopback test page A.
  2. In the same agent session, invoke a browser tool that navigates or reads a
    different loopback test page B.
  3. Compare the URL and DOM reported by the tool with the page still visible in
    the desktop pane.

Expected: the user and agent act on the same protected page and observe the same
URL/state. Actual: the desktop pane remains in its Electron webview while the
agent tool operates a separate server-side Chromium page.

Verification commands

Purpose Command Expected on success
Browser regression npm run test:frontend:regression -- agent-browser-tools-regressions shared-surface cases pass
Frontend tests npm --prefix frontend run test all pass
Frontend quality npm --prefix frontend run check:quality exit 0
Full integration npm run test:integration all pass
Desktop package npm --prefix frontend run desktop:dist production app built

Scope

In scope:

  • frontend/src/features/agent/ui/agent-browser.tsx
  • frontend/src/features/agent/ui/agent-browser-effects.ts
  • frontend/src/features/agent/ui/agent-browser-panel.tsx
  • frontend/src/features/agent/ui/agent-browser-screencast.tsx
  • frontend/src/features/agent/tools/browser-url.ts
  • File-link routing caller only if needed to open the existing Files/canvas view
  • frontend/desktop/logic/window-manager.ts
  • frontend/desktop/logic/security.ts
  • Focused frontend/regression tests

Out of scope:

  • Browser session isolation; audit proposal 042 follows this issue.
  • Reintroducing file URLs through CDP or serving arbitrary disk files over HTTP.
  • Browser networking policy changes beyond consuming audit proposal 040.
  • Redesigning the browser toolbar or Files/canvas viewers.

Solution design

Render ScreencastSurface in live mode for every platform. All toolbar, address,
frame, viewport, and input requests use the same browser-host endpoints that Pi
tools call. Remove webview refs/types/effects and the isElectron branch. Set
webviewTag: false or remove it, and delete guest-only security handlers once no
other webview consumer exists. Reject file:// in browser navigation; file links
should open the existing workspace Files/canvas viewer when inside the permitted
workspace, otherwise show a clear unsupported message.

Implementation plan

Step 1: Characterize cross-surface divergence

Add a regression that navigates through the visible pane, calls agent get-url,
then navigates through the agent and polls visible state. It must expose the
current desktop divergence and pass on the web screencast path.

Verify: the new test fails only for the old desktop webview branch before implementation.

Step 2: Remove the webview rendering/effect path

Delete WebviewElement, refs, initial webview state, Electron navigation
branches, and the <webview> render. Drive back/forward/reload and location
updates through the existing host/screencast APIs on every platform. Keep reader
fallback behavior unchanged.

Verify: rg -n 'webview|WebviewElement|webviewRef|initialWebviewUrl' frontend/src/features/agent returns no live browser-surface matches; focused tests pass.

Step 3: Remove desktop guest capability

Disable webviewTag in window-manager.ts. Remove will-attach-webview and
guest-only code only after rg proves no other product surface uses a webview.
Retain all main-window navigation, permission, sandbox, and origin hardening.

Verify: rg -n 'webviewTag: true|will-attach-webview|<webview' frontend returns no matches, while desktop security tests pass.

Step 4: Route files away from the browser

Remove file URL normalization/acceptance from browser panel code. Use the
existing workspace-relative file opening action for eligible file links and a
clear error for paths outside its boundary. Do not add an HTTP file-serving route.

Verify: tests assert file:// is rejected by browser navigation, in-workspace
links open Files/canvas, and out-of-workspace links do not read or render data.

Step 5: Prove one visible/tool state machine

Test navigate, URL/title, back/forward/reload, click/fill/scroll, viewport, and
reader fallback from both visible and tool callers against the same page/session.

Verify: browser regression suite passes with no platform-specific expected URL.

Step 6: Run gates and reinstall desktop

Run all frontend/repository checks, build desktop:dist, replace
/Applications/Local Studio.app using the exact AGENTS.md sequence, relaunch,
and query the installed /api/desktop-health endpoint.

Verify: npm --prefix frontend run check:quality && npm --prefix frontend run test && npm run check && npm run test:integration && npm --prefix frontend run desktop:dist → all exit 0; installed desktop health is HTTP 200 with ok: true.

Test plan

  • Visible navigation is returned by agent get-url/get-text and agent navigation
    updates visible frame/address.
  • Back/forward/reload and pointer/keyboard input affect that same history/page.
  • Web and packaged desktop use identical endpoint flow.
  • Reader fallback still activates when Chromium is unavailable.
  • Browser rejects file URLs; workspace file action enforces its root boundary.
  • Static regression proves no webview capability remains enabled.

Acceptance criteria

  • One CDP page is the visible and agent-driven surface on web and desktop.
  • No browser behavior branches on Electron.
  • No <webview>, webview ref, webviewTag: true, or guest handler remains.
  • Browser URLs are HTTP(S) only under audit proposal 040 policy.
  • Workspace files use Files/canvas and cannot escape its boundary.
  • Cross-surface regression and all canonical checks pass.
  • Reinstalled desktop health returns 200.

Risks and stop conditions

Stop and report if:

  • Another required product feature still uses Electron webviews.
  • audit proposal 040 is not complete enough to make CDP the sole network surface.
  • The existing Files/canvas action cannot enforce workspace boundaries.
  • CDP input/frame behavior cannot meet an existing accessibility requirement.
  • Desktop reinstall or health verification cannot complete.

Maintenance considerations

Do not add platform-specific browser state again. Reviewers should manually
observe a user navigation followed by an agent read in the packaged app. Plan
042 must key this unified surface by agent session before concurrent sessions are
considered isolated.


Generated from Local Studio 2.0 main-branch audit proposal 041.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions