One real Chromium session per Paseo workspace, shared live across every connected client.
npmjs · Paseo 0.9+
paseo plugin add npm:@omercnet/paseo-shared-browser@3.0.0Preview releases are unreleased plugin code. Install only if you want to test it; stable remains the default. Published 2026-10-20.
Security scan passed · 0 blocking · 0 advisory.
paseo plugin add npm:@omercnet/paseo-shared-browser@3.0.0-next.278.2GitHub · Paseo 0.8 fallback
paseo plugin add omercnet/paseo-plugins --ref 01ba4209e099c0f27a5b85ca6a911def76bc0b2a --path paseo-shared-browserGit security status and fallback installation are pinned to commit 01ba4209e099.
From the plugin's README
Enable trusted plugins on the target Paseo daemon, then install from npm:
paseo plugin install npm:@omercnet/paseo-shared-browser
paseo plugin ls
When Paseo acquires the npm package, it runs the npm run prepare:runtime build hook automatically. The
hook installs the pinned browser runtime, builds both supervisor.cjs and shared-browser-mcp.cjs
under a versioned directory in $PASEO_HOME/plugin-data/shared-browser, then atomically updates the
runtime-current pointer. Existing processes keep using their immutable runtime during an update.
The build requires Node.js 24 or newer and npm on the daemon host. On Linux x64, macOS, and
Windows, runtime preparation installs and stages the platform's Chrome for Testing distribution. On
Linux ARM64, where that download is unavailable, the installer automatically uses native Chromium
from /usr/bin/chromium. Install a non-Snap Chromium build with the system package manager before
adding the plugin. Set PASEO_SHARED_BROWSER_CHROMIUM_EXECUTABLE to an absolute path when Chromium
is installed elsewhere. The plugin does not emulate x64 Chromium on Linux.
On Windows, the upstream installer retains its Chrome download cache under the OS user profile. Before upgrading the plugin on Windows, close active Shared Browser sessions and stop the Paseo daemon; Windows does not allow the installer to replace runtime executables that are still running.
Open a workspace, search the Command Center for Open Shared Browser, or …
README
A Paseo plugin that runs one real Chromium browser per workspace on the daemon host and shares its
pages with connected Paseo clients and workspace agents. Version 1.0 replaces the previous browser
runtime in place with a plugin-owned, pinned agent-browser runtime; existing installations keep
the shared-browser plugin ID and upgrade without installing a second plugin.
Each browser tab is a real page in the same Chromium profile, so tabs share site logins and cookies. Each client and agent selects a tab independently. Viewers of the same tab share its live page, navigation and control state. Human control remains server-authoritative and takes priority over agent input on that tab.
https://github.com/user-attachments/assets/37d09fff-0750-440d-983d-426150b0724d
Both PNGs show the same isolated Chromium session from a dedicated Paseo test daemon. They were captured at 2× pixel density after browser DevTools verified the rendered page contained no private organization names.
agent-browser session and Chromium
process per open browser workspace. Browser execution, profiles, IPC, and network access are on the
daemon host, not on the viewing phone, browser, or desktop app.agent-browser version 0.39.1, its IPC directory, and the Chromium executable.
It strips inherited AGENT_BROWSER_* variables and sets AGENT_BROWSER_SOCKET_DIR,
AGENT_BROWSER_IDLE_TIMEOUT_MS=0, AGENT_BROWSER_STREAM_PORT=0, and
AGENT_BROWSER_NO_AUTO_DIALOG=1 itself.Page.startScreencast or bounded
screenshots, and no capture extension is loaded into Chromium. When the daemon is started with
PASEO_SHARED_BROWSER_VIDEO=1, desktop/web clients with usable WebCodecs receive encoded
workspace-tab video instead; other clients keep JPEG.
Remote input supports mouse hover, wheel scrolling, continuous dragging, native touch pan/pinch,
tap, double-tap, right-click, text, and special keys.The browser runtime is held by a detached supervisor rather than by a particular Paseo client or plugin subprocess. Closing a panel, disconnecting a client, or losing the plugin bridge invalidates that client's viewer/control tokens but does not immediately close Chromium. A replacement plugin bridge can reclaim the existing workspace runtime. If no bridge reconnects, the supervisor closes all orphaned runtimes after a 120-second grace period. A missed heartbeat fences the old bridge after 30 seconds; the bridge sends heartbeats every 10 seconds.
The browser actions menu has Close shared browser. After confirmation, it stops that workspace's Chromium process and ends every viewer and agent connection to it, even when their panels are active. Background reconnects cannot reopen a deliberately closed browser. A person can select the prominent Open shared browser button in the closed panel to start a new runtime with the retained profile. Closing the browser does not remove saved cookies or site data.
Each workspace gets a private profile under
$PASEO_HOME/plugin-data/shared-browser/profiles/<workspace-id-sha256>. Cookies and site login state
therefore survive viewer disconnects, plugin reloads, and Chromium process restarts while that
directory remains intact. Profiles are local to one daemon host: they are not synchronized between
hosts or Paseo clients, do not use a personal Chrome or Safari profile, and are not portable across
arbitrary Chromium versions.
When Paseo emits workspace.archived while the plugin server is active, the plugin fences that
workspace, expires its viewers and controller, and closes its browser runtime, including a runtime
whose creation raced the archive. The profile directory is retained. Archive events missed while
the plugin bridge is disconnected are not replayed or reconciled by the plugin; the orphan grace
still closes the runtime, but retained profile data must be removed manually if it is no longer
wanted.
Enable trusted plugins on the target Paseo daemon, then install from npm:
paseo plugin install npm:@omercnet/paseo-shared-browser
paseo plugin ls
When Paseo acquires the npm package, it runs the npm run prepare:runtime build hook automatically. The
hook installs the pinned browser runtime, builds both supervisor.cjs and shared-browser-mcp.cjs
under a versioned directory in $PASEO_HOME/plugin-data/shared-browser, then atomically updates the
runtime-current pointer. Existing processes keep using their immutable runtime during an update.
The build requires Node.js 24 or newer and npm on the daemon host. On Linux x64, macOS, and
Windows, runtime preparation installs and stages the platform's Chrome for Testing distribution. On
Linux ARM64, where that download is unavailable, the installer automatically uses native Chromium
from /usr/bin/chromium. Install a non-Snap Chromium build with the system package manager before
adding the plugin. Set PASEO_SHARED_BROWSER_CHROMIUM_EXECUTABLE to an absolute path when Chromium
is installed elsewhere. The plugin does not emulate x64 Chromium on Linux.
On Windows, the upstream installer retains its Chrome download cache under the OS user profile. Before upgrading the plugin on Windows, close active Shared Browser sessions and stop the Paseo daemon; Windows does not allow the installer to replace runtime executables that are still running.
Open a workspace, search the Command Center for Open Shared Browser, or tap the Shared Browser composer pill while a workspace session is open. A Shared Browser (n) row in the sidebar footer appears while browser sessions are open; it lists them and jumps to the chosen workspace's browser panel.
The plugin automatically injects its stdio MCP adapter only when a new, non-internal agent is created with a provider that accepts external MCP servers. Agents that already exist, resumed sessions, imported sessions, and Paseo's internal agents are not modified. Paseo's built-in OMP provider accepts session MCP servers, so new OMP agents receive the adapter. Pi agents also receive the adapter, but require Pi's optional MCP support to launch it.
The injected MCP server exposes shared_browser_status, shared_browser_capture,
shared_browser_acquire_control, shared_browser_release_control,
shared_browser_navigate, shared_browser_input, shared_browser_viewport,
shared_browser_tabs, shared_browser_tab_open, shared_browser_tab_select, and
shared_browser_tab_close. It does not
expose arbitrary CDP commands, JavaScript or page evaluation, browser profile access, or filesystem
access.
Each adapter launch receives an opaque credential bound to its workspace. It cannot use that credential to operate another workspace's browser. Agent input follows human-priority control: an agent cannot force a takeover while a human viewer holds control of the same tab. The human must release control or the lease must expire before agent input can proceed on that tab.
The provider launches the stdio adapter on the Paseo daemon host, beside the daemon-owned browser runtime. Web, desktop, and mobile clients never own or host the adapter or Chromium, and a client disconnect does not close or reset either process.
The plugin recognizes only these deployment overrides:
| Variable | Meaning |
|---|---|
PASEO_HOME |
Paseo data root. Defaults to ~/.paseo; browser runtime, supervisor IPC, and profiles live below plugin-data/shared-browser. |
PASEO_SHARED_BROWSER_AGENT_BROWSER_BINARY |
Absolute path to the pinned agent-browser executable. Defaults to the active runtime's node_modules/.bin/agent-browser (agent-browser.exe on Windows). |
PASEO_SHARED_BROWSER_CHROMIUM_EXECUTABLE |
Absolute path to Chromium. Defaults to the active runtime's chromium/chrome (chrome.exe on Windows). On Linux ARM64, installation automatically links /usr/bin/chromium; use this override for another compatible, non-Snap location. |
PASEO_SHARED_BROWSER_CHROMIUM_ARGS |
Optional Chromium arguments passed through the managed runtime. Intended for host requirements such as --no-sandbox in an already-isolated CI runner; do not disable the browser sandbox on a general-purpose host. |
User-supplied AGENT_BROWSER_* variables are deliberately ignored.
PASEO_SHARED_BROWSER_VIDEO=1 set in the daemon environment, desktop and web clients
with WebCodecs play genuine encoded tab video (H264 when supported, otherwise VP8). The
bundled capture helper, which holds tabCapture and debugger permissions, is then
loaded into every workspace Chromium profile and captures the exact workspace tab, not a
screenshot loop or title-selected window. Without the variable the helper is never
materialized or loaded, and clients show a one-time disabled reply then use JPEG.
Android and other native apps use JPEG: the plugin SDK this package targets publishes no
encoded-video surface, so native video is deferred until the host ships one.agent-browser, Chromium, and other processes running as the daemon OS user share one trust
boundary and can reach that user's files, processes, credentials, and network.PASEO_HOME; custom locations must remain
private to the daemon user. agent-browser uses loopback TCP for its command and stream services
on Windows, so Windows support assumes a trusted single-user host; these services are not an
isolation boundary between local OS users.agent-browser IPC metadata and workspace profile directories are owner-only on POSIX systems.
The plugin rejects a non-loopback CDP endpoint.Follow the repository's AGENTS.md. Runtime verification must use an isolated
Paseo home, never the default daemon, active plugin installation, or signed-in
profile. Run dependency installation from the monorepo root, then the following
checks from paseo-shared-browser:
bun install --frozen-lockfile
bun run typecheck
bun run check
bun run test:unit
The test:tabs native check requires explicit
PASEO_SHARED_BROWSER_AGENT_BROWSER_BINARY and
PASEO_SHARED_BROWSER_CHROMIUM_EXECUTABLE paths. It creates and cleans up its own
temporary Paseo home and browser profile.
node scripts/test-image-capture-mounted.mjs --tooling-root /path/to/test-workspace
opt-in checks the real React/React Query image scheduling and viewing recovery hooks
in JSDOM. The tooling workspace must already provide compatible React, react-dom,
jsdom, React Query and esbuild. The plugin intentionally does not add these DOM test
dependencies or install missing packages. Omitting --tooling-root uses this
checkout if its dependencies include them. The command owns and removes temporary
hook bundles; it never launches or accesses a browser/runtime or profile.
For reproducible mounted checks, create a disposable tooling workspace with
React and react-dom 19.1.0 (matching this repository's React version), jsdom
30.1.1, React Query 5.102.3 and esbuild 0.28.2. jsdom requires Node 24.15 or
newer on the supported Node 24 line. These are test-only dependencies, not
plugin runtime dependencies. For example:
npm install --prefix /tmp/shared-browser-dom-tools --ignore-scripts --no-save \
react@19.1.0 react-dom@19.1.0 jsdom@30.1.1 \
@tanstack/react-query@5.102.3 esbuild@0.28.2
node scripts/test-image-capture-mounted.mjs --tooling-root /tmp/shared-browser-dom-tools
node scripts/test-panel-video-mounted.mjs --tooling-root /tmp/shared-browser-dom-tools --fixture settlement
The panel fixture also accepts handoff, rapid, continuous and admission.
Run each variant for changes to media handoff or input policy. The settlement
fixture checks late replies across viewer and controller replacement. Delete
the tooling directory when done.
Use the same command with --fixture density for six mounted controller/density
menu regressions, including observer bounds, same-workspace token replacement,
unmount and no retry after an uncertain write.
Prepare runtime assets with an explicit temporary PASEO_HOME before either
browser gate. Keep that directory outside the default Paseo home. For example,
on POSIX systems:
export PASEO_HOME="$(mktemp -d -t shared-browser-verification-XXXXXX)"
bun run prepare:runtime
bun run test:smoke
bun run test:video
Remove the temporary directory after verification. On Windows, use a new
explicit temporary directory in $env:PASEO_HOME instead. Tests manage their
own browser teardown; do not run daemon lifecycle commands against the default
host to recover a test failure.
bun run test:smoke launches the configured real Chromium runtime and exercises two viewers,
control handoff, reconnect, stale-frame rejection, viewport changes, device emulation, profile
persistence, and archive teardown.
bun run test:video is an optional real video gate. It opts its own runtime into encoded video
and reads prepared Chromium/CLI assets,
then creates its own temporary Paseo home, browser profile, Unix socket and local fixture pages.
It checks the production video decoder and canvas at 1280x800, sharp Pixel and 2560x2560,
including all four corner markers. It never uses the live browser. This gate requires usable
WebCodecs/tab capture and the local runtime assets; it is separate from unit tests.
Linux CI requires Xvfb and runs this video gate without skipping unsupported
capture. macOS and Windows run the image/browser smoke; their native video
hardware and remote-network performance require separate qualification. CI also
runs the actual Paseo compiler on both plugin entries.
Release Please maintains the version, changelog, component tag, and GitHub release from Conventional Commits in the monorepo.
Both the Paseo daemon and app must satisfy ^0.12.0. Encoded video is opt-in on the daemon and
requires WebCodecs in a web client; JPEG is always available. The client surface uses React
Native primitives and works in desktop, web, iOS, and Android Paseo clients.
Every independent press (mouse down or first touch contact) carries the decoded frame receipt that was visible when it was made. Receipts last five seconds and are spent by acknowledged input, so a stalled or superseded presentation cannot admit a later click; held drags, releases and keys continue on their channel. A wheel capture can finish decoding after input revoked its frame token. The server returns a known non-admission receipt before creating a new channel; the canvas waits for another decoded frame before admitting that still-unsent gesture. Recovery allows up to three admission attempts within one four-second decoded-frame wait budget. Published input, unknown outcomes, expired leases, and replaced contexts are never retried.
Streaming design documents media ownership, resource bounds, input admission and recovery. Remote-control research records primary-source comparisons and the trade-offs behind continuous human input. These describe the implementation's guarantees, not a promise of a particular frame rate or remote-network latency.
Hidden browsers are headless by default. To expose desktop pointer and hover
behavior on Linux, opt in by setting PASEO_SHARED_BROWSER_XVFB=1 (exactly 1;
any other value stays headless) in the environment of the Shared Browser
supervisor process. The supervisor is a detached process that inherits the
daemon environment when it is spawned, so changing the variable affects it only
after that supervisor process restarts. Within a running supervisor the variable
is read each time a workspace browser runtime is created; existing runtimes keep
their mode. A trusted embedding can pass virtualDisplay: true | false to
createRuntimeOwner; an explicit false overrides the variable.
When opted in and /usr/bin/Xvfb exists, each hidden Linux browser uses its own
private, authenticated display. No visible window opens and no TCP or pathname
listener is created. The display is stopped with its browser. Headed mode and
non-Linux platforms are unchanged. The plugin never installs Xvfb or changes host
display settings.
If the display cannot start, the browser falls back to headless and the viewer shows a short notice (for example "Private display unavailable: Xvfb was not found."). The notice never contains paths or credentials. If an opted-in display dies while running, requests fail and the viewer shows an error; use Reconnect viewer to replace the browser. Reconnect discards the old runtime and starts a new one, so the page reloads from its initial URL, and old viewer, control and input attachments are rejected. Nothing is replayed automatically.
Known limitation: if the supervisor is killed with SIGKILL it cannot stop its child, so an orphaned Xvfb process and its private authority directory under the temporary directory can remain until removed manually.
Scanned 23 Oct 2026, 13:11 UTC from omercnet/paseo-plugins/paseo-shared-browser.