pi-browser-use 0.9.6 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/artifacts.d.ts +1 -1
- package/dist/artifacts.js +2 -2
- package/dist/chrome-launcher.d.ts +3 -0
- package/dist/chrome-launcher.js +38 -5
- package/dist/client.js +11 -2
- package/dist/config.d.ts +2 -2
- package/dist/config.js +12 -8
- package/dist/existing-flow.js +4 -2
- package/dist/index.d.ts +8 -35
- package/dist/index.js +17 -904
- package/dist/mcp-server.d.ts +47 -0
- package/dist/mcp-server.js +218 -0
- package/dist/persistent-backend.d.ts +1 -1
- package/dist/persistent-backend.js +10 -5
- package/dist/profile-lock.js +1 -1
- package/dist/runtime.d.ts +45 -0
- package/dist/runtime.js +1019 -0
- package/dist/setup-flow.d.ts +7 -1
- package/dist/setup-flow.js +17 -1
- package/dist/tab-bridge.js +5 -1
- package/docs/agent-plugins.md +131 -0
- package/mcp.json +14 -0
- package/package.json +9 -4
- package/plugin.json +12 -0
- package/skills/auth-bootstrap/SKILL.md +39 -36
- package/skills/browser-policy/SKILL.md +17 -13
- package/skills/gmail-auth/SKILL.md +6 -3
package/dist/setup-flow.d.ts
CHANGED
|
@@ -39,24 +39,30 @@ export declare function runBootstrap(options: {
|
|
|
39
39
|
profileDir?: string;
|
|
40
40
|
executablePath?: string;
|
|
41
41
|
chromeArgs?: string[];
|
|
42
|
+
signal?: AbortSignal;
|
|
42
43
|
launch?: (options: {
|
|
43
44
|
userDataDir: string;
|
|
44
45
|
profileDirectory?: string;
|
|
45
46
|
executablePath?: string;
|
|
46
47
|
chromeArgs?: string[];
|
|
48
|
+
signal?: AbortSignal;
|
|
47
49
|
}) => Promise<number | null>;
|
|
48
50
|
}, events?: SetupFlowEvents): Promise<number | null>;
|
|
49
51
|
export interface ReauthOptions {
|
|
50
|
-
backend: PersistentBackend
|
|
52
|
+
backend: Pick<PersistentBackend, 'profileDir' | 'restart'>;
|
|
51
53
|
/** Page that needs auth (used for messaging + Variant B navigation hint). */
|
|
52
54
|
url: string;
|
|
53
55
|
variant?: ReauthVariant;
|
|
56
|
+
signal?: AbortSignal;
|
|
57
|
+
executablePath?: string;
|
|
58
|
+
chromeArgs?: string[];
|
|
54
59
|
/** Plain-variant launcher (no CDP). Defaults to launchSetupBrowser. */
|
|
55
60
|
launchPlain?: (options: {
|
|
56
61
|
userDataDir: string;
|
|
57
62
|
profileDirectory?: string;
|
|
58
63
|
executablePath?: string;
|
|
59
64
|
chromeArgs?: string[];
|
|
65
|
+
signal?: AbortSignal;
|
|
60
66
|
}) => Promise<number | null>;
|
|
61
67
|
/** Restart the backend headed/headless (Variant B + resume). */
|
|
62
68
|
restartBackend?: (headed: boolean) => Promise<unknown>;
|
package/dist/setup-flow.js
CHANGED
|
@@ -44,6 +44,7 @@ export function reauthInstructions(url, variant) {
|
|
|
44
44
|
* window exit code after marking the profile initialized.
|
|
45
45
|
*/
|
|
46
46
|
export async function runBootstrap(options, events) {
|
|
47
|
+
options.signal?.throwIfAborted();
|
|
47
48
|
const profileDir = options.profileDir ?? DEFAULT_PROFILE_DIR;
|
|
48
49
|
events?.onSetupNeeded?.(SETUP_INSTRUCTIONS);
|
|
49
50
|
// Same named identity automation uses: sign in here, automate there.
|
|
@@ -54,7 +55,11 @@ export async function runBootstrap(options, events) {
|
|
|
54
55
|
profileDirectory: PI_PROFILE_NAME,
|
|
55
56
|
executablePath: options.executablePath,
|
|
56
57
|
chromeArgs: options.chromeArgs,
|
|
58
|
+
signal: options.signal,
|
|
57
59
|
});
|
|
60
|
+
options.signal?.throwIfAborted();
|
|
61
|
+
if (code !== 0)
|
|
62
|
+
throw new Error(`Browser setup did not complete successfully (exit ${code}).`);
|
|
58
63
|
markBootstrapped(profileDir);
|
|
59
64
|
events?.onSetupComplete?.(profileDir);
|
|
60
65
|
return code;
|
|
@@ -67,13 +72,23 @@ export async function runBootstrap(options, events) {
|
|
|
67
72
|
* and waits for close. Returns the user-facing instruction to relay.
|
|
68
73
|
*/
|
|
69
74
|
export async function runReauth(options) {
|
|
75
|
+
options.signal?.throwIfAborted();
|
|
70
76
|
const variant = options.variant ?? 'instrumented';
|
|
71
77
|
const profileDir = options.backend.profileDir?.() ?? DEFAULT_PROFILE_DIR;
|
|
72
78
|
const message = reauthInstructions(options.url, variant);
|
|
73
79
|
options.events?.onReauthNeeded?.(message);
|
|
74
80
|
if (variant === 'plain') {
|
|
75
81
|
const launch = options.launchPlain ?? launchSetupBrowser;
|
|
76
|
-
await launch({
|
|
82
|
+
const code = await launch({
|
|
83
|
+
userDataDir: profileDir,
|
|
84
|
+
profileDirectory: PI_PROFILE_NAME,
|
|
85
|
+
executablePath: options.executablePath,
|
|
86
|
+
chromeArgs: options.chromeArgs,
|
|
87
|
+
signal: options.signal,
|
|
88
|
+
});
|
|
89
|
+
options.signal?.throwIfAborted();
|
|
90
|
+
if (code !== 0)
|
|
91
|
+
throw new Error(`Browser verification did not complete successfully (exit ${code}).`);
|
|
77
92
|
}
|
|
78
93
|
else {
|
|
79
94
|
if (options.restartBackend) {
|
|
@@ -83,6 +98,7 @@ export async function runReauth(options) {
|
|
|
83
98
|
await options.backend.restart(true);
|
|
84
99
|
}
|
|
85
100
|
}
|
|
101
|
+
options.signal?.throwIfAborted();
|
|
86
102
|
options.events?.onReauthComplete?.(profileDir);
|
|
87
103
|
return message;
|
|
88
104
|
}
|
package/dist/tab-bridge.js
CHANGED
|
@@ -110,8 +110,12 @@ export class TabBridge {
|
|
|
110
110
|
const pollMs = options?.pollMs ?? 100;
|
|
111
111
|
const deadline = Date.now() + timeoutMs;
|
|
112
112
|
while (Date.now() < deadline) {
|
|
113
|
-
if (options?.signal?.aborted)
|
|
113
|
+
if (options?.signal?.aborted) {
|
|
114
|
+
// Do not leave a cancelled request for the extension to consume; it
|
|
115
|
+
// would create an unmanaged tab after the caller has given up.
|
|
116
|
+
this.pending.delete(token);
|
|
114
117
|
throw new Error('Tab wait aborted.');
|
|
118
|
+
}
|
|
115
119
|
const done = this.completed.get(token);
|
|
116
120
|
if (done) {
|
|
117
121
|
this.completed.delete(token);
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Agent Plugins 1.0
|
|
2
|
+
|
|
3
|
+
One browser runtime, two host adapters: native Pi and a portable stdio MCP server.
|
|
4
|
+
|
|
5
|
+
## Installation and distribution
|
|
6
|
+
|
|
7
|
+
Native Pi remains unchanged: `pi install npm:pi-browser-use`. It loads `dist/index.js`,
|
|
8
|
+
uses Pi's trusted settings, and retains `~/.pi/browser-profile` and `~/.pi/browser-artifacts`.
|
|
9
|
+
Do not enable both adapters in the same Pi session; that would register duplicate tools.
|
|
10
|
+
|
|
11
|
+
For a client supporting **Agent Plugins 1.0 and local stdio MCP**, install this npm
|
|
12
|
+
package into a user-controlled directory, then use that client's local-plugin
|
|
13
|
+
installation flow to select the **installed package root**, containing `plugin.json`,
|
|
14
|
+
`mcp.json`, `skills/`, and `dist/`. Node and the package's production dependencies must
|
|
15
|
+
be installed; a source-only Git clone is not a ready-to-run plugin.
|
|
16
|
+
|
|
17
|
+
For example, from an empty directory:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm install --omit=dev pi-browser-use
|
|
21
|
+
# Select this directory in the client's local-plugin loader:
|
|
22
|
+
# <absolute-install-directory>/node_modules/pi-browser-use
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
To test an unpublished branch, use `npm ci && npm run build` in the checkout and
|
|
26
|
+
load that directory. The manifest starts `node ${PLUGIN_ROOT}/dist/mcp-server.js`;
|
|
27
|
+
there is no install-time shell hook, network package download, or hidden Pi dependency
|
|
28
|
+
in that command. Clients without local-plugin loading can register the same script
|
|
29
|
+
as an ordinary stdio MCP server and load the bundled skills separately.
|
|
30
|
+
|
|
31
|
+
Chrome/Chromium must be installed. Tool discovery and `browser_status` do not launch
|
|
32
|
+
Chrome, open a login window, or require a signed-in profile. The first browser action
|
|
33
|
+
starts the configured backend. A plugin-capable client that only supports remote MCP
|
|
34
|
+
cannot run this local browser server.
|
|
35
|
+
|
|
36
|
+
## Configuration and private state
|
|
37
|
+
|
|
38
|
+
The manifest passes the client's `${PLUGIN_DATA}` as `PI_BROWSER_USE_DATA_DIR`.
|
|
39
|
+
The server reads only `<data>/config.json` (a direct `BrowserUseConfig` object):
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"mode": "persistent",
|
|
44
|
+
"headed": false,
|
|
45
|
+
"tabBridgePort": 31973
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Missing configuration uses persistent headless defaults. Invalid JSON, unknown
|
|
50
|
+
fields, and invalid field types fail closed. Pi user settings, project `.pi` files,
|
|
51
|
+
and Pi model credentials are never read by the portable adapter. Environment
|
|
52
|
+
interpolation is not performed inside this configuration file.
|
|
53
|
+
|
|
54
|
+
The data layout is:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
PLUGIN_DATA/
|
|
58
|
+
config.json
|
|
59
|
+
browser-profile/ # named pi-browser-use identity, cookies and site sessions
|
|
60
|
+
browser-profile.* # existing lock, metadata, preferences, ownership/advert files
|
|
61
|
+
artifacts/ # default screenshot and HTML destination
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The plugin root can be read-only after dependencies and build output are installed.
|
|
65
|
+
`browser_status` reports the actual profile and artifact paths; skills must use those
|
|
66
|
+
paths rather than assume `~/.pi`. Each client's plugin data is separate by default:
|
|
67
|
+
signing into one client does not authenticate another client's browser.
|
|
68
|
+
|
|
69
|
+
For standalone MCP, set `PI_BROWSER_USE_DATA_DIR` explicitly. Without it the server
|
|
70
|
+
uses `PLUGIN_DATA`, then `~/.local/share/pi-browser-use` (never Pi's data directory).
|
|
71
|
+
`PI_BROWSER_USE_CONFIG` optionally selects a different **absolute** configuration
|
|
72
|
+
file; an explicitly selected missing file is an error.
|
|
73
|
+
|
|
74
|
+
The existing launch, category, URL restriction, network-redaction, and bridge options
|
|
75
|
+
from `BrowserUseConfig` are supported. `userDataDir` and `executablePath` must be
|
|
76
|
+
absolute paths (a leading `~/` is supported). An explicit `userDataDir` can share a
|
|
77
|
+
**dedicated automation identity** across clients; coordinate profile ownership and
|
|
78
|
+
never point it at the user's daily Chrome directory. The chosen identity is retained
|
|
79
|
+
when switching through fresh or existing mode and back to persistent. `wsHeaders`
|
|
80
|
+
belongs to a host-managed secret-bearing configuration file, not the plugin bundle.
|
|
81
|
+
The core does not disable Chrome's sandbox.
|
|
82
|
+
|
|
83
|
+
## Behavior and host-specific capabilities
|
|
84
|
+
|
|
85
|
+
All curated upstream `browser_*` tools and the management tools (`save_artifact`,
|
|
86
|
+
`doctor`, `switch_mode`, `setup`, `status`, `reauth`, `open_background_tab`) share the
|
|
87
|
+
same runtime. The MCP adapter is not a raw chrome-devtools-mcp configuration: tool
|
|
88
|
+
filtering, network-header redaction, overlay recovery, annotated artifacts, ownership
|
|
89
|
+
checks, per-origin visibility preferences, and background-focus defaults remain in
|
|
90
|
+
place. MCP inputs are validated against each advertised tool's JSON schema.
|
|
91
|
+
|
|
92
|
+
Calls are serialized within a runtime so a mode switch cannot race an active page
|
|
93
|
+
operation. Cancellation propagates to upstream MCP, startup and human setup; stdin
|
|
94
|
+
EOF, MCP disconnect and SIGINT/SIGTERM close the session. Shutdown terminates only a
|
|
95
|
+
browser owned by that runtime, never a borrowed peer/user browser. Abrupt SIGKILL
|
|
96
|
+
still relies on the existing orphan-recovery mechanism. Profile locks cannot be
|
|
97
|
+
reclaimed from a live owner merely because their timestamps are old.
|
|
98
|
+
|
|
99
|
+
Existing mode remains explicit and human-authorized. Background grouped tabs require
|
|
100
|
+
the bundled Chrome extension in `extension/`, just as in native Pi. The loopback tab
|
|
101
|
+
bridge is not a hosted service. Multiple simultaneous Existing-mode runtimes need
|
|
102
|
+
coordinated bridge ports/extension configuration; this migration does not implement
|
|
103
|
+
a shared bridge broker.
|
|
104
|
+
|
|
105
|
+
**Vision:** Native Pi retains optional `visionModel` / `browser_analyze_screenshot`
|
|
106
|
+
through its own model registry. Portable hosts receive standard MCP image content
|
|
107
|
+
from `browser_take_screenshot` and use their own vision capability; the portable
|
|
108
|
+
adapter deliberately does not expose the Pi-registry analysis tool or make implicit
|
|
109
|
+
model/sampling calls. `visionModel` is rejected in portable configuration.
|
|
110
|
+
|
|
111
|
+
**Authentication:** `browser_setup` opens an ordinary headed window on the same
|
|
112
|
+
managed profile, with no automation attached. A human completes login and closes it.
|
|
113
|
+
Use `browser_reauth` for later verification, including `variant: plain` for a provider
|
|
114
|
+
that rejects instrumented sign-in. Human setup can exceed a client's default tool
|
|
115
|
+
request timeout; increase that timeout in the host before starting. Cancellation or
|
|
116
|
+
a nonzero browser exit does not mark setup/verification successful. Never copy daily
|
|
117
|
+
Chrome profiles, cookies, passwords or Pi credentials into a plugin installation.
|
|
118
|
+
|
|
119
|
+
## Validation and release
|
|
120
|
+
|
|
121
|
+
`npm test` exercises the shared runtime, native Pi adapter, MCP schema/routing/error
|
|
122
|
+
boundary, cancellation and auth lifecycle. `npm run test:smoke` packs the npm artifact,
|
|
123
|
+
installs its production dependency closure in a temporary directory **without Pi**,
|
|
124
|
+
and exercises a real stdio process, all tool schemas, status, EOF and SIGTERM.
|
|
125
|
+
`npm run test:browser` adds a real Chrome run against a loopback-only fixture, covering
|
|
126
|
+
navigation, screenshots, artifacts, profile reuse and fresh-mode isolation.
|
|
127
|
+
|
|
128
|
+
Release Please synchronizes `plugin.json.version` with the npm version. The package
|
|
129
|
+
includes both manifests and all skills, while excluding source maps, tests and CI
|
|
130
|
+
helpers. This is a packaging/API compatibility claim, not a claim that every named
|
|
131
|
+
agent client or real-world authentication provider has been tested.
|
package/mcp.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
|
|
3
|
+
"mcpServers": {
|
|
4
|
+
"browser": {
|
|
5
|
+
"type": "stdio",
|
|
6
|
+
"command": "node",
|
|
7
|
+
"args": ["${PLUGIN_ROOT}/dist/mcp-server.js"],
|
|
8
|
+
"cwd": "${PLUGIN_ROOT}",
|
|
9
|
+
"env": {
|
|
10
|
+
"PI_BROWSER_USE_DATA_DIR": "${PLUGIN_DATA}"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-browser-use",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Opinionated browser
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"description": "Opinionated browser automation via chrome-devtools-mcp: native Pi extension and portable Agent Plugins 1.0 skills + MCP server.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"automation",
|
|
7
7
|
"browser",
|
|
@@ -27,7 +27,10 @@
|
|
|
27
27
|
"docs/performance.md",
|
|
28
28
|
"extension",
|
|
29
29
|
"skills",
|
|
30
|
-
"README.md"
|
|
30
|
+
"README.md",
|
|
31
|
+
"plugin.json",
|
|
32
|
+
"mcp.json",
|
|
33
|
+
"docs/agent-plugins.md"
|
|
31
34
|
],
|
|
32
35
|
"type": "module",
|
|
33
36
|
"sideEffects": false,
|
|
@@ -56,7 +59,9 @@
|
|
|
56
59
|
"perf:audit": "node scripts/performance.mjs",
|
|
57
60
|
"preperf:check": "npm run build",
|
|
58
61
|
"perf:check": "node scripts/performance.mjs --check",
|
|
59
|
-
"pretest": "npm run build"
|
|
62
|
+
"pretest": "npm run build",
|
|
63
|
+
"test:smoke": "npm run build && node scripts/plugin-smoke.mjs",
|
|
64
|
+
"test:browser": "npm run build && node scripts/plugin-smoke.mjs --browser"
|
|
60
65
|
},
|
|
61
66
|
"dependencies": {
|
|
62
67
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
package/plugin.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
|
+
"name": "pi-browser-use",
|
|
4
|
+
"version": "0.10.0",
|
|
5
|
+
"description": "Managed persistent, fresh, and existing Chrome sessions with focus-safe browser tools and CLI-first skills.",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "0xPlayerOne"
|
|
8
|
+
},
|
|
9
|
+
"repository": "https://github.com/0xPlayerOne/pi-browser-use",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": ["browser", "chrome", "mcp", "agent-skills", "pi"]
|
|
12
|
+
}
|
|
@@ -1,58 +1,61 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: auth-bootstrap
|
|
3
|
-
description: "
|
|
3
|
+
description: "Initialize or reauthenticate the managed persistent browser profile. Use on a new machine or plugin instance, at a login wall, or when SSO, 2FA, passkeys or provider verification require a human. Works with native Pi and portable MCP hosts."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Auth Bootstrap
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Each managed profile starts empty. Native Pi and portable clients have separate
|
|
9
|
+
profiles by default. Call `browser_status` to identify this instance before doing
|
|
10
|
+
anything: a signed-in daily Chrome or another agent client proves nothing about it.
|
|
11
|
+
Never read, capture or paste passwords, one-time codes or session cookies into chat.
|
|
9
12
|
|
|
10
|
-
##
|
|
13
|
+
## First run: plain headed setup
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
1. A visible Chrome window opens on the persistent profile.
|
|
17
|
-
2. **You** navigate and log in normally — including SSO, 2FA, and passkeys.
|
|
18
|
-
3. Tell the agent you're done. It verifies (account page loads logged-in) and you close the window or it switches back to fresh.
|
|
15
|
+
Select persistent mode when needed, then call `browser_setup`. Explain **before**
|
|
16
|
+
calling it that an ordinary headed window opens on the managed profile, the human
|
|
17
|
+
signs into the needed sites, and they close that window when finished. No browser
|
|
18
|
+
automation is attached to this setup window. Do not automate its credential fields.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Setup waits for the window to close. Use a host tool timeout sufficient for a human
|
|
21
|
+
login; cancellation or browser failure is not success. Successful setup initializes
|
|
22
|
+
the profile, but does not prove that every target site is authenticated.
|
|
21
23
|
|
|
22
|
-
##
|
|
24
|
+
## Expired login or rejected instrumented sign-in
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
In persistent mode, request the human handoff:
|
|
25
27
|
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
+
```text
|
|
29
|
+
browser_reauth({ "url": "https://example.com/" })
|
|
28
30
|
```
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
## Google SSO says "browser or app may not be secure"
|
|
32
|
+
When the provider rejects an instrumented browser, use the plain variant on the
|
|
33
|
+
**same managed identity**, not the user's daily profile:
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
1. **Email + password** on the login form (no Google involved).
|
|
39
|
-
2. **Your daily browser**, which Google already trusts (real history, no
|
|
40
|
-
automation flags). Point the session at it temporarily with
|
|
41
|
-
`mode: existing` and drive the flow there, then switch back.
|
|
42
|
-
3. Complete SSO there once; the persistent profile keeps the resulting
|
|
43
|
-
Cloudflare session cookies either way.
|
|
35
|
+
```text
|
|
36
|
+
browser_reauth({ "url": "https://example.com/", "variant": "plain" })
|
|
37
|
+
```
|
|
44
38
|
|
|
45
|
-
|
|
39
|
+
Only the human completes SSO, 2FA, CAPTCHA, passkeys and device checks. Stop at the
|
|
40
|
+
challenge; never loop attempts. A live peer-owned backend cannot be restarted or
|
|
41
|
+
reauthenticated by this session: coordinate with its owner instead.
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
- **Export/import individual cookies** for HttpOnly session cookies. The tooling (keychain decryption, cookie-store surgery) is fragile; a two-minute headed login beats an hour of debugging.
|
|
49
|
-
- **Reuse the persistent profile for hostile links.** Unknown URLs go through `fresh` — no credentials present, nothing to steal.
|
|
43
|
+
## Resume and verify
|
|
50
44
|
|
|
51
|
-
|
|
45
|
+
After human verification, return persistent automation to headless:
|
|
52
46
|
|
|
53
47
|
```text
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
browser_switch_mode({ "mode": "persistent" })
|
|
49
|
+
browser_list_pages({})
|
|
56
50
|
```
|
|
57
51
|
|
|
58
|
-
|
|
52
|
+
Navigate an explicitly identified page to a benign, task-relevant account page and
|
|
53
|
+
verify its authenticated DOM. For Gmail, load `gmail-auth`; generic Chrome sign-in
|
|
54
|
+
is not proof of Gmail authentication. If only headless execution fails on this
|
|
55
|
+
profile, use persistent headed-background with `rememberSite: true` for that origin,
|
|
56
|
+
not a global downgrade.
|
|
57
|
+
|
|
58
|
+
Never clone daily Chrome profiles, export/import cookies, or point `userDataDir` at
|
|
59
|
+
the user's daily browser directory. Existing mode is a separate identity and requires
|
|
60
|
+
the user's explicit choice. Its cookies do not migrate back to persistent mode.
|
|
61
|
+
Use fresh mode only for anonymous checks and clean-room reproductions.
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: browser-policy
|
|
3
|
-
description: "Browser-use policy for
|
|
3
|
+
description: "Browser-use policy for agents. Use before any browser_* tool call. Prefer CLIs and APIs over browser automation, default to a dedicated persistent headless profile, use fresh mode for anonymous checks, and never steal user focus."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Browser Policy
|
|
7
7
|
|
|
8
|
+
These policies apply to native Pi and portable Agent Plugins/MCP hosts. Call
|
|
9
|
+
`browser_status` for this instance's profile and artifact paths; never infer
|
|
10
|
+
them from another client. Authentication does not transfer between profiles.
|
|
11
|
+
|
|
8
12
|
`browser_*` tools (this `pi-browser-use` package, powered by `chrome-devtools-mcp` — not Playwright) drive a real Chrome. They are the tool of last resort, not the first.
|
|
9
13
|
|
|
10
14
|
## Decision order
|
|
@@ -15,14 +19,14 @@ description: "Browser-use policy for Pi agents. Use before any browser_* tool ca
|
|
|
15
19
|
|
|
16
20
|
## Session modes
|
|
17
21
|
|
|
18
|
-
- **Default: persistent headless** (`mode: persistent`).
|
|
22
|
+
- **Default: persistent headless** (`mode: persistent`). The plugin's own browser on its dedicated profile (the profile reported by `browser_status`): self-launched Chrome, no window, never steals focus, no consent popups. Log in once via `browser_setup`; cookies persist. Use for everything unless there's a reason not to. Pass `headed: true` to watch, and warn the user before any headed launch.
|
|
19
23
|
- **Clean room** (`mode: fresh`). Ephemeral profile, thrown away each session. Use for anonymous checks, hostile links, and "does it render logged-out?" verifications — never for anything needing identity.
|
|
20
|
-
- **Existing Chrome** (`mode: existing`) attaches to the user's running Chrome — intrusive (drives the daily browser, sees all tabs). Avoid unless the user explicitly asks. First attach shows Chrome's "Allow remote debugging?" consent popup (once per session — click Allow).
|
|
24
|
+
- **Existing Chrome** (`mode: existing`) attaches to the user's running Chrome — intrusive (drives the daily browser, sees all tabs). Avoid unless the user explicitly asks. First attach shows Chrome's "Allow remote debugging?" consent popup (once per session — click Allow). Agent tabs must be opened with `browser_open_background_tab` (extension-brokered into the collapsed `pi-browser-use` group), never raw `browser_new_page`. Closing the last agent tab dissolves the group automatically; `browser_close_page` refuses tabs this session didn't open unless `force: true` was explicitly requested.
|
|
21
25
|
- **Switch, don't restart**: `browser_switch_mode` moves between persistent, fresh, and existing mid-session. Start persistent; drop to fresh for clean-room checks; touch existing only when the user explicitly asks.
|
|
22
26
|
- **Hard blocks escalate themselves**: login walls in fresh sessions suggest the switch call; login walls and bot challenges in authenticated sessions rebuild headed and prompt the human. Once per call, never looping, never in attached sessions — and a headed popup from a block is the one case where stealing focus is the job, not a bug.
|
|
23
|
-
- **Visual analysis** (`browser_analyze_screenshot`, only when `visionModel` is configured) is for canvas/WebGL scenes and coordinate clicks the tree cannot describe — not a substitute for reading the snapshot first.
|
|
27
|
+
- **Visual analysis** (`browser_analyze_screenshot`, native Pi only when `visionModel` is configured; other hosts analyze the MCP image from `browser_take_screenshot`) is for canvas/WebGL scenes and coordinate clicks the tree cannot describe — not a substitute for reading the snapshot first.
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
Chrome flags apply only to a managed launch (direct or upstream), never to an already-running browser attached with `autoConnect`/`browserUrl`. On macOS `--start-minimized` is ignored; only `headless: true` truly hides the window.
|
|
26
30
|
|
|
27
31
|
## Bot walls and logins
|
|
28
32
|
|
|
@@ -45,7 +49,7 @@ Turnstile, device checks, SSO/2FA cannot be automated away. On hitting one: stop
|
|
|
45
49
|
|
|
46
50
|
## Parallel agents (shared browser)
|
|
47
51
|
|
|
48
|
-
Many agents share one
|
|
52
|
+
Many agents share one plugin-owned Chrome. Separation is by tabs, not windows:
|
|
49
53
|
|
|
50
54
|
- Always pass an explicit `pageId` (from your own `browser_list_pages`) to every page-scoped call. Never assume the selected page is yours.
|
|
51
55
|
- Open your own tabs (`browser_new_page` background, or `browser_open_background_tab` in existing mode). They are claimed to your session automatically.
|
|
@@ -55,16 +59,16 @@ Many agents share one Pi-owned Chrome. Separation is by tabs, not windows:
|
|
|
55
59
|
|
|
56
60
|
## Browser mode rules
|
|
57
61
|
|
|
58
|
-
1. Prefer Persistent (the default) for everything:
|
|
62
|
+
1. Prefer Persistent (the default) for everything: the plugin's browser, invisible, no popups.
|
|
59
63
|
2. Use Fresh only for anonymous/stateless browsing: hostile links, logged-out checks, clean-room reproductions.
|
|
60
|
-
3. Persistent uses
|
|
61
|
-
4. If Persistent has never been initialized, launch the
|
|
64
|
+
3. Persistent uses the plugin's dedicated browser profile — never the user's daily Chrome data.
|
|
65
|
+
4. If Persistent has never been initialized, launch the managed browser setup flow (headed once, human signs in, close the window).
|
|
62
66
|
5. Never attempt to automate credentials, CAPTCHA, 2FA, passkeys, or security challenges that require the user.
|
|
63
67
|
6. When authentication is required, request the headed authentication flow.
|
|
64
68
|
7. After authentication, prefer restarting Persistent headless.
|
|
65
69
|
8. If a site fails specifically because it is headless, retry using Persistent headed-background (per-origin; never downgrade every site).
|
|
66
|
-
9. In headed-background mode, never request foreground focus unless the user explicitly asked to watch or
|
|
70
|
+
9. In headed-background mode, never request foreground focus unless the user explicitly asked to watch or the agent is handing over auth.
|
|
67
71
|
10. Use Existing only when the user explicitly chose it or Persistent cannot provide the required existing browser/session state.
|
|
68
|
-
11. In Existing mode, all new
|
|
69
|
-
12. Never activate
|
|
70
|
-
13. Never close or modify unrelated user tabs;
|
|
72
|
+
11. In Existing mode, all new agent tabs must be created through the bundled Chrome extension and placed in the collapsed `pi-browser-use` group.
|
|
73
|
+
12. Never activate agent-created Existing-mode tabs by default.
|
|
74
|
+
13. Never close or modify unrelated user tabs; close only this session's explicitly identified tabs; do not assume session shutdown closes tabs in a borrowed browser.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gmail-auth
|
|
3
|
-
description: "Verify Gmail authentication in the persistent
|
|
3
|
+
description: "Verify Gmail authentication in the persistent managed browser profile. Use when a task needs the Gmail inbox, after browser_setup, or when Google shows a login or verification challenge."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Gmail Auth
|
|
@@ -10,11 +10,14 @@ Authentication state lives in this skill, not in a generic browser heuristic: on
|
|
|
10
10
|
## Verify first
|
|
11
11
|
|
|
12
12
|
```text
|
|
13
|
-
|
|
13
|
+
browser_new_page({ "url": "https://mail.google.com/", "background": true })
|
|
14
14
|
browser_take_snapshot({ "pageId": <id> })
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Use the page ID returned by `browser_list_pages`. In explicitly selected Existing
|
|
18
|
+
mode, use `browser_open_background_tab` instead so the bundled Chrome extension
|
|
19
|
+
creates a grouped inactive tab. Check `browser_status` for the active profile; a
|
|
20
|
+
login in another client or daily Chrome does not authenticate this instance.
|
|
18
21
|
|
|
19
22
|
## Authenticated
|
|
20
23
|
|