Skip to content

Environment browser: the people's view, one tab of a person for one remote tab (F39, DEV-6646) - #242

Merged
immakermatty merged 4 commits into
mainfrom
agent/DEV-6646-people-view
Oct 6, 2026
Merged

immakermatty merged 4 commits into
mainfrom
agent/DEV-6646-people-view

Conversation

@immakermatty

@immakermatty immakermatty commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Status: ready for review. Head 3957fa8992fcf8f2bd8488092de142b8d5edfafd, four commits:

  1. the view itself;
  2. a viewer of a gone tab is told so, instead of reconnecting forever;
  3. a navigation clears a stale selection, and the extension turns Chrome's own context menu off;
  4. Pablo's review of e225489:
    • a selection or title read that a navigation overtook is dropped;
    • the menu is prevented in the capture phase, so a page that stops the event cannot let it through;
    • the extension listing test compares a sorted list (it was red on the Ubuntu shard).

Plan: HumanAndMachine-ai/mission-control-data:v3 data/mission-control/plans/2026/10/DEV-6646-environment-browser-and-desktop.yaml, task-2026-10-06-502. Decision: root 0191 points 11–18 (HumanAndMachines/Lazurio#505), this repo's new F39.

Why

On the pilot Environment the Environment browser's view for people was agent-browser's dashboard (F38 point 5). The Organization Admin found it "velmi zabugované":

The Admin decided the model, recorded as 0191 points 11–18: one tab of a person is one remote tab, agent and person work in it together, and nothing outside the page may block it.

What this changes

  • The people's view service (src/browser/people/, lazurio browser serve). A thin Platform service over the Chrome DevTools protocol replaces the dashboard in lazurio-browser-view.service.
    • Addresses. / opens a new remote tab (a new window of the default context, at the person's size) and becomes /t/<id>. /t/<id> shows exactly that tab, and /t/<id>/live is its WebSocket. The bar has only back, forward, reload and the address; the title and icon come from the page.
    • Pop-ups and new tabs. A page that can reach its opener (window.open, "Sign in with Google") shows over the page in the same person's tab. A target=_blank tab is offered with one click, and posted to an embedding app.
    • Input. Co-control: nothing locks the agent out. Keys keep the person's codes, so . - ' @ arrive unchanged. ⌘ shortcuts become Ctrl. Paste inserts the person's clipboard; copy and cut take the remote selection, read in an isolated world without ever enabling the Runtime domain. Touch is sent as touch.
    • Dialogs and files. JavaScript dialogs and file choosers are answered in the view. A file chooser with nobody watching is dropped, never shown on the screen.
    • Window size. The window takes the last acting person's page area. lazurio browser window no longer fixes a thread's viewport.
    • Closing. A tab the view opened closes 30 s after its last viewer leaves, unless an agent-browser session is bound to it.
    • Admission. The gateway is the only admission: there is no token. The service checks Host on every request and Origin on every socket and change, allows framing only from https://*.<vm>.<org>.lazurio.io, and listens on loopback.
  • The Lazurio extension, loaded with --load-extension from next to the profile:
  • The browser unit. It also gets --deny-permission-prompts. A changed browser unit now restarts the browser on install and update (F39 point 10, a change of F38 point 1); the profile keeps its sign-ins.
  • Links.
    • lazurio browser window prints the tab's own address, https://browser.…/t/<id>.
    • /.lazurio/browser.json?session= answers it, so T3 Code's Browser panel needs no change.
    • Without a session it answers /, so the Launchpad's panel opens a new tab. The all-windows view is retired (0191 point 18).
  • Folder manual (base-instructions-31). The agent sends its tab's link, works together with the Operator, finishes a sign-in through the Operator in the same tab, and knows that passkeys are declined for now.
  • Doctor asks the service's /.lazurio/health.

What deliberately does not change

  • agent-browser stays the agents' tool, and the window per thread stays.
  • The gateway route and the single gateway cookie stay.
  • HTTP authentication and print preview are not handled yet (F39 "Not decided").
  • T3 Code's automatic panel tab for a page's new tab comes in its own Lazurio/t3code revision; until then the one-click bar works there too.
  • The Bitwarden extension stays task 505.

Verification

  • Static checks: bun run lint, bun run typecheck and bun run check:public pass; bun run build:proof && bun run smoke:proof pass.
  • Full suite: bun test on 25560b1: 1514 pass, 7 skip, 0 fail (1521 tests, 162 files).
  • Later commits: 9162a46, e225489 and 3957fa8 change only the view service, the extension and their tests. On 3957fa8:
    • tests/environment-browser-view.test.ts passes 25/25 three times. The new ordering regression fails when the document check is removed;
    • tests/environment-browser.test.ts, tests/update-install.test.ts and tests/environment-browser-view-client.test.ts pass 61/61;
    • lint and typecheck pass.
    • A page in Chrome for Testing 155 whose contextmenu handler stops propagation still had its handler run, and defaultPrevented was true.
  • New tests:
    • tests/environment-browser-view.test.ts, 25 pass, against a scripted DevTools peer: admission (Host, Origin, frame-ancestors), new tab, frames and acks at the viewer's size, input codes, paste, navigation limits, the selection read on demand without Runtime.enable, cleared by a navigation and never repopulated by a read the navigation overtook, the title and icon from the page, pop-up versus new tab, dialogs, file choosers (single-use token, base names only, dropped with nobody watching), the grace close (own tab, agent-bound tab, unviewed tab), a tab that goes away (also for a socket opened after it went), a socket opened while the browser is away (told to retry), reconnect, flow control and the extension's three scripts;
    • tests/environment-browser-view-client.test.ts, 33 pass: input mapping, frames and the protocol.
  • Browser check before release. The service ran against a real headless Chrome for Testing 155 with the extension and was viewed in a browser:
    • a new tab from /, navigation from the bar, and the page's title;
    • typing j.-'@, a paste and a copy;
    • a sign-in pop-up shown in the same tab, which closed itself and reached its opener;
    • the offer of a new tab;
    • a prompt answered in the view;
    • a file uploaded into the page's input;
    • a passkey request declined at once (NotAllowedError);
    • the window taking the view's size.
  • Branded Google Chrome ignores --load-extension; Chrome for Testing, which the Environment runs, loads it.
  • Not yet verified: the pilot Environment through the real gateway (decision 0178). That follows the release as 0.1.8-rc.38, applied to the pilot Environment alone.

🤖 Generated with Claude Code

…emote tab (F39, DEV-6646)

On the pilot Environment the Organization Admin found agent-browser's
dashboard, the view of F38, "velmi zabugované". It is a browser inside a
browser, its second token broke every open view on each restart, its
links were pinned to stream ports, paste never reached the page, and a
passkey request opened Chrome's native window outside the page, which
blocked the page until it was closed on the screen. Root decision 0191
points 11–18 set the model: a person's tab is a window into exactly one
remote tab, agent and person work in it together, and nothing outside
the page may block it.

The view is now the Platform's own thin service over the Chrome DevTools
protocol, `lazurio browser serve`, run by lazurio-browser-view.service:
- `/` opens a new remote tab (a new window of the default context, at
  the person's size) and becomes `/t/<id>`, the view of exactly that
  tab; the bar has back, forward, reload and the address, and the title
  and icon are read from the page;
- a pop-up that can reach its opener shows over the page in the same
  person's tab; a new tab is offered with one click and posted to an
  embedding app;
- keys keep the person's codes, ⌘ shortcuts become Ctrl, paste inserts
  the person's clipboard and copy takes the remote selection, read in an
  isolated world without enabling the Runtime domain;
- JavaScript dialogs and file choosers are answered in the view; a file
  chooser with nobody watching is dropped;
- the window takes the last acting person's size, so `lazurio browser
  window` pins a thread's session without a fixed viewport;
- a tab the view opened closes 30 s after its last viewer, unless an
  agent-browser session is bound to it;
- the gateway is the only admission: the service checks Host on every
  request and Origin on every socket and change, frames only for the
  Environment's own origins and listens on loopback.

The browser unit gains `--deny-permission-prompts` and the Lazurio
extension, written next to the profile: it moves a page's new tab into
a window of its own and, until the Environment's Bitwarden holds its
passkeys, declines WebAuthn at once. A changed browser unit now restarts
the browser on install and update (F38 point 1 changes); the profile
keeps its sign-ins.

`/.lazurio/browser.json` answers the view of a thread's tab, so T3
Code's Browser panel needs no change; without a session it answers a new
tab and the view of every window is retired. The Folder manual
(base-instructions-31) tells agents to send their tab's link, to work
together with the Operator and that passkeys are declined for now.
Doctor asks the service's health.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
immakermatty and others added 2 commits October 6, 2026 21:04
…not left reconnecting (F39)

The service refused the socket of an unknown tab before the upgrade, so
the page saw only a failed handshake and retried forever with "Connecting…"
(after a browser restart, every open view). It now upgrades and says
`closed`, and the page offers a new tab. Only a hub that has discovered
every existing page says a tab is gone: while it reconnects to the
browser, a new socket is told `reconnecting` and closed with 1013, and
the page tries again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…menu (F39)

From the client's review against the service:
- A navigation reset the tab's selection in the hub but not in the
  viewers, so a copy after a navigation still took the old page's text.
  The hub now sends the empty selection when a new document replaces a
  selected one.
- A right click reached the page, and where the page drew no menu of its
  own, Chrome opened its native context menu outside the page, which
  nobody sees in the view (like the passkey window). The extension's
  third job turns Chrome's own menu off with a last listener on the
  window; a page's own menu still works.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@agentrozjedemeai agentrozjedemeai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@immakermatty — exact-head review of e225489. Changes requested:

  1. [P1] src/browser/people/extension.ts:108-113 — The contextmenu listener is registered on window in the bubbling phase. A page handler that calls stopPropagation() before the event reaches window, without preventDefault(), bypasses it and Chrome opens the native menu outside the view. In a real browser DOM probe with the same listener arrangement, windowListenerCalled=0 and defaultPrevented=false; a capturing window preventDefault listener kept the page handler running and defaultPrevented=true. Register the prevention in capture phase and add a propagation-stopping page regression (including page-owned menu behavior).

  2. [P1] src/browser/people/hub.ts:804-815,991-1000 — Navigation broadcasts an empty selection, but an in-flight old-document Runtime.evaluate can resolve after Page.frameNavigated and repopulate/broadcast the old text. A disposable focused FakeBrowser regression delaying that selection response until after navigation failed: received OLD-DOCUMENT-SECRET after the clear. Bind selection reads to a document generation/frame and discard obsolete responses; test this ordering so copy cannot take the previous document text.

  3. [P2] tests/environment-browser.test.ts:218-220 — The e225489 CI Ubuntu shard tests (3/4) is red: readdir returned manifest.json before background.js, unlike the asserted array order. Compare a sorted list or a set, then rerun the exact-head CI. Other local focused suites passed (85/85 across four files); lint and typecheck passed. The injected review-only regression was removed; the detached exact-head checkout and git diff --check are clean. No merge or release.

… menu prevention in the capture phase; sorted listing (F39)

Pablo's review of e225489:
- A selection read that was still out when the page navigated could
  resolve afterwards and put the old document's text back (a copy would
  then take it). The hub counts the main frame's documents and drops a
  selection or title read that a navigation overtook. A regression test
  holds the read across a navigation; it fails without the check.
- A page handler that stops a contextmenu event before it reaches the
  window bypassed the bubbling listener, and Chrome's native menu opened
  outside the view. The extension now prevents it in the capture phase on
  the window; the page's own handlers still run. Checked in Chrome for
  Testing 155 with a page that stops propagation: its handler ran and the
  default was prevented. A dispatch-order regression test covers it.
- The extension listing test depended on readdir order (red on the
  Ubuntu CI shard); it compares the sorted list.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@agentrozjedemeai agentrozjedemeai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@immakermatty — exact-head re-review of 3957fa8: APPROVED.

The three blockers from e225489 are addressed: main-frame navigation advances the document generation and discards overtaken selection/title reads; menu.js prevents the native context menu in window capture while page handlers still run; the extension listing assertion sorts the directory entries. I inspected the focused diff and code paths in an isolated, clean checkout; git diff --check is clean. Local Bun validation: 25/25 view tests, 61/61 client/environment/update tests, lint and typecheck pass. The exact-head Platform checks run 37517614106 completed successfully (all four test shards and static checks); no unresolved review threads. The real pilot Environment gateway smoke remains a post-release step per the PR body, not evidence claimed here. This is a review verdict only, not a merge or release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants