@agent-sh/computer-use-linux 0.5.0 → 0.7.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 CHANGED
@@ -48,7 +48,7 @@ MCP tools exposed by the server:
48
48
  - `list_apps` — running desktop apps visible to the AT-SPI registry
49
49
  - `list_windows` — compositor windows with title, app id, wm_class, focus state, client type (Wayland/X11), and bounds
50
50
  - `focused_window` — the window currently holding keyboard focus
51
- - `get_app_state` — combined screenshot + accessibility tree for a chosen app, with element indices that the input tools accept
51
+ - `get_app_state` — combined screenshot + accessibility tree for a chosen app, with element indices that the input tools accept. Scope it with `app_name_or_bundle_identifier` or a window target; an unscoped call returns the whole desktop tree, reports `tree_scoped: false`, and warns
52
52
  - `screenshot` — capture the screen as a bounded PNG or JPEG image; can target a window, which is raised to the front and cropped to just that window
53
53
 
54
54
  Screenshot payloads are size-bounded by default before they are returned to the MCP host: max 1920 px width/height and 2 MiB image bytes, with hard caps even when callers request more. Agents that need more detail can pass `max_width`, `max_height`, `max_bytes`, `scale`, `format: "jpeg"`, or `quality`, preferably with a window target or crop. PNG remains the default; JPEG lets callers trade lossless pixels for a smaller payload before the byte cap forces further resizing. Returned screenshot metadata includes `coordinate_width`, `coordinate_height`, `scale`, `format`, and `quality` so callers can convert from a downscaled preview to desktop coordinate pixels.
@@ -61,7 +61,24 @@ Screenshot payloads are size-bounded by default before they are returned to the
61
61
  - `press_key` — keys / chords; can focus a window or terminal first
62
62
  - `type_text` — literal text input, optionally targeted at a window or terminal
63
63
 
64
- Targeted `press_key`/`type_text` results append focused-element feedback from AT-SPI (role, name, editable) and warn when no editable element holds focus. Click/screenshot/input results warn when the target window or coordinate is partially or fully off-screen. `get_app_state` returns a compact readiness block by default; pass `verbose: true` for the full diagnostics report.
64
+ For a plain left `click` by element index or selector, a recognized native
65
+ AT-SPI `click`, `press`, or `toggle` action takes precedence
66
+ over bounds. Entry `activate` and slider `jump` must be requested explicitly
67
+ with `perform_action`; they are never a substitute for a pointer click, even
68
+ when bounds are missing.
69
+ This avoids pointer conversion for GTK3 HiDPI
70
+ extents and GTK4 zero-origin bounds when the element exposes such an action.
71
+ The preference does not substitute an arbitrary action name for a coordinate
72
+ click. Explicit `x`/`y`, right clicks, and double/multiple clicks retain pointer
73
+ semantics. Re-check application state after either kind of activation.
74
+
75
+ For coordinate `click` or `scroll` with `relative: true`, select a target window
76
+ and measure from its clipped screenshot crop origin. Divide preview `x` and
77
+ `y` by the returned screenshot `scale` before passing them. These are not raw
78
+ GDK surface or widget-local coordinates; decorations and clipping can change
79
+ the origin. A missing window target is rejected.
80
+
81
+ Targeted `press_key`/`type_text` results append focused-element feedback from AT-SPI (role, name, editable) and warn when no editable element holds focus. Click/screenshot/input results warn when the target window or coordinate is partially or fully off-screen. `get_app_state` returns a compact readiness block by default; pass `verbose: true` for the full diagnostics report. It also reports `tree_scoped` (false when no app target narrowed the AT-SPI tree, with a warning in `message`) and `accessibility_tree_truncated` (true when the node, depth, or read budget stopped traversal with unread elements left).
65
82
 
66
83
  **Semantic actions**
67
84
 
@@ -75,6 +92,8 @@ Targeted `press_key`/`type_text` results append focused-element feedback from AT
75
92
 
76
93
  **Conditional host execution**
77
94
 
95
+ - `complete_interaction` - optional desktop completion notification, registered only with `COMPUTER_USE_LINUX_NOTIFY_ON_COMPLETE=1`. Repeated calls can create repeated notifications; it does not provide desktop exclusivity.
96
+
78
97
  - `run_shell` — same-user `/bin/sh -c` execution without login-profile loading, registered only when the server operator starts the MCP process with `COMPUTER_USE_LINUX_ENABLE_SHELL=1`. It is deliberately absent by default and is not a sandbox.
79
98
 
80
99
  ### MCP safety contract
@@ -99,6 +118,7 @@ The binary also exposes the same capabilities from the CLI for scripting and deb
99
118
  computer-use-linux mcp # stdio MCP server
100
119
  computer-use-linux doctor # JSON readiness report
101
120
  computer-use-linux setup # enable AT-SPI
121
+ computer-use-linux guard-accessibility # explicit foreground GNOME accessibility guard
102
122
  computer-use-linux setup-window-targeting # install GNOME Shell extension
103
123
  computer-use-linux apps
104
124
  computer-use-linux state [APP_NAME]
@@ -358,6 +378,7 @@ Most setups need none of these — `doctor` and the installers pick sensible def
358
378
 
359
379
  | Variable | Effect |
360
380
  | --- | --- |
381
+ | `COMPUTER_USE_LINUX_NOTIFY_ON_COMPLETE` | Set exactly to `1` to expose the optional `complete_interaction` notification tool. Requires `notify-send` and a desktop notification service; disabled by default. |
361
382
  | `COMPUTER_USE_LINUX_COSMIC_HELPER` | Path to the `computer-use-linux-cosmic` helper when it isn't next to the binary or on `PATH`. |
362
383
  | `CU_DISABLE_ABS_POINTER` | Disable the uinput absolute pointer and click through `ydotool` instead for setups where the abs-pointer device misbehaves. |
363
384
  | `COMPUTER_USE_LINUX_FORCE_PORTAL_POINTER` / `…_KEYBOARD` | Always route pointer / keyboard through the RemoteDesktop portal on Wayland, skipping auto-detection. |
@@ -408,6 +429,44 @@ If you're running this on a shared workstation, set `ydotoold`'s socket permissi
408
429
 
409
430
  ## Troubleshooting
410
431
 
432
+ To receive an explicit completion cue, start the MCP server with
433
+ `COMPUTER_USE_LINUX_NOTIFY_ON_COMPLETE=1`. This exposes `complete_interaction`,
434
+ a parameter-free tool the agent calls once after finishing its desktop work.
435
+ It submits a notification through `notify-send` with a two-second execution
436
+ limit and bounded process cleanup. Missing services, errors, or timeouts return
437
+ `cue: "skipped"`; notification settings may suppress a submitted cue. This does
438
+ not reserve the desktop or prove that other clients have stopped sending input.
439
+ No sound or additional desktop settings are enabled by this option.
440
+ This option currently applies only to directly spawned MCP hosts. The native Pi
441
+ extension does not forward the flag or include this optional tool in its catalog.
442
+
443
+ `setup` and `setup_accessibility` write and read back GNOME's
444
+ `org.gnome.desktop.interface toolkit-accessibility` setting, even if AT-SPI
445
+ is already enabled at runtime. A runtime-only success is reported as a warning:
446
+ newly launched GTK apps may still have no tree. Enabling the saved key may
447
+ require restarting target apps. Other accessibility tools can change that key
448
+ later; setup does not continuously override user settings.
449
+
450
+ For an explicit foreground guard while using desktop automation, run:
451
+
452
+ ```bash
453
+ computer-use-linux guard-accessibility
454
+ ```
455
+
456
+ The guard registers a passive AT-SPI window-activation listener and watches
457
+ GNOME's saved `toolkit-accessibility` key. It re-enables the key after a reset
458
+ and verifies it by readback, with periodic checks as well as change monitoring.
459
+ This affects all applications using the current user's GNOME setting, not just
460
+ the target app. It does not start a screen reader or change focus.
461
+
462
+ `mcp`, `setup`, `setup_accessibility`, and `get_app_state` never start this guard.
463
+ Stop it with Ctrl-C or SIGTERM **before** intentionally disabling accessibility.
464
+ Stopping ends setting writes and removes its listener without disabling other
465
+ accessibility clients or restoring an old saved value. A reset and reassertion
466
+ are not atomic: an app launched in that interval may still need restarting.
467
+ This is an opt-in mitigation, not a guarantee that every GNOME toggle sequence
468
+ preserves application accessibility trees.
469
+
411
470
  `computer-use-linux doctor` is the source of truth. Common failure modes and fixes:
412
471
 
413
472
  - **`accessibility.at_spi_bus.ok = false`** — AT-SPI registry isn't running or the toolkit bridge is off. Fix: `computer-use-linux setup` (or call the `setup_accessibility` MCP tool). Restart the apps you want to drive.
@@ -419,9 +478,30 @@ If you're running this on a shared workstation, set `ydotoold`'s socket permissi
419
478
  - **KWin / Hyprland / i3 / COSMIC / X11 windowing is unavailable** — check `doctor.windowing.backends`. KWin needs session-bus scripting; Hyprland needs `hyprctl`; i3 needs `i3-msg` and its IPC socket; generic X11 needs `wmctrl` and `xprop`. COSMIC needs `computer-use-linux-cosmic`, which the standard installers provide automatically; if you copied binaries by hand, copy the helper too or set `COMPUTER_USE_LINUX_COSMIC_HELPER`.
420
479
  - **Screenshots return black frames on multi-monitor setups** — known portal / compositor edge case. Use `get_app_state` with `include_screenshot: false` and rely on AT-SPI until the portal backend is healthy.
421
480
  - **`type_text` types into the wrong window** — pass an explicit target (`window_id`, `pid`, `wm_class`, `title`, or for terminals `tty` / `terminal_pid` / `terminal_command` / `terminal_cwd`). Without a target, input goes to whatever window currently has compositor focus.
481
+ - **Wayland pointer actions miss an unfocused window** — injected pointer input is subject to the compositor's input-focus rules. Call `activate_window` for the target before `click`, `drag`, or coordinate `scroll`; a pointer can land at the requested coordinate without the unfocused surface receiving the action.
422
482
 
423
483
  If `doctor` is green and a specific tool still misbehaves, file an issue with the JSON output of `doctor` and the failing tool's request payload.
424
484
 
485
+ For coordinate calibration, launch [the GTK4 probe](examples/coordinate_probe.py)
486
+ in your test desktop and take a targeted screenshot. Choose the center of its
487
+ green 10x10 square from that screenshot, convert by `scale`, and click relative
488
+ to the same target window. The probe's delivered-event `hit: true` is the
489
+ acceptance condition. Do not pass its widget-local `(85, 85)` directly as a
490
+ window-relative click: margins and decorations belong to different spaces.
491
+
492
+ [The semantic-click regression](scripts/semantic_click_test.py) runs against a
493
+ built binary in an isolated graphical display and checks actual GTK3 button
494
+ activation through MCP at scales 1 and 2. This does not establish correctness
495
+ of Mutter 46 EWMH move/resize, all mixed-output layouts, or GNOME 50.4 pointer
496
+ clicks.
497
+
498
+ Native Wayland qualification on GNOME 50.1 at 133.3% display scale used the
499
+ same green target for both modes: crop-relative `(122, 145)` and desktop
500
+ `(2140, 193)` both delivered widget coordinates approximately `(84.81, 84.78)`
501
+ with `hit: true` through uinput. These are one capture's measured coordinates,
502
+ not reusable offsets. Raw surface coordinates must still be transformed before
503
+ comparing them with a widget-local target.
504
+
425
505
  ## Related
426
506
 
427
507
  - [agent-workspace-linux](https://github.com/agent-sh/agent-workspace-linux) — the sibling MCP that gives an agent its **own** isolated Linux desktop (a hidden Xvfb display with its own apps and browser) instead of driving yours. It is the inverse of this project: `computer-use-linux` automates the desktop you are already on; `agent-workspace-linux` sandboxes the agent in a separate one. Use them together.
package/npm/README.md CHANGED
@@ -9,6 +9,17 @@ mutating and can change real application state. The MCP tool list includes
9
9
  `ToolAnnotations` so hosts can distinguish read-only observation from mutating
10
10
  desktop actions.
11
11
 
12
+ Plain left `click` by element index or selector prefers a native AT-SPI
13
+ `click`, `press`, or `toggle` action over toolkit bounds,
14
+ avoiding pointer-coordinate conversion when that action is available. Explicit
15
+ `activate`/`jump` requests belong in `perform_action`, not `click`, even when
16
+ bounds are missing. Explicit
17
+ `x`/`y`, right clicks, and multi-clicks retain pointer semantics. For coordinate
18
+ `click` or `scroll` with `relative: true`, use the clipped target-window
19
+ screenshot crop origin and divide preview coordinates by screenshot `scale`.
20
+ Do not use widget-local or raw GDK surface coordinates. A window target is
21
+ required.
22
+
12
23
  ```bash
13
24
  npm install -g @agent-sh/computer-use-linux
14
25
  computer-use-linux doctor
@@ -20,6 +31,28 @@ hermes mcp test computer-use-linux
20
31
  hermes mcp configure computer-use-linux
21
32
  ```
22
33
 
34
+ For an optional MCP completion notification, set
35
+ `COMPUTER_USE_LINUX_NOTIFY_ON_COMPLETE=1` in the server environment and have the
36
+ agent call `complete_interaction` after its desktop work. `notify-send` must be
37
+ installed with an available desktop notification service. The cue is best effort
38
+ and does not provide exclusive desktop ownership.
39
+ This cue is available only to directly spawned MCP hosts; the native Pi extension
40
+ does not yet forward the flag or include the tool in its catalog.
41
+
42
+ If accessibility is disabled, run `computer-use-linux setup`. Setup writes and
43
+ reads back GNOME's `toolkit-accessibility` setting and warns if only runtime
44
+ accessibility is available. Restart target apps if their trees remain empty.
45
+
46
+ To explicitly keep that saved setting enabled during desktop automation, run
47
+ `computer-use-linux guard-accessibility` in a foreground terminal. It registers
48
+ a passive AT-SPI window-activation listener and reasserts the current user's
49
+ GNOME `toolkit-accessibility` key after resets, verifying each write by readback.
50
+ This affects other apps using the same user setting. MCP, setup, and
51
+ `get_app_state` never start it automatically. Stop with Ctrl-C or SIGTERM before
52
+ disabling accessibility; stopping removes its listener and ends writes without
53
+ disabling other clients or restoring an old value. An app launched during a
54
+ reset may still need restarting, so this is not a complete GNOME toggle fix.
55
+
23
56
  The generated Hermes config should look like this:
24
57
 
25
58
  ```yaml
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-sh/computer-use-linux",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Linux desktop-control MCP server: AT-SPI accessibility trees, Wayland/X11 input, screenshots, and compositor window targeting.",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -7,9 +7,9 @@ export interface GeneratedMcpToolDefinition {
7
7
  annotations: Record<string, unknown>;
8
8
  }
9
9
 
10
- export const GENERATED_SERVER_VERSION = "0.5.0";
11
- export const GENERATED_TOOL_CATALOG_HASH = "3dd52d53c100e240fe2789dd1818ef80fd30202331c0aca2718212e2a79e47ff";
12
- export const GENERATED_SHELL_TOOL_CATALOG_HASH = "13406c87ad78dbdea7e5480e3e482be14c97687fa92320fde8e16f2efbbd3339";
10
+ export const GENERATED_SERVER_VERSION = "0.7.0";
11
+ export const GENERATED_TOOL_CATALOG_HASH = "c0c1e9d0e200637ff286baec47b6ee8a6798c7e17f29a9cb71a62a8c292a47ed";
12
+ export const GENERATED_SHELL_TOOL_CATALOG_HASH = "f2ebf4164a8a92893933b674bf761430251dce068d7944ce363c99eb88d316ff";
13
13
  export const GENERATED_MCP_TOOLS =
14
14
  [
15
15
  {
@@ -102,7 +102,7 @@ export const GENERATED_MCP_TOOLS =
102
102
  "openWorldHint": true,
103
103
  "readOnlyHint": false
104
104
  },
105
- "description": "Click an element by index, semantic selector, or desktop coordinate pixels from screenshot metadata.",
105
+ "description": "Click an element by index, semantic selector, or desktop coordinate pixels from screenshot metadata. Plain left activation prefers a native AT-SPI click/press/toggle action, avoiding toolkit coordinate scaling. Entry activate and slider jump actions are not substituted for pointer clicks. Explicit coordinates, right clicks, and multi-clicks retain pointer semantics.",
106
106
  "inputSchema": {
107
107
  "$schema": "https://json-schema.org/draft/2020-12/schema",
108
108
  "properties": {
@@ -153,7 +153,7 @@ export const GENERATED_MCP_TOOLS =
153
153
  },
154
154
  "relative": {
155
155
  "default": null,
156
- "description": "Interpret `x`/`y` as relative to the targeted window's top-left corner\n(the same coordinate space as a window-cropped `screenshot`). Requires a\nwindow target; ignored otherwise.",
156
+ "description": "Interpret `x`/`y` from the clipped window screenshot crop origin, in\ncoordinate pixels before preview resizing. Divide preview pixels by its\nscale first. This is not a toolkit widget or raw GDK surface origin.\nRequires a window target; missing targets are rejected.",
157
157
  "type": [
158
158
  "boolean",
159
159
  "null"
@@ -298,7 +298,7 @@ export const GENERATED_MCP_TOOLS =
298
298
  "openWorldHint": true,
299
299
  "readOnlyHint": true
300
300
  },
301
- "description": "Start an app use session if needed, then get a size-bounded screenshot and accessibility state for a Linux app. Screenshot results include coordinate_width, coordinate_height, scale, format, and quality when the returned image is downscaled or compressed; callers can request jpeg/quality for compression before resizing.",
301
+ "description": "Start an app use session if needed, then get a size-bounded screenshot and accessibility state for a Linux app. Scope the accessibility tree with app_name_or_bundle_identifier or a window_id/pid/app_id/wm_class/title target; omitting a target returns the whole desktop tree and can flood context. Screenshot results include coordinate_width, coordinate_height, scale, format, and quality when the returned image is downscaled or compressed; callers can request jpeg/quality for compression before resizing.",
302
302
  "inputSchema": {
303
303
  "$defs": {
304
304
  "ScreenshotOutputFormat": {
@@ -313,6 +313,7 @@ export const GENERATED_MCP_TOOLS =
313
313
  "properties": {
314
314
  "app_id": {
315
315
  "default": null,
316
+ "description": "Application id. Also scopes the accessibility tree when it matches an\nAT-SPI root.",
316
317
  "type": [
317
318
  "string",
318
319
  "null"
@@ -320,6 +321,7 @@ export const GENERATED_MCP_TOOLS =
320
321
  },
321
322
  "app_name_or_bundle_identifier": {
322
323
  "default": null,
324
+ "description": "App name or AT-SPI id that limits the accessibility tree. Omit only when\nyou need the whole desktop tree; unscoped results can flood context.",
323
325
  "type": [
324
326
  "string",
325
327
  "null"
@@ -339,6 +341,7 @@ export const GENERATED_MCP_TOOLS =
339
341
  },
340
342
  "include_screenshot": {
341
343
  "default": null,
344
+ "description": "Include a size-bounded screenshot (default true). Set false when the\naccessibility tree is enough.",
342
345
  "type": [
343
346
  "boolean",
344
347
  "null"
@@ -391,6 +394,7 @@ export const GENERATED_MCP_TOOLS =
391
394
  },
392
395
  "pid": {
393
396
  "default": null,
397
+ "description": "Process id. Also scopes the accessibility tree to that process when it\nexposes AT-SPI.",
394
398
  "minimum": 0,
395
399
  "type": [
396
400
  "integer",
@@ -418,6 +422,7 @@ export const GENERATED_MCP_TOOLS =
418
422
  },
419
423
  "terminal_command": {
420
424
  "default": null,
425
+ "description": "Terminal command substring. Resolves a window target and scopes the tree\nwhen possible.",
421
426
  "type": [
422
427
  "string",
423
428
  "null"
@@ -425,6 +430,7 @@ export const GENERATED_MCP_TOOLS =
425
430
  },
426
431
  "terminal_cwd": {
427
432
  "default": null,
433
+ "description": "Terminal working directory. Resolves a window target and scopes the tree\nwhen possible.",
428
434
  "type": [
429
435
  "string",
430
436
  "null"
@@ -432,6 +438,7 @@ export const GENERATED_MCP_TOOLS =
432
438
  },
433
439
  "terminal_pid": {
434
440
  "default": null,
441
+ "description": "Terminal emulator pid. Resolves a window target and scopes the tree when\npossible.",
435
442
  "minimum": 0,
436
443
  "type": [
437
444
  "integer",
@@ -440,6 +447,7 @@ export const GENERATED_MCP_TOOLS =
440
447
  },
441
448
  "title": {
442
449
  "default": null,
450
+ "description": "Window title substring. Also scopes the accessibility tree when it\nmatches an AT-SPI root.",
443
451
  "type": [
444
452
  "string",
445
453
  "null"
@@ -447,6 +455,7 @@ export const GENERATED_MCP_TOOLS =
447
455
  },
448
456
  "tty": {
449
457
  "default": null,
458
+ "description": "Terminal tty device (for example /dev/pts/3). Resolves a window target\nand scopes the tree when possible.",
450
459
  "type": [
451
460
  "string",
452
461
  "null"
@@ -462,6 +471,7 @@ export const GENERATED_MCP_TOOLS =
462
471
  },
463
472
  "window_id": {
464
473
  "default": null,
474
+ "description": "Compositor window id. Also scopes the accessibility tree to that window's\napplication when possible.",
465
475
  "minimum": 0,
466
476
  "type": [
467
477
  "integer",
@@ -470,6 +480,7 @@ export const GENERATED_MCP_TOOLS =
470
480
  },
471
481
  "wm_class": {
472
482
  "default": null,
483
+ "description": "Window manager class. Also scopes the accessibility tree when it matches\nan AT-SPI root.",
473
484
  "type": [
474
485
  "string",
475
486
  "null"
@@ -1043,7 +1054,7 @@ export const GENERATED_MCP_TOOLS =
1043
1054
  },
1044
1055
  "relative": {
1045
1056
  "default": null,
1046
- "description": "Interpret `x`/`y` as relative to the targeted window's top-left corner\n(the same coordinate space as a window-cropped `screenshot`). Requires a\nwindow target; ignored otherwise.",
1057
+ "description": "Interpret `x`/`y` from the clipped window screenshot crop origin, in\ncoordinate pixels before preview resizing. Divide preview pixels by its\nscale first. This is not a toolkit widget or raw GDK surface origin.\nRequires a window target; missing targets are rejected.",
1047
1058
  "type": [
1048
1059
  "boolean",
1049
1060
  "null"
@@ -24,13 +24,23 @@ Do not use this for remote browsers, websites, or headless automation when a bro
24
24
 
25
25
  ## Install
26
26
 
27
- Pi users need only the package:
27
+ Pick the install that matches how you will run this skill. You can use both.
28
+
29
+ ### Pi native tools
28
30
 
29
31
  ```bash
30
32
  pi install npm:@agent-sh/computer-use-linux
31
33
  ```
32
34
 
33
- Preferred install:
35
+ This enables Pi's `computer_use_linux_*` tools. It does not put
36
+ `computer-use-linux` on `PATH`. Shell commands in this skill (`doctor`,
37
+ `setup`, `setup-window-targeting`, `guard-accessibility`, the MCP `command`
38
+ config, and Verification) need the CLI install below.
39
+
40
+ ### Shell CLI / MCP server
41
+
42
+ Use this when you need `computer-use-linux` on `PATH` for the commands in this
43
+ skill.
34
44
 
35
45
  ```bash
36
46
  npm install -g @agent-sh/computer-use-linux
@@ -56,6 +66,31 @@ If `doctor` selects ydotool as the input backend, also enable its per-user daemo
56
66
 
57
67
  On GNOME Wayland, log out and back in after `setup-window-targeting` if the GNOME Shell extension was newly installed.
58
68
 
69
+ For MCP hosts with `COMPUTER_USE_LINUX_NOTIFY_ON_COMPLETE=1`, call the optional
70
+ `complete_interaction` tool once after finishing desktop interaction. A skipped
71
+ cue is not a task failure. This notification does not guarantee exclusive
72
+ desktop ownership or that other clients have stopped sending input.
73
+ This applies only to directly spawned MCP hosts, not the native Pi extension.
74
+
75
+ `setup_accessibility` verifies the saved GNOME `toolkit-accessibility` key
76
+ separately from runtime AT-SPI. Inspect its warning and readback before assuming
77
+ new apps can expose trees. Other accessibility tools may change the key later;
78
+ setup does not hold it enabled continuously.
79
+
80
+ ### Optional foreground accessibility guard
81
+
82
+ Skip unless: the user explicitly wants GNOME's saved `toolkit-accessibility`
83
+ setting kept enabled while desktop automation runs.
84
+
85
+ Run `computer-use-linux guard-accessibility` in a foreground terminal. It
86
+ registers a passive AT-SPI window-activation listener and watches/reasserts the
87
+ saved key with readback. The setting affects all apps for the current user.
88
+ `mcp`, setup, and `get_app_state` never start this guard automatically.
89
+ Stop with Ctrl-C or SIGTERM before intentionally disabling accessibility.
90
+ Stopping ends writes and removes its listener without disabling other clients
91
+ or restoring a previous saved value. Apps launched during a reset/reassertion
92
+ race may still need restarting; do not claim a complete GNOME toggle fix.
93
+
59
94
  ## Configure Your Agent
60
95
 
61
96
  The `computer-use-linux` binary is an MCP server. Configure it as a stdio MCP server in your agent of choice:
@@ -68,6 +103,7 @@ The `computer-use-linux` binary is an MCP server. Configure it as a stdio MCP se
68
103
  ```
69
104
 
70
105
  If the binary is not on `PATH`, use the absolute path (typically `~/.local/bin/computer-use-linux` or the npm global bin directory).
106
+ Pi native tools skip this MCP `command` config; see [Pi setup](references/pi-setup.md).
71
107
 
72
108
  ### Host-specific guides
73
109
 
@@ -77,7 +113,7 @@ If the binary is not on `PATH`, use the absolute path (typically `~/.local/bin/c
77
113
  ## Procedure
78
114
 
79
115
  1. In Pi, call `computer_use_linux_tools` with the exact tools or capability you need. Enabled tools use the `computer_use_linux_<name>` prefix, appear starting on the next model turn, and remain active for the session.
80
- 2. Begin every desktop-control turn with `get_app_state`; use `include_screenshot: false` when the accessibility tree is sufficient. Its compact readiness block identifies missing setup.
116
+ 2. Begin every desktop-control turn with `get_app_state`, scoped to the app you are working in: pass `app_name_or_bundle_identifier` or a window target (`window_id`, `pid`, `app_id`, `wm_class`, `title`). Without a target the result is the whole desktop AT-SPI tree, `tree_scoped` is `false`, and `message` warns; that can flood context. Use `include_screenshot: false` when the accessibility tree is sufficient. If `accessibility_tree_truncated` is `true`, the tree is incomplete: scope to a narrower target and raise `max_nodes` or `max_depth` (hard caps 2000 and 64) rather than lowering them. The compact readiness block identifies missing setup.
81
117
  3. Use `doctor` only when you need the full diagnostic report.
82
118
  4. If `can_build_accessibility_tree` is false, run `setup_accessibility` and restart the target app.
83
119
  5. If `can_query_windows` is false on GNOME Wayland, run `setup_window_targeting` and ask the user to log out and back in if setup says the shell extension needs a reload.
@@ -87,6 +123,26 @@ If the binary is not on `PATH`, use the absolute path (typically `~/.local/bin/c
87
123
  9. For text input, prefer `type_text` with a target selector (`window_id`, `pid`, `app_id`, `wm_class`, `title`, `tty`, `terminal_pid`, `terminal_command`, or `terminal_cwd`) rather than relying on current focus.
88
124
  10. After mutating actions, re-check state with `get_app_state`, `focused_window`, or an app-specific readback.
89
125
 
126
+ Plain left element/index/selector `click` prefers native AT-SPI `click`,
127
+ `press`, or `toggle` over toolkit bounds, avoiding coordinate
128
+ conversion when available. This preference does not replace a coordinate click
129
+ with an arbitrary action name. Explicit `x`/`y`, right clicks, and double/multiple
130
+ clicks retain pointer semantics.
131
+ Use `perform_action` explicitly for entry `activate` or slider `jump`; `click`
132
+ never substitutes those actions, including when bounds are unavailable.
133
+
134
+ ### Screenshot-relative coordinates
135
+
136
+ Skip unless: a coordinate `click` or `scroll` uses `relative: true`.
137
+
138
+ Select a target window and use its clipped screenshot crop origin. Divide
139
+ preview `x`/`y` by screenshot `scale` first. Widget-local and raw GDK surface
140
+ coordinates are not interchangeable with that origin; missing window targets
141
+ are rejected. For calibration, use the repository's
142
+ `examples/coordinate_probe.py`: select the green square from the screenshot
143
+ and require a delivered-event `hit: true`. Do not pass widget-local `(85, 85)`
144
+ directly to a window-relative click.
145
+
90
146
  ## Pitfalls
91
147
 
92
148
  - Already-running GTK, Qt, and Electron apps may need a restart after AT-SPI is enabled.
@@ -100,6 +156,10 @@ If the binary is not on `PATH`, use the absolute path (typically `~/.local/bin/c
100
156
 
101
157
  ## Verification
102
158
 
159
+ Pi-only installs: enable and call `computer_use_linux_doctor` as in
160
+ [Pi setup](references/pi-setup.md). Shell `computer-use-linux doctor` needs
161
+ the CLI on `PATH`.
162
+
103
163
  Run:
104
164
 
105
165
  ```bash
@@ -14,7 +14,10 @@ pi install npm:@agent-sh/computer-use-linux
14
14
  ```
15
15
 
16
16
  Restart Pi or run `/reload`. No separate MCP adapter or MCP configuration is
17
- required.
17
+ required. This does not put `computer-use-linux` on `PATH`. For shell `doctor`,
18
+ `setup`, or MCP hosts, also install the CLI with
19
+ `npm install -g @agent-sh/computer-use-linux` or
20
+ `cargo install computer-use-linux`.
18
21
 
19
22
  The integration is designed for current Pi releases with additive dynamic tool
20
23
  loading. Update Pi and installed packages when needed:
@@ -59,8 +62,11 @@ session so `get_app_state` element indices and portal sessions remain valid.
59
62
  ## Safe operating loop
60
63
 
61
64
  1. Enable `get_app_state`, `list_windows`, and any likely action tools.
62
- 2. Call `computer_use_linux_get_app_state`, using
63
- `include_screenshot: false` when accessibility data is enough.
65
+ 2. Call `computer_use_linux_get_app_state` scoped to the target app
66
+ (`app_name_or_bundle_identifier`, or `window_id`/`pid`/`app_id`/`wm_class`/
67
+ `title`), using `include_screenshot: false` when accessibility data is
68
+ enough. An unscoped call returns the whole desktop tree, reports
69
+ `tree_scoped: false`, and warns; that can exhaust a small context window.
64
70
  3. Inspect the returned readiness block; enable/call `doctor` only for full
65
71
  diagnostics.
66
72
  4. Identify the target with `computer_use_linux_list_windows` or