patchright-cli 0.9.1__tar.gz → 0.11.0__tar.gz

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.
Files changed (109) hide show
  1. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/.claude-plugin/marketplace.json +1 -1
  2. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/.github/workflows/ci.yml +2 -2
  3. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/CLAUDE.md +9 -5
  4. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/CONTRIBUTING.md +1 -1
  5. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/PKG-INFO +107 -16
  6. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/README.md +104 -11
  7. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/docs/daemon-protocol.md +44 -0
  8. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/docs/installation.md +1 -1
  9. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/pyproject.toml +7 -7
  10. patchright_cli-0.11.0/scripts/gen_skill.py +79 -0
  11. patchright_cli-0.11.0/scripts/ref_sweep/classify.py +207 -0
  12. patchright_cli-0.11.0/scripts/ref_sweep/fixtures/common.js +9 -0
  13. patchright_cli-0.11.0/scripts/ref_sweep/fixtures/controls.html +46 -0
  14. patchright_cli-0.11.0/scripts/ref_sweep/fixtures/delayed.html +18 -0
  15. patchright_cli-0.11.0/scripts/ref_sweep/fixtures/dialog.html +12 -0
  16. patchright_cli-0.11.0/scripts/ref_sweep/fixtures/iframe.html +9 -0
  17. patchright_cli-0.11.0/scripts/ref_sweep/fixtures/iframe_child.html +9 -0
  18. patchright_cli-0.11.0/scripts/ref_sweep/fixtures/large.html +161 -0
  19. patchright_cli-0.11.0/scripts/ref_sweep/fixtures/nav.html +31 -0
  20. patchright_cli-0.11.0/scripts/ref_sweep/fixtures/nav2.html +10 -0
  21. patchright_cli-0.11.0/scripts/ref_sweep/fixtures/nested.html +21 -0
  22. patchright_cli-0.11.0/scripts/ref_sweep/fixtures/offscreen.html +10 -0
  23. patchright_cli-0.11.0/scripts/ref_sweep/fixtures/shadow.html +17 -0
  24. patchright_cli-0.11.0/scripts/ref_sweep/results/after.json +3920 -0
  25. patchright_cli-0.11.0/scripts/ref_sweep/results/before.json +3950 -0
  26. patchright_cli-0.11.0/scripts/ref_sweep/results/diff-report.md +187 -0
  27. patchright_cli-0.11.0/scripts/ref_sweep/results/diff.txt +5247 -0
  28. patchright_cli-0.11.0/scripts/ref_sweep/sweep.py +627 -0
  29. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/skills/patchright-cli/SKILL.md +247 -48
  30. patchright_cli-0.11.0/skills/patchright-cli/references/snapshot-refs.md +155 -0
  31. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/skills/patchright-cli/references/storage-state.md +1 -1
  32. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/src/patchright_cli/__init__.py +1 -1
  33. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/src/patchright_cli/__main__.py +1 -1
  34. patchright_cli-0.11.0/src/patchright_cli/_entry.py +26 -0
  35. patchright_cli-0.11.0/src/patchright_cli/agent_hooks.py +470 -0
  36. patchright_cli-0.11.0/src/patchright_cli/cli.py +2341 -0
  37. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/src/patchright_cli/daemon.py +1629 -358
  38. patchright_cli-0.11.0/src/patchright_cli/daemon_pid.py +168 -0
  39. patchright_cli-0.11.0/src/patchright_cli/debugger.py +240 -0
  40. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/src/patchright_cli/mcp_server.py +264 -12
  41. patchright_cli-0.11.0/src/patchright_cli/snapshot.py +55 -0
  42. patchright_cli-0.11.0/src/patchright_cli/snapshot_text.py +535 -0
  43. patchright_cli-0.11.0/src/patchright_cli/toon.py +281 -0
  44. patchright_cli-0.11.0/src/patchright_cli/values.py +316 -0
  45. patchright_cli-0.11.0/tests/detect_fixture.html +39 -0
  46. patchright_cli-0.11.0/tests/ref_helpers.py +24 -0
  47. patchright_cli-0.11.0/tests/test_agent_hooks.py +414 -0
  48. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_annotate.py +1 -3
  49. patchright_cli-0.11.0/tests/test_cli_audit.py +272 -0
  50. patchright_cli-0.11.0/tests/test_cli_axi.py +570 -0
  51. patchright_cli-0.11.0/tests/test_cli_home.py +256 -0
  52. patchright_cli-0.11.0/tests/test_daemon_audit.py +201 -0
  53. patchright_cli-0.11.0/tests/test_daemon_axi.py +515 -0
  54. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_daemon_handlers.py +635 -139
  55. patchright_cli-0.11.0/tests/test_daemon_pid.py +245 -0
  56. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_daemon_token.py +3 -1
  57. patchright_cli-0.11.0/tests/test_debugger.py +389 -0
  58. patchright_cli-0.11.0/tests/test_e2e.py +940 -0
  59. patchright_cli-0.11.0/tests/test_i41_extras.py +494 -0
  60. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_mcp.py +49 -1
  61. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_navigation_policy.py +7 -10
  62. patchright_cli-0.11.0/tests/test_passkeys.py +304 -0
  63. patchright_cli-0.11.0/tests/test_pick_locator.py +368 -0
  64. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_profiles.py +16 -2
  65. patchright_cli-0.11.0/tests/test_skill_sync.py +60 -0
  66. patchright_cli-0.11.0/tests/test_snapshot_refs.py +236 -0
  67. patchright_cli-0.11.0/tests/test_snapshot_text.py +340 -0
  68. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_tabs.py +14 -14
  69. patchright_cli-0.11.0/tests/test_toon.py +275 -0
  70. patchright_cli-0.11.0/tests/test_webmcp.py +266 -0
  71. patchright_cli-0.11.0/tests/webmcp_fixture.html +21 -0
  72. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/uv.lock +30 -847
  73. patchright_cli-0.9.1/skills/patchright-cli/references/snapshot-refs.md +0 -142
  74. patchright_cli-0.9.1/src/patchright_cli/cli.py +0 -987
  75. patchright_cli-0.9.1/src/patchright_cli/ref_registry.py +0 -339
  76. patchright_cli-0.9.1/src/patchright_cli/snapshot.py +0 -48
  77. patchright_cli-0.9.1/tests/test_e2e.py +0 -238
  78. patchright_cli-0.9.1/tests/test_ref_registry.py +0 -608
  79. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/.claude-plugin/skills/browser-automation.json +0 -0
  80. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/.github/dependabot.yml +0 -0
  81. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/.github/workflows/publish-docker.yml +0 -0
  82. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/.github/workflows/publish.yml +0 -0
  83. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/.gitignore +0 -0
  84. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/.pre-commit-config.yaml +0 -0
  85. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/Dockerfile +0 -0
  86. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/GLOSSARY.md +0 -0
  87. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/LICENSE +0 -0
  88. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/Makefile +0 -0
  89. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/compose.yml +0 -0
  90. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/docs/mcp-architecture.svg +0 -0
  91. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/patchright-cli +0 -0
  92. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/patchright-cli.cmd +0 -0
  93. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/skills/patchright-cli/references/request-mocking.md +0 -0
  94. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/skills/patchright-cli/references/running-code.md +0 -0
  95. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/skills/patchright-cli/references/session-management.md +0 -0
  96. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/skills/patchright-cli/references/tracing.md +0 -0
  97. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/skills/patchright-cli/references/video-recording.md +0 -0
  98. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/src/patchright_cli/dashboard.py +0 -0
  99. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/__init__.py +0 -0
  100. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/fixture.html +0 -0
  101. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_attach.py +0 -0
  102. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_cli_config.py +0 -0
  103. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_daemon_info.py +0 -0
  104. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_daemon_read.py +0 -0
  105. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_docker.py +0 -0
  106. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_emulation.py +0 -0
  107. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_network_guard.py +0 -0
  108. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_packaging.py +0 -0
  109. {patchright_cli-0.9.1 → patchright_cli-0.11.0}/tests/test_supply_chain.py +0 -0
@@ -5,7 +5,7 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "Anti-detect browser automation CLI & Skills for AI agents, powered by Patchright",
8
- "version": "0.9.1"
8
+ "version": "0.11.0"
9
9
  },
10
10
  "plugins": [
11
11
  {
@@ -22,10 +22,10 @@ jobs:
22
22
  strategy:
23
23
  matrix:
24
24
  os: [ubuntu-latest, windows-latest]
25
- python-version: ["3.10", "3.12"]
25
+ python-version: ["3.12", "3.13"]
26
26
  include:
27
27
  - os: macos-latest
28
- python-version: "3.12"
28
+ python-version: "3.13"
29
29
  runs-on: ${{ matrix.os }}
30
30
  steps:
31
31
  - uses: actions/checkout@v7
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
4
4
 
5
5
  ## Project Overview
6
6
 
7
- patchright-cli is an anti-detect browser automation CLI built on [Patchright](https://github.com/kaliiiiiiiiii/patchright-python) (undetected Playwright fork). It provides the same command interface as Microsoft's playwright-cli but bypasses bot detection (Akamai, Cloudflare, etc.).
7
+ patchright-cli is an anti-detect browser automation CLI built on [Patchright](https://github.com/kaliiiiiiiiii/patchright-python) (undetected Playwright fork). Its commands follow Microsoft's playwright-cli, but it bypasses bot detection (Akamai, Cloudflare, etc.) and is not a drop-in replacement: playwright-cli features Patchright cannot support (other browsers, extensions) are left out, and unknown flags are rejected with exit 2 rather than ignored.
8
8
 
9
9
  ## Development Setup
10
10
 
@@ -37,6 +37,9 @@ pytest tests/test_e2e.py -v
37
37
 
38
38
  # Lint
39
39
  pre-commit run --all-files
40
+
41
+ # SKILL.md command block in sync with COMMAND_SPECS (rewrite without --check)
42
+ python scripts/gen_skill.py --check
40
43
  ```
41
44
 
42
45
  ## Architecture
@@ -47,11 +50,11 @@ Three-component client-daemon-browser design:
47
50
  CLI (cli.py) --TCP:9321--> Daemon (daemon.py) --Patchright--> Chrome
48
51
  ```
49
52
 
50
- - **CLI (`src/patchright_cli/cli.py`)**: Stateless thin client. Parses argv manually (not click subcommands), builds a JSON `{command, args, options, cwd}` message, sends it over a length-prefixed TCP socket to the daemon, prints the response, and exits. All commands are defined in the `COMMANDS_HELP` dict and `ALL_COMMANDS` list.
53
+ - **CLI (`src/patchright_cli/cli.py`)**: Stateless thin client. Parses argv manually (not click subcommands), builds a JSON `{command, args, options, cwd}` message, sends it over a length-prefixed TCP socket to the daemon, prints the response, and exits. All commands are defined in the `COMMAND_SPECS` dict (usage, summary, flags, examples; `COMMANDS_HELP` and `ALL_COMMANDS` derive from it) and grouped for the manual in `COMMAND_CATEGORIES`. With no arguments it prints the home view (`_print_home`): live daemon state from an already-running daemon only, never starting one. `--toon` renders a reply's `data` field with `toon.py`. A failed reply, whatever the daemon's wording, prints through `_failure_lines()`: `error: <message>`, detail lines, then `help: <next step>` lines (exit 1, or 2 when the reply carries `exit_code: 2`); `--json` adds `error`/`help` fields.
51
54
 
52
55
  - **Daemon (`src/patchright_cli/daemon.py`)**: Long-running async process managing browser sessions. Auto-spawned on `open` via `ensure_daemon_running()` which launches a subprocess. Uses `DaemonState` → multiple `Session` objects, each owning a Patchright persistent browser context. Command dispatch uses `@register()` decorated handlers in `COMMAND_HANDLERS` dict, dispatched by `handle_command()`. Console capture uses CDP sessions (not Playwright's `page.on('console')`) because Patchright suppresses it.
53
56
 
54
- - **Snapshot (`src/patchright_cli/snapshot.py`)**: Uses Playwright's native `aria_snapshot()` to get the accessibility tree. `RefRegistry` annotates each node with sequential refs (`e1`, `e2`, ...). Snapshots are saved as YAML to `.patchright-cli/` in the caller's cwd.
57
+ - **Snapshot (`src/patchright_cli/snapshot.py`, `snapshot_text.py`)**: One full-page `page.aria_snapshot(mode="ai")` per tab (kept as `Tab.last_raw`) gives Playwright's own refs (`e5`, `f3e5` in iframes and after navigation); `page.get_by_ref` resolves them. Any other `aria_snapshot()` call replaces the page's ref map, so `snapshot.py` is the only caller (a unit test greps for it) and scoping, `--depth`, `-i` and `find` are text operations in `snapshot_text.py`. `scripts/ref_sweep/` is the before/after sweep of every ref-taking command; rerun it on a patchright bump. Snapshots are saved as YAML to `.patchright-cli/` in the caller's cwd.
55
58
 
56
59
  ## Key Design Decisions
57
60
 
@@ -59,8 +62,9 @@ CLI (cli.py) --TCP:9321--> Daemon (daemon.py) --Patchright--> Chrome
59
62
  - Headed by default (headless is more detectable)
60
63
  - Default daemon port: 9321, profiles stored at `~/.patchright-cli/profiles/<profile-name>`; a session's profile defaults to its session name (`--profile=<name>` overrides, a value with `/` or `\` is a directory). One session per profile at a time
61
64
  - CLI-daemon protocol: length-prefixed (4-byte big-endian `!I`) JSON over TCP; every message carries a `token` field read from `~/.patchright-cli/daemon-<port>.token` (written 0600 by the daemon before it listens), and the daemon rejects messages without the right one
62
- - CLI parses argv manually in `main()` — click is only used for `click.echo()`, not subcommands. New commands need a `COMMANDS_HELP` entry and a `@register("<name>")` handler in daemon.py; only session and lifecycle commands (open, attach, close, kill-all, ...) live in `handle_command()` itself
65
+ - CLI parses argv manually in `main()` — click is only used for `click.echo()`, not subcommands. New commands need a `COMMAND_SPECS` entry, a place in `COMMAND_CATEGORIES`, and a `@register("<name>")` handler in daemon.py, then `python scripts/gen_skill.py` to refresh the generated command block in `skills/patchright-cli/SKILL.md` (`--check` exits 1 when stale; `tests/test_skill_sync.py` enforces it); only session and lifecycle commands (open, attach, close, kill-all, ...) live in `handle_command()` itself
66
+ - Flag and positional value shapes (numbers, choices, flags that need a value) live in `src/patchright_cli/values.py` (`FLAG_KINDS`, `ARG_KINDS`); the CLI checks them before contacting the daemon (exit 2) and the daemon checks them again for clients that skip the CLI. A new numeric or enum flag needs an entry there (`tests/test_cli_audit.py` enforces it)
63
67
  - Version must be updated in `pyproject.toml`, `src/patchright_cli/__init__.py` and `.claude-plugin/marketplace.json` (then run `uv lock` to sync the lock file; `tests/test_packaging.py` checks they match)
64
68
  - `python -m patchright_cli` works via `__main__.py`
65
- - Uses hatchling as build backend, ruff for linting (line-length=120, target py310)
69
+ - Uses hatchling as build backend, ruff for linting (line-length=120, target py312)
66
70
  - Ruff rules: E, F, I, W, UP, B, SIM (ignores E501, SIM105, E402)
@@ -31,7 +31,7 @@ pre-commit install
31
31
 
32
32
  ## Code Style
33
33
 
34
- - Python 3.10+
34
+ - Python 3.12+
35
35
  - Formatted with [Ruff](https://github.com/astral-sh/ruff) (enforced via pre-commit)
36
36
  - Keep the daemon lightweight — avoid heavy dependencies
37
37
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: patchright-cli
3
- Version: 0.9.1
3
+ Version: 0.11.0
4
4
  Summary: Anti-detect browser automation CLI using Patchright (undetected Playwright fork)
5
5
  Project-URL: Homepage, https://github.com/AhaiMk01/patchright-cli
6
6
  Project-URL: Repository, https://github.com/AhaiMk01/patchright-cli
@@ -14,16 +14,14 @@ Classifier: Environment :: Console
14
14
  Classifier: Intended Audience :: Developers
15
15
  Classifier: License :: OSI Approved :: Apache Software License
16
16
  Classifier: Programming Language :: Python :: 3
17
- Classifier: Programming Language :: Python :: 3.10
18
- Classifier: Programming Language :: Python :: 3.11
19
17
  Classifier: Programming Language :: Python :: 3.12
20
18
  Classifier: Programming Language :: Python :: 3.13
21
19
  Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
22
20
  Classifier: Topic :: Software Development :: Testing
23
- Requires-Python: >=3.10
21
+ Requires-Python: >=3.12
24
22
  Requires-Dist: aiohttp>=3.9
25
23
  Requires-Dist: click
26
- Requires-Dist: patchright
24
+ Requires-Dist: patchright<1.65,>=1.64
27
25
  Requires-Dist: pywin32>=306; sys_platform == 'win32'
28
26
  Requires-Dist: pyyaml
29
27
  Provides-Extra: dev
@@ -46,7 +44,7 @@ Description-Content-Type: text/markdown
46
44
  [![GitHub issues](https://img.shields.io/github/issues/AhaiMk01/patchright-cli?label=Issues)](https://github.com/AhaiMk01/patchright-cli/issues)
47
45
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
48
46
 
49
- Anti-detect browser automation CLI. Same command interface as [Microsoft's playwright-cli](https://github.com/microsoft/playwright-cli) but using [Patchright](https://github.com/kaliiiiiiiiii/patchright-python) (undetected Playwright fork) to bypass bot detection.
47
+ Anti-detect browser automation CLI. Commands follow [Microsoft's playwright-cli](https://github.com/microsoft/playwright-cli), but it uses [Patchright](https://github.com/kaliiiiiiiiii/patchright-python) (undetected Playwright fork) to bypass bot detection.
50
48
 
51
49
  [Install](#install) · [Quick Start](#quick-start) · [Commands](#-commands) · [Snapshots](#snapshots) · [Agent Integration](#agent-integration)
52
50
 
@@ -55,7 +53,7 @@ Anti-detect browser automation CLI. Same command interface as [Microsoft's playw
55
53
  | | Feature |
56
54
  |---|---|
57
55
  | :shield: | Bypasses Akamai, Cloudflare, and other anti-bot systems |
58
- | :rocket: | Same command interface as playwright-cli — zero learning curve |
56
+ | :rocket: | playwright-cli's command names and arguments — little to relearn |
59
57
  | :robot: | Built for AI agents (Claude Code, Codex, etc.) with YAML snapshots |
60
58
  | :zap: | Daemon architecture — browser stays open between commands |
61
59
  | :package: | `pip install` / `uvx` — no Docker, no config files |
@@ -85,7 +83,7 @@ curl -s https://raw.githubusercontent.com/AhaiMk01/patchright-cli/main/docs/inst
85
83
  </details>
86
84
 
87
85
  > [!IMPORTANT]
88
- > **Requirements:** Python 3.10+ and Google Chrome
86
+ > **Requirements:** Python 3.12+ and Google Chrome
89
87
 
90
88
  ```bash
91
89
  # Recommended — always runs latest version, no install needed
@@ -235,7 +233,7 @@ graph LR
235
233
  |-----------|------|
236
234
  | **Daemon** (`daemon.py`) | Long-running process managing browser sessions via Patchright. Auto-starts on first `open`. |
237
235
  | **CLI** (`cli.py`) | Thin client — connects, sends command, prints result, disconnects. Browser stays open. |
238
- | **Snapshot** (`snapshot.py`) | Playwright `aria_snapshot()` accessibility tree, annotated with sequential `[ref=eN]` handles for element targeting. |
236
+ | **Snapshot** (`snapshot.py`) | Playwright's AI-mode `aria_snapshot()` accessibility tree, iframes included, with Playwright's own `[ref=e5]` handles, resolved with `get_by_ref`. |
239
237
 
240
238
  ### Daemon token
241
239
 
@@ -246,6 +244,10 @@ The daemon only listens on `127.0.0.1`, but any local process can reach that por
246
244
  - Run the CLI as the same user, with the same home directory, as the daemon. In Docker the MCP server and daemon share a user and `HOME`, so this holds.
247
245
  - An older CLI talking to a newer daemon gets an error saying the daemon requires an auth token: upgrade, or stop the daemon (`patchright-cli kill-all` from the newer install, or end the process). A newer CLI talking to an older daemon finds no token file and sends none, which the older daemon accepts.
248
246
 
247
+ ### Stopping a stuck daemon
248
+
249
+ The daemon runs without a window. `kill-all` asks it to close every session and exit. If it does not answer within 20 seconds, or with `--force`, the CLI ends the daemon process and the browsers it launched (`taskkill /T` on Windows, the daemon's process group elsewhere). It finds the process through `~/.patchright-cli/daemon-<port>.pid`, which the daemon writes at startup with its PID and start time, and kills only a process whose start time still matches, so a reused PID is never touched. A daemon from a version that writes no PID file has to be ended by hand: its command line contains `patchright_cli.daemon`.
250
+
249
251
  ### Daemon client protocol
250
252
 
251
253
  Third-party clients can use the daemon TCP interface directly. The
@@ -291,6 +293,10 @@ patchright-cli find "text" # Search snapshot for text
291
293
  patchright-cli find --regex "a|b" # Search by regex
292
294
  patchright-cli find "text" --all # Include text/paragraph nodes
293
295
  patchright-cli find "text" --limit=50 # Cap hits (default 20)
296
+ patchright-cli find --role=button --description="Deletes" # By role + accessible name/description
297
+ patchright-cli html # Page HTML (first 8000 chars; --max-chars=0 for all)
298
+ patchright-cli html --include-shadow --filename=page.html # With open shadow roots, to a file
299
+ patchright-cli html e5 # One element's outerHTML (or --selector=CSS)
294
300
  patchright-cli eval <expr> # Run JavaScript
295
301
  patchright-cli eval --file=script.js # Run JS from file
296
302
  patchright-cli run-code <code> # Run JS with return value
@@ -396,6 +402,19 @@ patchright-cli sessionstorage-delete <key>
396
402
  patchright-cli sessionstorage-clear
397
403
  ```
398
404
 
405
+ ### Passkeys
406
+ A virtual WebAuthn authenticator for testing passkey sign-ups and logins. The first `passkey-*` command installs it in the session, overriding `navigator.credentials.create()` / `.get()` in every page (a page can notice the override, so it stays off until asked for). **Run a `passkey-*` command (e.g. `passkey-list`) before the page calls WebAuthn**: until then the page gets Chrome's native OS passkey dialog and hangs. Passkeys live in the session only; use `passkey-export` / `passkey-import` to keep them (the export holds private keys and is written owner-only; keep it out of version control).
407
+ ```bash
408
+ patchright-cli passkey-list # Installs the authenticator, lists passkeys (no keys shown)
409
+ patchright-cli passkey-list --rp-id=example.com
410
+ patchright-cli passkey-add example.com # Seed a new P-256 passkey
411
+ patchright-cli passkey-add example.com --id=<b64url> --user-handle=<b64url> --private-key=<b64url> --public-key=<b64url> --sign-count=5
412
+ patchright-cli passkey-delete <credential-id>
413
+ patchright-cli passkey-clear [--rp-id=example.com]
414
+ patchright-cli passkey-export passkeys.json # Includes private keys
415
+ patchright-cli passkey-import passkeys.json
416
+ ```
417
+
399
418
  ### Request Mocking
400
419
  ```bash
401
420
  patchright-cli route "**/*.jpg" --status=404
@@ -412,7 +431,8 @@ patchright-cli unroute # Remove all routes
412
431
  ```bash
413
432
  patchright-cli tracing-start
414
433
  patchright-cli tracing-stop # Saves .zip trace file
415
- patchright-cli video-start # Start video recording (CDP screencast)
434
+ patchright-cli video-start # Start real-time video recording at 25 fps (CDP screencast)
435
+ patchright-cli video-start --fps=60 # Another frame rate, 1-60
416
436
  patchright-cli video-stop # Stop and save video (requires ffmpeg for .webm)
417
437
  patchright-cli video-stop --filename=recording.webm
418
438
  patchright-cli show --annotate # Ask a human to mark up the page, wait for it
@@ -432,15 +452,57 @@ patchright-cli network-state-set online # Restore connectivity
432
452
 
433
453
  ### DevTools
434
454
  ```bash
435
- patchright-cli console # All console messages
455
+ patchright-cli console # Start capture / show captured console messages
436
456
  patchright-cli console warning # Filter by level
437
457
  patchright-cli console --clear # Clear after printing
438
458
  ```
439
459
 
460
+ The first `console` call enables CDP Runtime capture for every page in the session,
461
+ including tabs and popups opened later. Messages from before capture starts are
462
+ unavailable: run `console` before reproducing an issue, then call it again to read
463
+ the messages. Capture can make automation detectable and stays enabled until the
464
+ session closes; `--clear` only clears the message buffer. A new session starts
465
+ with capture disabled.
466
+
467
+ Two DevTools commands leave traces a page can see. `highlight` draws inside an
468
+ `<x-pw-glass>` element under `<html>`; `highlight --hide` removes it once no
469
+ highlight is left. `pick-locator` runs only with `--detectable`: it installs
470
+ Playwright's recorder, which puts `window.playwright`, `__pw_*` globals and an
471
+ `<x-pw-glass>` element into every page of the session until the session closes.
472
+
440
473
  ### Output
441
474
  ```bash
442
475
  patchright-cli --raw eval --file=s.js # Raw output (no page/snapshot decoration)
443
476
  patchright-cli --raw snapshot > p.yml # Pipe raw snapshot to file
477
+ patchright-cli --json tab-list # Whole reply as JSON ({success, output, data, ...})
478
+ patchright-cli --toon tab-list # Structured result as TOON
479
+ ```
480
+
481
+ `--toon` prints a reply's structured `data` as [TOON](https://github.com/toon-format/spec), a compact
482
+ format for agents: `list`, `tab-list`, `cookie-list`, `localstorage-list`, `sessionstorage-list`,
483
+ `route-list`, `console`, `network`, `profile-list` and `find` give a table, `url` and `title` a single
484
+ field. A cut-short list adds `total` and a `help:` line. Commands without structured data, and errors,
485
+ print exactly as they do without the flag. `--json` and `--toon` together are a usage error.
486
+
487
+ ```
488
+ tabs[2]{index,title,url,active}:
489
+ 0,Example Domain,"https://example.com/",true
490
+ 1,"","about:blank",false
491
+ ```
492
+
493
+ Run with no arguments, `patchright-cli` prints a short home view instead of the manual (that is
494
+ `--help`): where the binary is, whether the daemon is running on the port (`--port=N` picks another),
495
+ the open sessions with their URL and tab count, and what to run next. It only asks a daemon that is
496
+ already running and never starts one. Add `--toon` or `--json` for the same state as data.
497
+
498
+ ```
499
+ ~/.local/bin/patchright-cli v0.10.0 -- anti-detect Chrome automation CLI (playwright-cli style commands)
500
+ daemon: running on port 9321 (1 session)
501
+ sessions[1]{name,status,url,tabs}:
502
+ default,open,"https://example.com/",2
503
+ help: patchright-cli snapshot (element refs for the current page; -s=<name> for another session)
504
+ help: patchright-cli list (sessions and their tabs)
505
+ help: patchright-cli --help (all commands); patchright-cli <command> --help (one command)
444
506
  ```
445
507
 
446
508
  ### Setup
@@ -455,7 +517,8 @@ patchright-cli -s=mysession click e6
455
517
  patchright-cli -s=mysession close
456
518
  patchright-cli list # List all sessions
457
519
  patchright-cli close-all
458
- patchright-cli kill-all
520
+ patchright-cli kill-all # Stop the daemon; force-stops it if it does not answer
521
+ patchright-cli kill-all --force # Kill the daemon and its browsers without asking
459
522
  patchright-cli delete-data # Delete the profile named after the session
460
523
  patchright-cli profile-list # Profiles, size, and which session uses each
461
524
  patchright-cli profile-delete <name> # Delete an idle named profile
@@ -468,10 +531,36 @@ patchright-cli --port=9322 open # Custom daemon port
468
531
 
469
532
  ## Agent Integration
470
533
 
471
- Works with Claude Code, Cursor, Gemini CLI, Codex, and [40+ other agents](https://github.com/vercel-labs/skills).
534
+ The CLI follows the [AXI](https://github.com/kunchenguid/axi) standard for agent-facing tools: errors and hints on stdout, exit 2 for usage errors, `(no-op)` for repeated actions, and a no-argument home view with live state.
535
+
536
+ There are two ways to teach your agent about patchright-cli. Both get it to the same place, so you only need one.
537
+
538
+ | | Session hook | Skill |
539
+ |---|---|---|
540
+ | Install | `patchright-cli install --hooks` | `npx skills add AhaiMk01/patchright-cli` or `patchright-cli install --skills` |
541
+ | What the agent gets | Live state (open sessions, the commands to drive them) at the start of every session | Full command reference, loaded when a browser task comes up |
542
+ | Cost | A few lines of context in every session | Nothing until it is needed |
543
+ | Agents | Claude Code, Codex, OpenCode | Claude Code, Cursor, Gemini CLI, Codex and [40+ others](https://github.com/vercel-labs/skills) |
544
+
545
+ ### Session hook (recommended)
546
+
547
+ ```bash
548
+ patchright-cli install --hooks # install or repair
549
+ patchright-cli install --hooks --uninstall # remove
550
+ ```
551
+
552
+ At the start of each session the agent runs `patchright-cli` with no arguments, which prints the home view (see [Output](#output)): whether the daemon is up and which sessions are open, so the agent can pick up an open browser session without asking. The hook goes only to apps whose config directory exists, and prints one line per app (`installed`, `updated`, `(no-op)` or `skipped`):
553
+
554
+ - **Claude Code**: a `SessionStart` hook in `~/.claude/settings.json`
555
+ - **Codex**: a `SessionStart` hook in `~/.codex/hooks.json`, plus `hooks = true` under `[features]` in `~/.codex/config.toml`
556
+ - **OpenCode**: a managed plugin at `~/.config/opencode/plugins/patchright-cli.js` that adds the dashboard to the system prompt
557
+
558
+ The hook calls plain `patchright-cli` when that name on your `PATH` is the same binary you ran the install with, and its absolute path otherwise. Re-run `install --hooks` after reinstalling or moving patchright-cli and it rewrites the path. Your other hooks and settings are left as they are, and `--uninstall` removes only patchright-cli's entries (the Codex `[features]` flag stays, since other hooks may need it).
559
+
560
+ ### Skill
472
561
 
473
562
  ```bash
474
- # Install skill for all detected agents (recommended)
563
+ # Install skill for all detected agents
475
564
  npx skills add AhaiMk01/patchright-cli
476
565
  ```
477
566
 
@@ -562,7 +651,7 @@ URLs passed to `patchright_open`, `patchright_goto` and `patchright_tab_new` mus
562
651
  <details>
563
652
  <summary><h2>Differences from playwright-cli</h2></summary>
564
653
 
565
- patchright-cli aims for full command parity with [Microsoft's playwright-cli](https://github.com/microsoft/playwright-cli). The following playwright-cli features are **intentionally not implemented** due to Patchright's architecture:
654
+ patchright-cli follows the command names and arguments of [Microsoft's playwright-cli](https://github.com/microsoft/playwright-cli) where Patchright allows it, but it is **not a drop-in replacement**. Some playwright-cli features cannot work on Patchright and are not implemented:
566
655
 
567
656
  | Feature | Reason |
568
657
  |---------|--------|
@@ -570,7 +659,7 @@ patchright-cli aims for full command parity with [Microsoft's playwright-cli](ht
570
659
  | `--extension` | Browser extension connection not supported. Patchright uses CDP directly. |
571
660
  | `install` / `install-browser` | Use `python -m patchright install chromium` instead. |
572
661
 
573
- All other commands and options are fully supported.
662
+ Each command accepts only the flags it implements. A playwright-cli flag patchright-cli does not support, such as `open --browser=firefox`, is rejected with `error: unknown flag` and exit code 2 rather than silently ignored, so a script ported from playwright-cli fails loudly where it would otherwise behave differently. `patchright-cli <command> --help` lists a command's flags.
574
663
 
575
664
  </details>
576
665
 
@@ -590,6 +679,8 @@ This project builds on the work of:
590
679
  - **[Patchright](https://github.com/Kaliiiiiiiiii-Vinyzu/patchright)** by [@Kaliiiiiiiiii-Vinyzu](https://github.com/Kaliiiiiiiiii-Vinyzu) — the undetected Playwright fork that makes this possible. All anti-detect capabilities come from Patchright.
591
680
  - **[playwright-cli](https://github.com/microsoft/playwright-cli)** by Microsoft — the original CLI that patchright-cli's command interface is modeled after.
592
681
  - **[camoufox-cli](https://github.com/Bin-Huang/camoufox-cli)** by [@Bin-Huang](https://github.com/Bin-Huang) — inspiration for the CLI-first approach to anti-detect browser automation and the SKILL.md agent integration pattern.
682
+ - **[AXI (Agent eXperience Interface)](https://github.com/kunchenguid/axi)** by [@kunchenguid](https://github.com/kunchenguid) — the standard for agent-facing CLIs that shaped the home view, strict per-command flags, `error:`/`help:` output, `(no-op)` replies, explicit empty states and the session-start hook.
683
+ - **[TOON](https://github.com/toon-format/spec)** — the token-oriented output format behind `--toon`.
593
684
 
594
685
  ---
595
686
 
@@ -9,7 +9,7 @@
9
9
  [![GitHub issues](https://img.shields.io/github/issues/AhaiMk01/patchright-cli?label=Issues)](https://github.com/AhaiMk01/patchright-cli/issues)
10
10
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
11
11
 
12
- Anti-detect browser automation CLI. Same command interface as [Microsoft's playwright-cli](https://github.com/microsoft/playwright-cli) but using [Patchright](https://github.com/kaliiiiiiiiii/patchright-python) (undetected Playwright fork) to bypass bot detection.
12
+ Anti-detect browser automation CLI. Commands follow [Microsoft's playwright-cli](https://github.com/microsoft/playwright-cli), but it uses [Patchright](https://github.com/kaliiiiiiiiii/patchright-python) (undetected Playwright fork) to bypass bot detection.
13
13
 
14
14
  [Install](#install) · [Quick Start](#quick-start) · [Commands](#-commands) · [Snapshots](#snapshots) · [Agent Integration](#agent-integration)
15
15
 
@@ -18,7 +18,7 @@ Anti-detect browser automation CLI. Same command interface as [Microsoft's playw
18
18
  | | Feature |
19
19
  |---|---|
20
20
  | :shield: | Bypasses Akamai, Cloudflare, and other anti-bot systems |
21
- | :rocket: | Same command interface as playwright-cli — zero learning curve |
21
+ | :rocket: | playwright-cli's command names and arguments — little to relearn |
22
22
  | :robot: | Built for AI agents (Claude Code, Codex, etc.) with YAML snapshots |
23
23
  | :zap: | Daemon architecture — browser stays open between commands |
24
24
  | :package: | `pip install` / `uvx` — no Docker, no config files |
@@ -48,7 +48,7 @@ curl -s https://raw.githubusercontent.com/AhaiMk01/patchright-cli/main/docs/inst
48
48
  </details>
49
49
 
50
50
  > [!IMPORTANT]
51
- > **Requirements:** Python 3.10+ and Google Chrome
51
+ > **Requirements:** Python 3.12+ and Google Chrome
52
52
 
53
53
  ```bash
54
54
  # Recommended — always runs latest version, no install needed
@@ -198,7 +198,7 @@ graph LR
198
198
  |-----------|------|
199
199
  | **Daemon** (`daemon.py`) | Long-running process managing browser sessions via Patchright. Auto-starts on first `open`. |
200
200
  | **CLI** (`cli.py`) | Thin client — connects, sends command, prints result, disconnects. Browser stays open. |
201
- | **Snapshot** (`snapshot.py`) | Playwright `aria_snapshot()` accessibility tree, annotated with sequential `[ref=eN]` handles for element targeting. |
201
+ | **Snapshot** (`snapshot.py`) | Playwright's AI-mode `aria_snapshot()` accessibility tree, iframes included, with Playwright's own `[ref=e5]` handles, resolved with `get_by_ref`. |
202
202
 
203
203
  ### Daemon token
204
204
 
@@ -209,6 +209,10 @@ The daemon only listens on `127.0.0.1`, but any local process can reach that por
209
209
  - Run the CLI as the same user, with the same home directory, as the daemon. In Docker the MCP server and daemon share a user and `HOME`, so this holds.
210
210
  - An older CLI talking to a newer daemon gets an error saying the daemon requires an auth token: upgrade, or stop the daemon (`patchright-cli kill-all` from the newer install, or end the process). A newer CLI talking to an older daemon finds no token file and sends none, which the older daemon accepts.
211
211
 
212
+ ### Stopping a stuck daemon
213
+
214
+ The daemon runs without a window. `kill-all` asks it to close every session and exit. If it does not answer within 20 seconds, or with `--force`, the CLI ends the daemon process and the browsers it launched (`taskkill /T` on Windows, the daemon's process group elsewhere). It finds the process through `~/.patchright-cli/daemon-<port>.pid`, which the daemon writes at startup with its PID and start time, and kills only a process whose start time still matches, so a reused PID is never touched. A daemon from a version that writes no PID file has to be ended by hand: its command line contains `patchright_cli.daemon`.
215
+
212
216
  ### Daemon client protocol
213
217
 
214
218
  Third-party clients can use the daemon TCP interface directly. The
@@ -254,6 +258,10 @@ patchright-cli find "text" # Search snapshot for text
254
258
  patchright-cli find --regex "a|b" # Search by regex
255
259
  patchright-cli find "text" --all # Include text/paragraph nodes
256
260
  patchright-cli find "text" --limit=50 # Cap hits (default 20)
261
+ patchright-cli find --role=button --description="Deletes" # By role + accessible name/description
262
+ patchright-cli html # Page HTML (first 8000 chars; --max-chars=0 for all)
263
+ patchright-cli html --include-shadow --filename=page.html # With open shadow roots, to a file
264
+ patchright-cli html e5 # One element's outerHTML (or --selector=CSS)
257
265
  patchright-cli eval <expr> # Run JavaScript
258
266
  patchright-cli eval --file=script.js # Run JS from file
259
267
  patchright-cli run-code <code> # Run JS with return value
@@ -359,6 +367,19 @@ patchright-cli sessionstorage-delete <key>
359
367
  patchright-cli sessionstorage-clear
360
368
  ```
361
369
 
370
+ ### Passkeys
371
+ A virtual WebAuthn authenticator for testing passkey sign-ups and logins. The first `passkey-*` command installs it in the session, overriding `navigator.credentials.create()` / `.get()` in every page (a page can notice the override, so it stays off until asked for). **Run a `passkey-*` command (e.g. `passkey-list`) before the page calls WebAuthn**: until then the page gets Chrome's native OS passkey dialog and hangs. Passkeys live in the session only; use `passkey-export` / `passkey-import` to keep them (the export holds private keys and is written owner-only; keep it out of version control).
372
+ ```bash
373
+ patchright-cli passkey-list # Installs the authenticator, lists passkeys (no keys shown)
374
+ patchright-cli passkey-list --rp-id=example.com
375
+ patchright-cli passkey-add example.com # Seed a new P-256 passkey
376
+ patchright-cli passkey-add example.com --id=<b64url> --user-handle=<b64url> --private-key=<b64url> --public-key=<b64url> --sign-count=5
377
+ patchright-cli passkey-delete <credential-id>
378
+ patchright-cli passkey-clear [--rp-id=example.com]
379
+ patchright-cli passkey-export passkeys.json # Includes private keys
380
+ patchright-cli passkey-import passkeys.json
381
+ ```
382
+
362
383
  ### Request Mocking
363
384
  ```bash
364
385
  patchright-cli route "**/*.jpg" --status=404
@@ -375,7 +396,8 @@ patchright-cli unroute # Remove all routes
375
396
  ```bash
376
397
  patchright-cli tracing-start
377
398
  patchright-cli tracing-stop # Saves .zip trace file
378
- patchright-cli video-start # Start video recording (CDP screencast)
399
+ patchright-cli video-start # Start real-time video recording at 25 fps (CDP screencast)
400
+ patchright-cli video-start --fps=60 # Another frame rate, 1-60
379
401
  patchright-cli video-stop # Stop and save video (requires ffmpeg for .webm)
380
402
  patchright-cli video-stop --filename=recording.webm
381
403
  patchright-cli show --annotate # Ask a human to mark up the page, wait for it
@@ -395,15 +417,57 @@ patchright-cli network-state-set online # Restore connectivity
395
417
 
396
418
  ### DevTools
397
419
  ```bash
398
- patchright-cli console # All console messages
420
+ patchright-cli console # Start capture / show captured console messages
399
421
  patchright-cli console warning # Filter by level
400
422
  patchright-cli console --clear # Clear after printing
401
423
  ```
402
424
 
425
+ The first `console` call enables CDP Runtime capture for every page in the session,
426
+ including tabs and popups opened later. Messages from before capture starts are
427
+ unavailable: run `console` before reproducing an issue, then call it again to read
428
+ the messages. Capture can make automation detectable and stays enabled until the
429
+ session closes; `--clear` only clears the message buffer. A new session starts
430
+ with capture disabled.
431
+
432
+ Two DevTools commands leave traces a page can see. `highlight` draws inside an
433
+ `<x-pw-glass>` element under `<html>`; `highlight --hide` removes it once no
434
+ highlight is left. `pick-locator` runs only with `--detectable`: it installs
435
+ Playwright's recorder, which puts `window.playwright`, `__pw_*` globals and an
436
+ `<x-pw-glass>` element into every page of the session until the session closes.
437
+
403
438
  ### Output
404
439
  ```bash
405
440
  patchright-cli --raw eval --file=s.js # Raw output (no page/snapshot decoration)
406
441
  patchright-cli --raw snapshot > p.yml # Pipe raw snapshot to file
442
+ patchright-cli --json tab-list # Whole reply as JSON ({success, output, data, ...})
443
+ patchright-cli --toon tab-list # Structured result as TOON
444
+ ```
445
+
446
+ `--toon` prints a reply's structured `data` as [TOON](https://github.com/toon-format/spec), a compact
447
+ format for agents: `list`, `tab-list`, `cookie-list`, `localstorage-list`, `sessionstorage-list`,
448
+ `route-list`, `console`, `network`, `profile-list` and `find` give a table, `url` and `title` a single
449
+ field. A cut-short list adds `total` and a `help:` line. Commands without structured data, and errors,
450
+ print exactly as they do without the flag. `--json` and `--toon` together are a usage error.
451
+
452
+ ```
453
+ tabs[2]{index,title,url,active}:
454
+ 0,Example Domain,"https://example.com/",true
455
+ 1,"","about:blank",false
456
+ ```
457
+
458
+ Run with no arguments, `patchright-cli` prints a short home view instead of the manual (that is
459
+ `--help`): where the binary is, whether the daemon is running on the port (`--port=N` picks another),
460
+ the open sessions with their URL and tab count, and what to run next. It only asks a daemon that is
461
+ already running and never starts one. Add `--toon` or `--json` for the same state as data.
462
+
463
+ ```
464
+ ~/.local/bin/patchright-cli v0.10.0 -- anti-detect Chrome automation CLI (playwright-cli style commands)
465
+ daemon: running on port 9321 (1 session)
466
+ sessions[1]{name,status,url,tabs}:
467
+ default,open,"https://example.com/",2
468
+ help: patchright-cli snapshot (element refs for the current page; -s=<name> for another session)
469
+ help: patchright-cli list (sessions and their tabs)
470
+ help: patchright-cli --help (all commands); patchright-cli <command> --help (one command)
407
471
  ```
408
472
 
409
473
  ### Setup
@@ -418,7 +482,8 @@ patchright-cli -s=mysession click e6
418
482
  patchright-cli -s=mysession close
419
483
  patchright-cli list # List all sessions
420
484
  patchright-cli close-all
421
- patchright-cli kill-all
485
+ patchright-cli kill-all # Stop the daemon; force-stops it if it does not answer
486
+ patchright-cli kill-all --force # Kill the daemon and its browsers without asking
422
487
  patchright-cli delete-data # Delete the profile named after the session
423
488
  patchright-cli profile-list # Profiles, size, and which session uses each
424
489
  patchright-cli profile-delete <name> # Delete an idle named profile
@@ -431,10 +496,36 @@ patchright-cli --port=9322 open # Custom daemon port
431
496
 
432
497
  ## Agent Integration
433
498
 
434
- Works with Claude Code, Cursor, Gemini CLI, Codex, and [40+ other agents](https://github.com/vercel-labs/skills).
499
+ The CLI follows the [AXI](https://github.com/kunchenguid/axi) standard for agent-facing tools: errors and hints on stdout, exit 2 for usage errors, `(no-op)` for repeated actions, and a no-argument home view with live state.
500
+
501
+ There are two ways to teach your agent about patchright-cli. Both get it to the same place, so you only need one.
502
+
503
+ | | Session hook | Skill |
504
+ |---|---|---|
505
+ | Install | `patchright-cli install --hooks` | `npx skills add AhaiMk01/patchright-cli` or `patchright-cli install --skills` |
506
+ | What the agent gets | Live state (open sessions, the commands to drive them) at the start of every session | Full command reference, loaded when a browser task comes up |
507
+ | Cost | A few lines of context in every session | Nothing until it is needed |
508
+ | Agents | Claude Code, Codex, OpenCode | Claude Code, Cursor, Gemini CLI, Codex and [40+ others](https://github.com/vercel-labs/skills) |
509
+
510
+ ### Session hook (recommended)
511
+
512
+ ```bash
513
+ patchright-cli install --hooks # install or repair
514
+ patchright-cli install --hooks --uninstall # remove
515
+ ```
516
+
517
+ At the start of each session the agent runs `patchright-cli` with no arguments, which prints the home view (see [Output](#output)): whether the daemon is up and which sessions are open, so the agent can pick up an open browser session without asking. The hook goes only to apps whose config directory exists, and prints one line per app (`installed`, `updated`, `(no-op)` or `skipped`):
518
+
519
+ - **Claude Code**: a `SessionStart` hook in `~/.claude/settings.json`
520
+ - **Codex**: a `SessionStart` hook in `~/.codex/hooks.json`, plus `hooks = true` under `[features]` in `~/.codex/config.toml`
521
+ - **OpenCode**: a managed plugin at `~/.config/opencode/plugins/patchright-cli.js` that adds the dashboard to the system prompt
522
+
523
+ The hook calls plain `patchright-cli` when that name on your `PATH` is the same binary you ran the install with, and its absolute path otherwise. Re-run `install --hooks` after reinstalling or moving patchright-cli and it rewrites the path. Your other hooks and settings are left as they are, and `--uninstall` removes only patchright-cli's entries (the Codex `[features]` flag stays, since other hooks may need it).
524
+
525
+ ### Skill
435
526
 
436
527
  ```bash
437
- # Install skill for all detected agents (recommended)
528
+ # Install skill for all detected agents
438
529
  npx skills add AhaiMk01/patchright-cli
439
530
  ```
440
531
 
@@ -525,7 +616,7 @@ URLs passed to `patchright_open`, `patchright_goto` and `patchright_tab_new` mus
525
616
  <details>
526
617
  <summary><h2>Differences from playwright-cli</h2></summary>
527
618
 
528
- patchright-cli aims for full command parity with [Microsoft's playwright-cli](https://github.com/microsoft/playwright-cli). The following playwright-cli features are **intentionally not implemented** due to Patchright's architecture:
619
+ patchright-cli follows the command names and arguments of [Microsoft's playwright-cli](https://github.com/microsoft/playwright-cli) where Patchright allows it, but it is **not a drop-in replacement**. Some playwright-cli features cannot work on Patchright and are not implemented:
529
620
 
530
621
  | Feature | Reason |
531
622
  |---------|--------|
@@ -533,7 +624,7 @@ patchright-cli aims for full command parity with [Microsoft's playwright-cli](ht
533
624
  | `--extension` | Browser extension connection not supported. Patchright uses CDP directly. |
534
625
  | `install` / `install-browser` | Use `python -m patchright install chromium` instead. |
535
626
 
536
- All other commands and options are fully supported.
627
+ Each command accepts only the flags it implements. A playwright-cli flag patchright-cli does not support, such as `open --browser=firefox`, is rejected with `error: unknown flag` and exit code 2 rather than silently ignored, so a script ported from playwright-cli fails loudly where it would otherwise behave differently. `patchright-cli <command> --help` lists a command's flags.
537
628
 
538
629
  </details>
539
630
 
@@ -553,6 +644,8 @@ This project builds on the work of:
553
644
  - **[Patchright](https://github.com/Kaliiiiiiiiii-Vinyzu/patchright)** by [@Kaliiiiiiiiii-Vinyzu](https://github.com/Kaliiiiiiiiii-Vinyzu) — the undetected Playwright fork that makes this possible. All anti-detect capabilities come from Patchright.
554
645
  - **[playwright-cli](https://github.com/microsoft/playwright-cli)** by Microsoft — the original CLI that patchright-cli's command interface is modeled after.
555
646
  - **[camoufox-cli](https://github.com/Bin-Huang/camoufox-cli)** by [@Bin-Huang](https://github.com/Bin-Huang) — inspiration for the CLI-first approach to anti-detect browser automation and the SKILL.md agent integration pattern.
647
+ - **[AXI (Agent eXperience Interface)](https://github.com/kunchenguid/axi)** by [@kunchenguid](https://github.com/kunchenguid) — the standard for agent-facing CLIs that shaped the home view, strict per-command flags, `error:`/`help:` output, `(no-op)` replies, explicit empty states and the session-start hook.
648
+ - **[TOON](https://github.com/toon-format/spec)** — the token-oriented output format behind `--toon`.
556
649
 
557
650
  ---
558
651
 
@@ -86,6 +86,50 @@ this table are part of the protocol:
86
86
  | `rejected the auth token` | The supplied token is invalid or stale. Read the token file fresh before retrying. |
87
87
  | `Daemon error: request of` | The request exceeded the 64 MiB limit. |
88
88
 
89
+ ### Idempotent no-ops
90
+
91
+ A mutation whose target state already holds succeeds instead of failing:
92
+ `success` is `true` and `output` ends with ` (no-op)`. This covers `close` and
93
+ `detach` of a session that is not open (the output still contains
94
+ `Session '<name>' is not open`), `close` of a named tab that is not open,
95
+ `video-stop`, `tracing-stop` and `codegen-stop` with nothing running,
96
+ `video-start` and `tracing-start` while already running, `video-hide-actions`
97
+ when callouts are off, `unroute` of a pattern that is not routed (or with no
98
+ routes at all), `cookie-delete`, `localstorage-delete` and
99
+ `sessionstorage-delete` of an absent name or key, `highlight --hide` with
100
+ nothing highlighted, and `profile-delete` of a profile that does not exist.
101
+ `go-back` and `go-forward` at the edge of the history still fail.
102
+
103
+ ### Structured data
104
+
105
+ Some replies carry an optional `data` field next to `output`, holding the same
106
+ result as JSON. `output` stays the human-readable text. When a list reply shows
107
+ fewer items than exist, `total` holds the full count.
108
+
109
+ | Command | `data` |
110
+ | --- | --- |
111
+ | `url` | `{"url"}` |
112
+ | `title` | `{"title"}` |
113
+ | `list` | `[{"name", "status", "url"}]`, where `status` is `open` or `attached` |
114
+ | `tab-list` | `[{"index", "title", "url", "active"}]` |
115
+ | `cookie-list` | `[{"name", "domain", "expires"}]` |
116
+ | `localstorage-list`, `sessionstorage-list` | `[{"key", "value"}]` |
117
+ | `route-list` | `[{"pattern", "status"}]` |
118
+ | `console` | `[{"level", "text"}]`, plus `total` when older messages are cut off |
119
+ | `network` (alias `requests`) | `[{"id", "method", "status", "url"}]`, plus `total` when older requests are cut off |
120
+ | `profile-list` | `[{"name", "size", "session"}]`, where `size` is bytes and `session` is the holding session or `null` |
121
+ | `find` | `[{"ref", "role", "name"}]`, plus `total` when `--limit` cut the hits |
122
+
123
+ `console` opts the session into CDP Runtime capture on existing and future pages.
124
+ Earlier messages are unavailable; the first response explains this and the CDP
125
+ detection risk. Capture lasts until the session closes; `--clear` only clears the
126
+ buffer. If capture fails on a live page, the response has `success: false` and any
127
+ available messages; another `console` call retries pages that failed.
128
+
129
+ An empty list is `[]`, and its `output` states the zero explicitly, for example
130
+ `0 cookies in this session`. Commands not listed here send no `data`. More
131
+ fields or commands can gain `data` later, so read only the keys you need.
132
+
89
133
  Best effort, not covered by the compatibility rules below: a command on a page,
90
134
  context or browser that has closed usually fails with Playwright's own message
91
135
  containing `has been closed`. That text comes from Playwright and can change
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Prerequisites
4
4
 
5
- - Python 3.10+
5
+ - Python 3.12+
6
6
  - Google Chrome installed on the system
7
7
 
8
8
  ## Install