<feed xmlns='http://www.w3.org/2005/Atom'>
<title>sz-chrome-remote-extension.git, branch master</title>
<subtitle>pi-chrome, patched to drive a signed-in browser on another host through a broker, with an MCP server
</subtitle>
<id>https://git.soarez.net/sz/sz-chrome-remote-extension.git/atom?h=master</id>
<link rel='self' href='https://git.soarez.net/sz/sz-chrome-remote-extension.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-extension.git/'/>
<updated>2026-11-06T11:49:39+00:00</updated>
<entry>
<title>extension: end a /chrome authorize grant with its session</title>
<updated>2026-11-06T11:49:39+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-11-06T11:49:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-extension.git/commit/?id=ff99a4432a3feedfac10d9514ce661a9cb95004c'/>
<id>urn:sha1:ff99a4432a3feedfac10d9514ce661a9cb95004c</id>
<content type='text'>
The grant lives on globalThis so /reload keeps it, but nothing cleared it
when pi replaced the session in the same process. After /new, /resume or
/fork the next session started authorized and announced it in the footer.

Drop the saved grant on session_shutdown for new, resume and fork. Reload
keeps it. Quit leaves it alone, so a subagent quitting in the same process
does not take its parent's grant with it.

grant-scope.test.mjs loads the shipped module once per runtime in one
shared context, the way pi keeps globalThis across reloads and switches,
and checks the tools and the footer after each. It fails on 85b4988, and
its /chrome authorize cases fail with only the PI_CHROME_AUTHORIZE fix.
</content>
</entry>
<entry>
<title>extension: keep PI_CHROME_AUTHORIZE grants out of the persisted grant</title>
<updated>2026-11-06T11:49:39+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-11-06T11:49:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-extension.git/commit/?id=68216dcb01c8cd5894c6e2b4914d7c619d75ab35'/>
<id>urn:sha1:68216dcb01c8cd5894c6e2b4914d7c619d75ab35</id>
<content type='text'>
The env grant was saved to globalThis like a /chrome authorize grant. After
a /reload or a session switch (/resume, /fork, /new) the new runtime restored
it, skipped the env branch, and left envGranted false, so the footer
announced a grant the user never gave.

Read the variable again on each session_start instead of persisting it.
A restored grant now always comes from /chrome authorize. A timed env grant
restarts its countdown on each reload or switch.
</content>
</entry>
<entry>
<title>broker: refuse uploads from outside the staging directory</title>
<updated>2026-11-06T09:20:16+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-11-06T09:20:16+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-extension.git/commit/?id=85b49885256464b735923eaa771044706383718f'/>
<id>urn:sha1:85b49885256464b735923eaa771044706383718f</id>
<content type='text'>
page.upload and a raw DOM.setFileInputFiles through cdp.call now have to name
files whose real path is under /tmp/pi-chrome-uploads (PI_CHROME_UPLOAD_DIR),
on the broker's host. Anyone holding the token could otherwise attach any file
the user can read to a page.
</content>
</entry>
<entry>
<title>extension: show the bridge footer only for grants given this session</title>
<updated>2026-10-26T13:42:32+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-26T13:42:32+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-extension.git/commit/?id=ee1ddab7f9f24adfc55a41e62efa3156a282c7a8'/>
<id>urn:sha1:ee1ddab7f9f24adfc55a41e62efa3156a282c7a8</id>
<content type='text'>
A standing PI_CHROME_AUTHORIZE is not session state worth a line at the
bottom of every session that has it; announce only access the user granted
through /chrome authorize.
</content>
</entry>
<entry>
<title>mcp: pi-chrome-mcp joins the fork as sz-chrome-remote-extension, loading the fork's own extension</title>
<updated>2026-10-15T22:11:41+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-15T22:11:41+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-extension.git/commit/?id=2a3854c2e246d38636779c2c8dea7cd368f0fe4b'/>
<id>urn:sha1:2a3854c2e246d38636779c2c8dea7cd368f0fe4b</id>
<content type='text'>
</content>
</entry>
<entry>
<title>pi-chrome 0.15.57: stand in for pi-tui, collect the primer from prompt sections</title>
<updated>2026-10-15T05:49:35+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-15T05:49:35+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-extension.git/commit/?id=cc86d6114291305fcea1ed8b0904c8be0e633767'/>
<id>urn:sha1:cc86d6114291305fcea1ed8b0904c8be0e633767</id>
<content type='text'>
</content>
</entry>
<entry>
<title>pi: native MCP instead of pi-mcp-adapter</title>
<updated>2026-10-02T03:31:21+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-02T03:31:21+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-extension.git/commit/?id=50c251e082b8122bfd1a6e80427d0dc19fa4f246'/>
<id>urn:sha1:50c251e082b8122bfd1a6e80427d0dc19fa4f246</id>
<content type='text'>
pi 0.99+ ships MCP as a built-in, and the adapter suppresses it. The gate moves
from the adapter's approval event, which the built-in never emits, to pi's own
tool_call hook on mcp__&lt;server&gt;__*, which every call passes through, codemode
included. approveTools went with the adapter, so nothing backs the gate up: a
decision it cannot reach now denies rather than throws. server.mjs also treats
a client named plain "pi" as pi, which is how the built-in introduces itself.

From change request 562974, filed from the work laptop.
</content>
</entry>
<entry>
<title>ship the pi side we actually run, not a different arrangement</title>
<updated>2026-09-25T13:42:26+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-09-25T13:42:26+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-extension.git/commit/?id=66dcc84d51bed88cbfb608b9dc6800a8edd32b3c'/>
<id>urn:sha1:66dcc84d51bed88cbfb608b9dc6800a8edd32b3c</id>
<content type='text'>
The README told pi users to install pi-chrome directly and run /chrome
authorize every session. That is not how this is used: pi reaches the same MCP
server through pi-mcp-adapter, with pi's own pi-chrome switched off, which is
why nobody types /chrome authorize.

pi/browser-gate.ts is that setup's missing piece, generalised from the one in
use: it answers pi-mcp-adapter's approval broker for one server, asking once per
session instead of once per call (the adapter's own grant only covers identical
arguments, so for a browser it asks nearly every time). /browser authorize,
/browser revoke, and PI_BROWSER_AUTHORIZE for headless runs. approveTools stays
on in mcp.json as the backstop if the gate does not load.

The README now leads with that: install the adapter, register the server in
mcp.json, copy the gate. Installing pi-chrome in pi is kept as the alternative,
with what it costs - two definitions of the browser, /chrome authorize per
session, and the trap of loading the extension twice.

Tested on an isolated pi config against a stand-in browser: with
PI_BROWSER_AUTHORIZE the call reaches the browser, without it the gate denies it.
</content>
</entry>
<entry>
<title>FORK.md: what the fork changes, setup, upstream releases</title>
<updated>2026-10-14T11:16:02+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-14T11:08:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-extension.git/commit/?id=fd06303bec47430f4644896d587f8f677245c9ac'/>
<id>urn:sha1:fd06303bec47430f4644896d587f8f677245c9ac</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat(remote): drive a companion extension on another host through a broker</title>
<updated>2026-10-14T11:16:02+00:00</updated>
<author>
<name>Igor Soarez</name>
<email>igor@soarez.org</email>
</author>
<published>2026-10-14T11:08:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.soarez.net/sz/sz-chrome-remote-extension.git/commit/?id=7e2196bd1f046707d1930f8c3d9aa7e4cc390bd6'/>
<id>urn:sha1:7e2196bd1f046707d1930f8c3d9aa7e4cc390bd6</id>
<content type='text'>
PI_CHROME_REMOTE=host:port sends every command to a broker/broker.mjs there,
with its bearer token, instead of binding a bridge on this machine. Unset, the
extension behaves as upstream. A remote session never binds or takes over a
port: when the broker is unreachable the tools fail rather than drive some
other browser.

A pi-chrome-remote prompt section says which browser chrome_* drives and how
files move to and from its host; chrome_upload_file wants absolute paths there.
PI_CHROME_AUTHORIZE grants every session up front.
</content>
</entry>
</feed>
