arthur-runtime 0.1.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 (33) hide show
  1. arthur_runtime-0.1.0/.gitignore +8 -0
  2. arthur_runtime-0.1.0/CONTEXT.md +26 -0
  3. arthur_runtime-0.1.0/LICENSE +21 -0
  4. arthur_runtime-0.1.0/PKG-INFO +300 -0
  5. arthur_runtime-0.1.0/README.md +286 -0
  6. arthur_runtime-0.1.0/issues/01-minimal-cdp-websocket-client.md +15 -0
  7. arthur_runtime-0.1.0/issues/02-chromium-process-lifecycle.md +14 -0
  8. arthur_runtime-0.1.0/issues/03-semantic-snapshot-generator.md +14 -0
  9. arthur_runtime-0.1.0/issues/04-cdp-synthetic-input.md +15 -0
  10. arthur_runtime-0.1.0/issues/05-synchronous-browser-api.md +14 -0
  11. arthur_runtime-0.1.0/issues/06-persistent-repl-engine.md +15 -0
  12. arthur_runtime-0.1.0/issues/07-fastmcp-server-and-cli.md +13 -0
  13. arthur_runtime-0.1.0/issues/map.md +48 -0
  14. arthur_runtime-0.1.0/issues/spec-arthur-headless-runtime.md +124 -0
  15. arthur_runtime-0.1.0/pyproject.toml +39 -0
  16. arthur_runtime-0.1.0/src/arthur/__init__.py +25 -0
  17. arthur_runtime-0.1.0/src/arthur/browser.py +699 -0
  18. arthur_runtime-0.1.0/src/arthur/cdp.py +291 -0
  19. arthur_runtime-0.1.0/src/arthur/cli.py +122 -0
  20. arthur_runtime-0.1.0/src/arthur/dom.py +649 -0
  21. arthur_runtime-0.1.0/src/arthur/errors.py +157 -0
  22. arthur_runtime-0.1.0/src/arthur/input.py +201 -0
  23. arthur_runtime-0.1.0/src/arthur/launcher.py +321 -0
  24. arthur_runtime-0.1.0/src/arthur/repl.py +378 -0
  25. arthur_runtime-0.1.0/src/arthur/server.py +101 -0
  26. arthur_runtime-0.1.0/tests/test_browser.py +155 -0
  27. arthur_runtime-0.1.0/tests/test_cdp.py +218 -0
  28. arthur_runtime-0.1.0/tests/test_dom.py +259 -0
  29. arthur_runtime-0.1.0/tests/test_input.py +212 -0
  30. arthur_runtime-0.1.0/tests/test_launcher.py +51 -0
  31. arthur_runtime-0.1.0/tests/test_repl.py +88 -0
  32. arthur_runtime-0.1.0/tests/test_server.py +52 -0
  33. arthur_runtime-0.1.0/uv.lock +1584 -0
@@ -0,0 +1,8 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ .pytest_cache/
5
+ .mypy_cache/
6
+ dist/
7
+ build/
8
+ *.egg-info/
@@ -0,0 +1,26 @@
1
+ # Arthur — Domain Vocabulary & Context
2
+
3
+ This glossary defines the shared domain vocabulary and architectural seams of the **Arthur** headless Chromium runtime.
4
+
5
+ ---
6
+
7
+ ## Domain Concepts
8
+
9
+ ### 1. Browser & Tabs
10
+ - **`Browser`**: The top-level synchronous runtime facade exposed to AI agents and the REPL. Manages browser process lifecycle and delegates actions to the active tab.
11
+ - **`Tab`**: A synchronous proxy to an attached page target (`sessionId`), exposing navigation, semantic snapshot inspection, element querying, and synthetic interactions.
12
+ - **`TabManager`**: The internal lifecycle tracker mapping CDP `targetId`s to sequential integer IDs, session attachments, URLs, and active tab pointers.
13
+
14
+ ### 2. DOM Engine & Ref-IDs
15
+ - **`DOM Engine`**: The in-page JavaScript runtime (`window.__arthur_dom_op`) that parses the accessible DOM tree, evaluates WAI-ARIA roles/names, and maintains interactive element coordinates.
16
+ - **`Ref-ID`**: A deterministic integer reference (formatted canonically as `[#1]`, `[#2]`) assigned to actionable DOM nodes in a snapshot outline, enabling token-efficient agent targeting without XPath/CSS selectors.
17
+ - **`Target Reference`**: Polymorphic target specifier accepted by all interaction methods: numeric Ref-ID (`1`), string Ref-ID (`"[#1]"` or `"#1"`), or CSS selector (`"button.submit"`).
18
+ - **`Diagnostic Auto-Snapshot`**: An automatic lightweight semantic DOM outline captured and attached to exception payloads when a REPL command fails, allowing single-turn self-healing.
19
+
20
+ ### 3. CDP Transport & Input
21
+ - **`CDPClient`**: Asynchronous, thread-safe Chrome DevTools Protocol WebSocket transport with numeric request/response multiplexing and session targeting (`flatten: true`).
22
+ - **`InteractionDriver`**: Synthetic input coordinator handling coordinate-accurate mouse clicks, text typing with Enter submissions, dropdown selections, hover, and scrolling over CDP.
23
+
24
+ ### 4. REPL & Budgeting
25
+ - **`REPL Session`**: Persistent in-memory Python execution environment that retains variables, imports, and helper functions across agent turns via AST statement/expression compilation.
26
+ - **`Output Budget`**: Hard character/token limit and formatting pipeline with telemetry defanging (sanitizing image beacons and raw active tags).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shivansh Singh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,300 @@
1
+ Metadata-Version: 2.5
2
+ Name: arthur-runtime
3
+ Version: 0.1.0
4
+ Summary: Lightweight Headless Chromium Runtime for Gloria and AI Agents
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.10
7
+ Requires-Dist: mcp>=1.0.0
8
+ Requires-Dist: websockets>=12.0
9
+ Provides-Extra: dev
10
+ Requires-Dist: mypy>=1.10.0; extra == 'dev'
11
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
12
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
13
+ Description-Content-Type: text/markdown
14
+
15
+ <div align="center">
16
+
17
+ # Arthur
18
+
19
+ ### Lightweight Headless Chromium Runtime & MCP Server for AI Agents
20
+
21
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
22
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
23
+ [![MCP Standard](https://img.shields.io/badge/MCP-Standard%20Compatible-green.svg)](https://modelcontextprotocol.io/)
24
+ [![Built with uv](https://img.shields.io/badge/built%20with-uv-purple.svg)](https://github.com/astral-sh/uv)
25
+
26
+ <p align="center">
27
+ Direct CDP WebSockets • Semantic Ref-ID Snapshots • Persistent Python REPL • FastMCP Server
28
+ </p>
29
+
30
+ </div>
31
+
32
+ ---
33
+
34
+ ## Overview
35
+
36
+ **Arthur** is a standalone, lightweight headless Chromium runtime engineered specifically for AI agents (such as Gloria, Claude, and autonomous coding assistants).
37
+
38
+ Arthur eliminates browser extensions, native messaging hosts, and heavy automation drivers by connecting directly to Chromium via **Chrome DevTools Protocol (CDP) WebSockets**. It manages an ephemeral sandboxed Chromium process, retains persistent Python REPL state across turns, and generates concise, token-efficient semantic DOM snapshots with assigned **Ref-IDs** (`[#1]`, `[#2]`).
39
+
40
+ ```text
41
+ Agent / MCP Client
42
+
43
+ ▼ execute_python(code)
44
+ FastMCP Server (stdio / Streamable HTTP)
45
+
46
+
47
+ Python REPL Session (stateful memory & auto-snapshots)
48
+
49
+
50
+ Arthur Browser API (synchronous facade)
51
+
52
+ ▼ CDP WebSockets
53
+ Headless Chromium (--headless=new)
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Quickstart
59
+
60
+ ### 1. Instant Zero-Clone Execution via `uvx`
61
+
62
+ No repository cloning or manual environment management is required:
63
+
64
+ ```bash
65
+ # Run MCP Server (stdio transport)
66
+ uvx --from git+https://github.com/sh7vansh/arthur arthur mcp
67
+
68
+ # Run Interactive Terminal REPL
69
+ uvx --from git+https://github.com/sh7vansh/arthur arthur repl
70
+
71
+ # Run One-Shot Command
72
+ uvx --from git+https://github.com/sh7vansh/arthur arthur repl -c "browser.navigate('https://example.com'); print(browser.snapshot())"
73
+ ```
74
+
75
+ ---
76
+
77
+ ### 2. Connect to MCP Clients (Claude Desktop, Cursor, etc.)
78
+
79
+ Add Arthur to your MCP settings configuration (e.g. `claude_desktop_config.json`):
80
+
81
+ #### Using `uvx` (Zero-Clone):
82
+ ```json
83
+ {
84
+ "mcpServers": {
85
+ "arthur": {
86
+ "command": "uvx",
87
+ "args": [
88
+ "--from",
89
+ "git+https://github.com/sh7vansh/arthur",
90
+ "arthur",
91
+ "mcp"
92
+ ]
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ #### Using Local Repository:
99
+ ```json
100
+ {
101
+ "mcpServers": {
102
+ "arthur": {
103
+ "command": "uv",
104
+ "args": [
105
+ "--directory",
106
+ "/path/to/Arthur",
107
+ "run",
108
+ "arthur",
109
+ "mcp"
110
+ ]
111
+ }
112
+ }
113
+ }
114
+ ```
115
+
116
+ ---
117
+
118
+ ## Local Installation
119
+
120
+ ### Prerequisites
121
+ - **Python 3.10+**
122
+ - **[uv](https://astral.sh/uv/)** package manager
123
+ - **Google Chrome** or **Chromium** (Arthur automatically discovers existing local installations)
124
+
125
+ ```bash
126
+ # Clone the repository
127
+ git clone https://github.com/sh7vansh/arthur.git
128
+ cd arthur
129
+
130
+ # Install dependencies in an isolated virtual environment
131
+ uv sync --all-extras
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Key Capabilities
137
+
138
+ ### 1. In-Page Semantic DOM Engine & Ref-IDs
139
+ Arthur evaluates an in-page accessibility parser that extracts the visible DOM, calculates WAI-ARIA accessible roles/names, and generates a compact, token-efficient semantic tree with assigned numeric **Ref-IDs**:
140
+
141
+ ```text
142
+ PAGE: "Example Domain" (https://example.com)
143
+ - heading[level=1] "Example Domain"
144
+ - paragraph: "This domain is for use in illustrative examples in documents."
145
+ - link [#1] "More information..." (href="https://www.iana.org/domains/example")
146
+ ```
147
+
148
+ Agents target elements directly using Ref-IDs (`1`, `"[#1]"`), avoiding brittle CSS or XPath selectors.
149
+
150
+ ### 2. Coordinate-Accurate Synthetic Input
151
+ Translates high-level agent actions into coordinate-precise CDP events:
152
+ - **`browser.click(target)`**: Resolves bounding center coordinates and dispatches `Input.dispatchMouseEvent`.
153
+ - **`browser.type(target, text, press_enter=True)`**: Focuses the element, clears existing input, inserts text, and simulates real key events.
154
+ - **`browser.select(target, value)`**: Handles `<select>` dropdown menus.
155
+ - **`browser.hover(target)`** & **`browser.scroll(x, y)`**: Simulates mouse hover and viewport/element scrolling.
156
+
157
+ ### 3. Persistent Stateful Python REPL
158
+ The `execute_python` tool retains variables, functions, and imports across successive agent turns:
159
+ ```python
160
+ # Turn 1: Define helper and fetch data
161
+ import json
162
+ browser.navigate("https://news.ycombinator.com")
163
+ titles = browser.eval_js("[...document.querySelectorAll('.titleline > a')].map(a => a.innerText)")
164
+
165
+ # Turn 2: State persists across tool calls
166
+ print(f"Captured {len(titles)} articles:")
167
+ print(titles[:3])
168
+ ```
169
+
170
+ ### 4. Single-Turn Self-Healing & Diagnostics
171
+ - **Diagnostic Auto-Snapshot**: When an unhandled exception occurs, Arthur automatically captures the latest DOM snapshot (`[diagnostic_auto_snapshot]`) and appends it to the error payload, allowing the agent to self-heal in a single turn without extra roundtrips.
172
+ - **Fuzzy Suggestions**: If an element reference becomes stale after a dynamic DOM mutation, Arthur provides fuzzy match suggestions from snapshot history.
173
+
174
+ ### 5. Output Budgeting & Telemetry Defanging
175
+ All execution output passes through a strict budgeting pipeline:
176
+ - Prevents context window explosion by truncating output exceeding token/character limits.
177
+ - Automatically defangs tracking image beacons (`![beacon](url)` -> `[IMAGE_BLOCKED]`) and unsafe active HTML tags.
178
+
179
+ ---
180
+
181
+ ## Python API Reference
182
+
183
+ The synchronous `browser` instance is pre-injected into the REPL environment:
184
+
185
+ ```python
186
+ # --- Navigation & Inspection ---
187
+ browser.navigate("https://example.com", timeout=30.0)
188
+ snapshot_text = browser.snapshot()
189
+ current_url = browser.url
190
+ page_title = browser.title
191
+
192
+ # --- Synthetic Interactions (Ref-ID, String Ref, or CSS Selector) ---
193
+ browser.click(1) # Click Ref-ID #1
194
+ browser.click("[#1]") # String Ref-ID format
195
+ browser.click("button.submit-btn") # CSS selector fallback
196
+ browser.type(2, "search query", press_enter=True)
197
+ browser.select(3, "Option Value")
198
+ browser.hover(1)
199
+ browser.scroll(x=0, y=500)
200
+
201
+ # --- Synchronization & Waiting ---
202
+ browser.wait_for(1, state="visible", timeout=10.0)
203
+ browser.wait_for_url(r"^https://example\.com/dashboard", timeout=15.0)
204
+
205
+ # --- Evaluation & Captures ---
206
+ result = browser.eval_js("window.innerWidth")
207
+ png_bytes = browser.screenshot()
208
+ text_content = browser.get_text(1)
209
+ attr_value = browser.get_attribute(1, "data-custom")
210
+
211
+ # --- Multi-Tab Management ---
212
+ new_tab = browser.new_tab("https://google.com")
213
+ tabs = browser.tabs # List of open Tab instances
214
+ active = browser.active_tab
215
+ tab_2 = browser.get_tab(2)
216
+ browser.close_tab(2)
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Remote Deployment & Transports
222
+
223
+ Arthur supports multiple network transports for remote, cloud, and containerized deployments.
224
+
225
+ ### 1. Stateless Streamable HTTP (Recommended for Remote / Cloud)
226
+
227
+ For remote servers, VMs, Docker containers, Cloudflare Tunnels, and reverse proxies, **Stateless Streamable HTTP is the most reliable transport**.
228
+
229
+ #### Why Stateless HTTP is Superior for Remote Setups:
230
+ - **Resilient to Network Drops**: Unlike stateful SSE connections that drop or report "Session Expired" when a network glitch occurs between agent turns, stateless HTTP treats each tool execution as an independent request.
231
+ - **Proxy & Tunnel Friendly**: Works cleanly behind Nginx, Cloudflare Tunnels, AWS ALBs, and Ngrok without hitting idle connection timeouts (e.g. 60s stream timeouts).
232
+ - **Preserved Backend State**: While the HTTP wire transport is stateless, Arthur's in-memory Python REPL session, Chromium browser instance, cookies, and open tabs remain fully persistent on the server.
233
+
234
+ #### Starting Stateless Streamable HTTP:
235
+ ```bash
236
+ # Start server on remote host (listening on 0.0.0.0:8000)
237
+ uv run arthur mcp --transport streamable-http --stateless --host 0.0.0.0 --port 8000
238
+ ```
239
+
240
+ #### Client Configuration:
241
+ ```json
242
+ {
243
+ "mcpServers": {
244
+ "arthur": {
245
+ "url": "http://remote-server-ip:8000/mcp"
246
+ }
247
+ }
248
+ }
249
+ ```
250
+
251
+ ---
252
+
253
+ ### 2. SSH Stdio Tunneling (Zero-Port Remote Access)
254
+
255
+ Run Arthur securely over SSH without opening public firewall ports:
256
+
257
+ ```json
258
+ {
259
+ "mcpServers": {
260
+ "remote-arthur": {
261
+ "command": "ssh",
262
+ "args": [
263
+ "user@remote-host",
264
+ "uvx --from git+https://github.com/sh7vansh/arthur arthur mcp"
265
+ ]
266
+ }
267
+ }
268
+ }
269
+ ```
270
+
271
+ ---
272
+
273
+ ### 3. Server-Sent Events (`/sse`)
274
+
275
+ For legacy MCP clients requiring standard SSE endpoints:
276
+
277
+ ```bash
278
+ uv run arthur mcp --transport sse --host 0.0.0.0 --port 8000
279
+ ```
280
+ - **Endpoint**: `http://<host>:8000/sse`
281
+
282
+ ---
283
+
284
+ ## Testing & Development
285
+
286
+ Run the test suite to validate CDP WebSocket transport, headless Chromium lifecycle, in-page DOM operations, and persistent REPL execution:
287
+
288
+ ```bash
289
+ # Run pytest test suite
290
+ uv run pytest
291
+
292
+ # Run type checker
293
+ uv run mypy src
294
+ ```
295
+
296
+ ---
297
+
298
+ ## License
299
+
300
+ This project is licensed under the **MIT License** — see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,286 @@
1
+ <div align="center">
2
+
3
+ # Arthur
4
+
5
+ ### Lightweight Headless Chromium Runtime & MCP Server for AI Agents
6
+
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
8
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
9
+ [![MCP Standard](https://img.shields.io/badge/MCP-Standard%20Compatible-green.svg)](https://modelcontextprotocol.io/)
10
+ [![Built with uv](https://img.shields.io/badge/built%20with-uv-purple.svg)](https://github.com/astral-sh/uv)
11
+
12
+ <p align="center">
13
+ Direct CDP WebSockets • Semantic Ref-ID Snapshots • Persistent Python REPL • FastMCP Server
14
+ </p>
15
+
16
+ </div>
17
+
18
+ ---
19
+
20
+ ## Overview
21
+
22
+ **Arthur** is a standalone, lightweight headless Chromium runtime engineered specifically for AI agents (such as Gloria, Claude, and autonomous coding assistants).
23
+
24
+ Arthur eliminates browser extensions, native messaging hosts, and heavy automation drivers by connecting directly to Chromium via **Chrome DevTools Protocol (CDP) WebSockets**. It manages an ephemeral sandboxed Chromium process, retains persistent Python REPL state across turns, and generates concise, token-efficient semantic DOM snapshots with assigned **Ref-IDs** (`[#1]`, `[#2]`).
25
+
26
+ ```text
27
+ Agent / MCP Client
28
+
29
+ ▼ execute_python(code)
30
+ FastMCP Server (stdio / Streamable HTTP)
31
+
32
+
33
+ Python REPL Session (stateful memory & auto-snapshots)
34
+
35
+
36
+ Arthur Browser API (synchronous facade)
37
+
38
+ ▼ CDP WebSockets
39
+ Headless Chromium (--headless=new)
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Quickstart
45
+
46
+ ### 1. Instant Zero-Clone Execution via `uvx`
47
+
48
+ No repository cloning or manual environment management is required:
49
+
50
+ ```bash
51
+ # Run MCP Server (stdio transport)
52
+ uvx --from git+https://github.com/sh7vansh/arthur arthur mcp
53
+
54
+ # Run Interactive Terminal REPL
55
+ uvx --from git+https://github.com/sh7vansh/arthur arthur repl
56
+
57
+ # Run One-Shot Command
58
+ uvx --from git+https://github.com/sh7vansh/arthur arthur repl -c "browser.navigate('https://example.com'); print(browser.snapshot())"
59
+ ```
60
+
61
+ ---
62
+
63
+ ### 2. Connect to MCP Clients (Claude Desktop, Cursor, etc.)
64
+
65
+ Add Arthur to your MCP settings configuration (e.g. `claude_desktop_config.json`):
66
+
67
+ #### Using `uvx` (Zero-Clone):
68
+ ```json
69
+ {
70
+ "mcpServers": {
71
+ "arthur": {
72
+ "command": "uvx",
73
+ "args": [
74
+ "--from",
75
+ "git+https://github.com/sh7vansh/arthur",
76
+ "arthur",
77
+ "mcp"
78
+ ]
79
+ }
80
+ }
81
+ }
82
+ ```
83
+
84
+ #### Using Local Repository:
85
+ ```json
86
+ {
87
+ "mcpServers": {
88
+ "arthur": {
89
+ "command": "uv",
90
+ "args": [
91
+ "--directory",
92
+ "/path/to/Arthur",
93
+ "run",
94
+ "arthur",
95
+ "mcp"
96
+ ]
97
+ }
98
+ }
99
+ }
100
+ ```
101
+
102
+ ---
103
+
104
+ ## Local Installation
105
+
106
+ ### Prerequisites
107
+ - **Python 3.10+**
108
+ - **[uv](https://astral.sh/uv/)** package manager
109
+ - **Google Chrome** or **Chromium** (Arthur automatically discovers existing local installations)
110
+
111
+ ```bash
112
+ # Clone the repository
113
+ git clone https://github.com/sh7vansh/arthur.git
114
+ cd arthur
115
+
116
+ # Install dependencies in an isolated virtual environment
117
+ uv sync --all-extras
118
+ ```
119
+
120
+ ---
121
+
122
+ ## Key Capabilities
123
+
124
+ ### 1. In-Page Semantic DOM Engine & Ref-IDs
125
+ Arthur evaluates an in-page accessibility parser that extracts the visible DOM, calculates WAI-ARIA accessible roles/names, and generates a compact, token-efficient semantic tree with assigned numeric **Ref-IDs**:
126
+
127
+ ```text
128
+ PAGE: "Example Domain" (https://example.com)
129
+ - heading[level=1] "Example Domain"
130
+ - paragraph: "This domain is for use in illustrative examples in documents."
131
+ - link [#1] "More information..." (href="https://www.iana.org/domains/example")
132
+ ```
133
+
134
+ Agents target elements directly using Ref-IDs (`1`, `"[#1]"`), avoiding brittle CSS or XPath selectors.
135
+
136
+ ### 2. Coordinate-Accurate Synthetic Input
137
+ Translates high-level agent actions into coordinate-precise CDP events:
138
+ - **`browser.click(target)`**: Resolves bounding center coordinates and dispatches `Input.dispatchMouseEvent`.
139
+ - **`browser.type(target, text, press_enter=True)`**: Focuses the element, clears existing input, inserts text, and simulates real key events.
140
+ - **`browser.select(target, value)`**: Handles `<select>` dropdown menus.
141
+ - **`browser.hover(target)`** & **`browser.scroll(x, y)`**: Simulates mouse hover and viewport/element scrolling.
142
+
143
+ ### 3. Persistent Stateful Python REPL
144
+ The `execute_python` tool retains variables, functions, and imports across successive agent turns:
145
+ ```python
146
+ # Turn 1: Define helper and fetch data
147
+ import json
148
+ browser.navigate("https://news.ycombinator.com")
149
+ titles = browser.eval_js("[...document.querySelectorAll('.titleline > a')].map(a => a.innerText)")
150
+
151
+ # Turn 2: State persists across tool calls
152
+ print(f"Captured {len(titles)} articles:")
153
+ print(titles[:3])
154
+ ```
155
+
156
+ ### 4. Single-Turn Self-Healing & Diagnostics
157
+ - **Diagnostic Auto-Snapshot**: When an unhandled exception occurs, Arthur automatically captures the latest DOM snapshot (`[diagnostic_auto_snapshot]`) and appends it to the error payload, allowing the agent to self-heal in a single turn without extra roundtrips.
158
+ - **Fuzzy Suggestions**: If an element reference becomes stale after a dynamic DOM mutation, Arthur provides fuzzy match suggestions from snapshot history.
159
+
160
+ ### 5. Output Budgeting & Telemetry Defanging
161
+ All execution output passes through a strict budgeting pipeline:
162
+ - Prevents context window explosion by truncating output exceeding token/character limits.
163
+ - Automatically defangs tracking image beacons (`![beacon](url)` -> `[IMAGE_BLOCKED]`) and unsafe active HTML tags.
164
+
165
+ ---
166
+
167
+ ## Python API Reference
168
+
169
+ The synchronous `browser` instance is pre-injected into the REPL environment:
170
+
171
+ ```python
172
+ # --- Navigation & Inspection ---
173
+ browser.navigate("https://example.com", timeout=30.0)
174
+ snapshot_text = browser.snapshot()
175
+ current_url = browser.url
176
+ page_title = browser.title
177
+
178
+ # --- Synthetic Interactions (Ref-ID, String Ref, or CSS Selector) ---
179
+ browser.click(1) # Click Ref-ID #1
180
+ browser.click("[#1]") # String Ref-ID format
181
+ browser.click("button.submit-btn") # CSS selector fallback
182
+ browser.type(2, "search query", press_enter=True)
183
+ browser.select(3, "Option Value")
184
+ browser.hover(1)
185
+ browser.scroll(x=0, y=500)
186
+
187
+ # --- Synchronization & Waiting ---
188
+ browser.wait_for(1, state="visible", timeout=10.0)
189
+ browser.wait_for_url(r"^https://example\.com/dashboard", timeout=15.0)
190
+
191
+ # --- Evaluation & Captures ---
192
+ result = browser.eval_js("window.innerWidth")
193
+ png_bytes = browser.screenshot()
194
+ text_content = browser.get_text(1)
195
+ attr_value = browser.get_attribute(1, "data-custom")
196
+
197
+ # --- Multi-Tab Management ---
198
+ new_tab = browser.new_tab("https://google.com")
199
+ tabs = browser.tabs # List of open Tab instances
200
+ active = browser.active_tab
201
+ tab_2 = browser.get_tab(2)
202
+ browser.close_tab(2)
203
+ ```
204
+
205
+ ---
206
+
207
+ ## Remote Deployment & Transports
208
+
209
+ Arthur supports multiple network transports for remote, cloud, and containerized deployments.
210
+
211
+ ### 1. Stateless Streamable HTTP (Recommended for Remote / Cloud)
212
+
213
+ For remote servers, VMs, Docker containers, Cloudflare Tunnels, and reverse proxies, **Stateless Streamable HTTP is the most reliable transport**.
214
+
215
+ #### Why Stateless HTTP is Superior for Remote Setups:
216
+ - **Resilient to Network Drops**: Unlike stateful SSE connections that drop or report "Session Expired" when a network glitch occurs between agent turns, stateless HTTP treats each tool execution as an independent request.
217
+ - **Proxy & Tunnel Friendly**: Works cleanly behind Nginx, Cloudflare Tunnels, AWS ALBs, and Ngrok without hitting idle connection timeouts (e.g. 60s stream timeouts).
218
+ - **Preserved Backend State**: While the HTTP wire transport is stateless, Arthur's in-memory Python REPL session, Chromium browser instance, cookies, and open tabs remain fully persistent on the server.
219
+
220
+ #### Starting Stateless Streamable HTTP:
221
+ ```bash
222
+ # Start server on remote host (listening on 0.0.0.0:8000)
223
+ uv run arthur mcp --transport streamable-http --stateless --host 0.0.0.0 --port 8000
224
+ ```
225
+
226
+ #### Client Configuration:
227
+ ```json
228
+ {
229
+ "mcpServers": {
230
+ "arthur": {
231
+ "url": "http://remote-server-ip:8000/mcp"
232
+ }
233
+ }
234
+ }
235
+ ```
236
+
237
+ ---
238
+
239
+ ### 2. SSH Stdio Tunneling (Zero-Port Remote Access)
240
+
241
+ Run Arthur securely over SSH without opening public firewall ports:
242
+
243
+ ```json
244
+ {
245
+ "mcpServers": {
246
+ "remote-arthur": {
247
+ "command": "ssh",
248
+ "args": [
249
+ "user@remote-host",
250
+ "uvx --from git+https://github.com/sh7vansh/arthur arthur mcp"
251
+ ]
252
+ }
253
+ }
254
+ }
255
+ ```
256
+
257
+ ---
258
+
259
+ ### 3. Server-Sent Events (`/sse`)
260
+
261
+ For legacy MCP clients requiring standard SSE endpoints:
262
+
263
+ ```bash
264
+ uv run arthur mcp --transport sse --host 0.0.0.0 --port 8000
265
+ ```
266
+ - **Endpoint**: `http://<host>:8000/sse`
267
+
268
+ ---
269
+
270
+ ## Testing & Development
271
+
272
+ Run the test suite to validate CDP WebSocket transport, headless Chromium lifecycle, in-page DOM operations, and persistent REPL execution:
273
+
274
+ ```bash
275
+ # Run pytest test suite
276
+ uv run pytest
277
+
278
+ # Run type checker
279
+ uv run mypy src
280
+ ```
281
+
282
+ ---
283
+
284
+ ## License
285
+
286
+ This project is licensed under the **MIT License** — see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,15 @@
1
+ # 01 — Minimal CDP WebSocket Client & Session Dispatcher
2
+
3
+ **What to build:** An asynchronous, thread-safe Chrome DevTools Protocol (CDP) WebSocket client that connects to Chromium's remote debugging endpoint, correlates auto-incrementing numeric command IDs with awaiting futures, multiplexes target sessions (`sessionId`) across a single connection, and dispatches asynchronous CDP event streams to registered listeners.
4
+
5
+ **Blocked by:** None — can start immediately.
6
+
7
+ **Status:** closed
8
+
9
+ - [x] Connects to Chromium's DevTools WebSocket endpoint via lightweight async transport.
10
+ - [x] Provides generic `call(method, params, session_id)` interface resolving responses and propagating errors.
11
+ - [x] Correlates request IDs with awaiting futures for concurrent command execution.
12
+ - [x] Supports target session multiplexing via `Target.attachToTarget` (with `flatten: true`).
13
+ - [x] Dispatches incoming CDP domain events to registered event callbacks.
14
+ - [x] Gracefully detects connection drops and raises structured `BrowserUnavailableError`.
15
+ - [x] Unit & mock-server test suite passing.
@@ -0,0 +1,14 @@
1
+ # 02 — Headless Chromium Process Lifecycle & Ephemeral Sandbox
2
+
3
+ **What to build:** Cross-platform Chromium binary discovery, ephemeral `--user-data-dir` sandboxing, launching modern `--headless=new` with ephemeral port allocation, DevToolsActivePort/WebSocket discovery, and guaranteed zero-leak process termination on exit or POSIX signals.
4
+
5
+ **Blocked by:** None — can start immediately.
6
+
7
+ **Status:** closed
8
+
9
+ - [x] Discovers local Chromium binary across `CHROMIUM_PATH`, system paths (`chromium`, `google-chrome`, etc.), and sandbox fallbacks.
10
+ - [x] Creates isolated temporary user data directory per session.
11
+ - [x] Launches Chromium subprocess with `--headless=new`, `--remote-debugging-port=0`, `--no-first-run`, and minimal memory flags.
12
+ - [x] Reads assigned DevTools port / WebSocket URL reliably from `DevToolsActivePort`.
13
+ - [x] Registers `atexit` and signal handlers (`SIGINT`, `SIGTERM`) to kill subprocess tree and purge temporary user directory.
14
+ - [x] Unit & lifecycle integration tests passing.
@@ -0,0 +1,14 @@
1
+ # 03 — In-Page Semantic Snapshot Generator & Ref-ID Registry
2
+
3
+ **What to build:** In-page DOM engine evaluation via CDP `Runtime.evaluate` that generates compact, token-efficient semantic text snapshots with interactive roles, accessible names, Ref-IDs (`[#1]`, `[#2]`), element bounding coordinates, and historical state for stale reference detection.
4
+
5
+ **Blocked by:** 01 (Minimal CDP WebSocket Client), 02 (Headless Chromium Process Lifecycle).
6
+
7
+ **Status:** closed
8
+
9
+ - [x] Injects and evaluates DOM engine in target page context via CDP `Runtime.evaluate`.
10
+ - [x] Resolves accessible roles (`button`, `link`, `textbox`, `combobox`, `checkbox`, `heading`, etc.) and accessible names.
11
+ - [x] Assigns sequential Ref-IDs (`[#1]`, `[#2]`) and stores element references & bounding rect coordinates in `window.__AG_REGISTRY__`.
12
+ - [x] Returns compact semantic text snapshot representation.
13
+ - [x] Detects stale Ref-IDs upon query and returns structured `ElementNotFoundError` with fuzzy match suggestions.
14
+ - [x] Integration tests passing against local HTML test fixtures.