@bastani/atomic 0.9.56-alpha.1 → 0.9.57-alpha.1

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 (57) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/builtin/intercom/package.json +1 -1
  3. package/dist/builtin/mcp/package.json +1 -1
  4. package/dist/builtin/subagents/CHANGELOG.md +24 -0
  5. package/dist/builtin/subagents/package.json +1 -1
  6. package/dist/builtin/subagents/skills/agent-desktop/SKILL.md +83 -0
  7. package/dist/builtin/web-access/package.json +1 -1
  8. package/dist/builtin/workflows/CHANGELOG.md +12 -0
  9. package/dist/builtin/workflows/builtin/adversarial-verification.js +3 -3
  10. package/dist/builtin/workflows/builtin/{chunk-49kkbdpr.js → chunk-2f1shjah.js} +1 -1
  11. package/dist/builtin/workflows/builtin/{chunk-dcxscfnb.js → chunk-37gm3bzk.js} +1 -1
  12. package/dist/builtin/workflows/builtin/{chunk-2jfst7e4.js → chunk-45fn5q5p.js} +1 -1
  13. package/dist/builtin/workflows/builtin/{chunk-hx8v4p97.js → chunk-4ek3v2wm.js} +1 -1
  14. package/dist/builtin/workflows/builtin/{chunk-z3pajrfs.js → chunk-8d40nyz9.js} +1 -1
  15. package/dist/builtin/workflows/builtin/{chunk-qhm35ntx.js → chunk-g3b2zf8r.js} +2 -2
  16. package/dist/builtin/workflows/builtin/{chunk-6jpwc09k.js → chunk-h6bt0r0g.js} +2 -2
  17. package/dist/builtin/workflows/builtin/{chunk-9cm2ckq2.js → chunk-x25rjw4y.js} +4 -4
  18. package/dist/builtin/workflows/builtin/{chunk-apagcs4r.js → chunk-xqcy5nve.js} +1 -1
  19. package/dist/builtin/workflows/builtin/{chunk-w4xp1w1f.js → chunk-yb55w6me.js} +1 -1
  20. package/dist/builtin/workflows/builtin/{chunk-k5q3t7je.js → chunk-yjgfnbgd.js} +1 -1
  21. package/dist/builtin/workflows/builtin/classify-and-act.js +3 -3
  22. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +3 -3
  23. package/dist/builtin/workflows/builtin/generate-and-filter.js +3 -3
  24. package/dist/builtin/workflows/builtin/goal.js +3 -3
  25. package/dist/builtin/workflows/builtin/index.js +11 -11
  26. package/dist/builtin/workflows/builtin/loop-until-done.js +3 -3
  27. package/dist/builtin/workflows/builtin/open-claude-design.js +3 -3
  28. package/dist/builtin/workflows/builtin/ralph.js +3 -3
  29. package/dist/builtin/workflows/builtin/steering-context.js +1 -1
  30. package/dist/builtin/workflows/builtin/tournament.js +3 -3
  31. package/dist/builtin/workflows/package.json +1 -1
  32. package/dist/builtin/workflows/src/extension/index.bundle.mjs +7 -7
  33. package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +4 -4
  34. package/dist/builtin/workflows/src/index.js +4 -4
  35. package/dist/builtin/workflows/src/local-worker-entry.mjs +4 -4
  36. package/dist/core/system-prompt.d.ts.map +1 -1
  37. package/dist/core/system-prompt.js +2 -3
  38. package/dist/core/system-prompt.js.map +1 -1
  39. package/docs/computer-use.md +119 -98
  40. package/docs/getting-started/first-session.md +1 -1
  41. package/docs/skills.md +2 -2
  42. package/docs/usage.md +1 -1
  43. package/docs/workflows/authoring.md +105 -141
  44. package/docs/workflows/verification.md +14 -13
  45. package/npm-shrinkwrap.json +32 -32
  46. package/package.json +3 -3
  47. package/dist/builtin/subagents/skills/cua-driver/BROWSER.md +0 -562
  48. package/dist/builtin/subagents/skills/cua-driver/EMBEDDING.md +0 -685
  49. package/dist/builtin/subagents/skills/cua-driver/LINUX.md +0 -412
  50. package/dist/builtin/subagents/skills/cua-driver/MACOS.md +0 -996
  51. package/dist/builtin/subagents/skills/cua-driver/README.md +0 -123
  52. package/dist/builtin/subagents/skills/cua-driver/RECORDING.md +0 -132
  53. package/dist/builtin/subagents/skills/cua-driver/RUNTIME.md +0 -115
  54. package/dist/builtin/subagents/skills/cua-driver/SKILL.md +0 -108
  55. package/dist/builtin/subagents/skills/cua-driver/VISUAL.md +0 -125
  56. package/dist/builtin/subagents/skills/cua-driver/WINDOWS.md +0 -832
  57. package/dist/builtin/subagents/skills/cua-driver/WORKFLOW.md +0 -226
@@ -1,412 +0,0 @@
1
- # cua-driver: Linux
2
-
3
- Start with `cua-driver doctor` in the graphical user's session. X11,
4
- XWayland, and native Wayland expose different capture and input facilities;
5
- successful discovery does not prove either input delivery or window capture.
6
- Use [WORKFLOW.md](WORKFLOW.md) for exact targets and verification and
7
- [RUNTIME.md](RUNTIME.md) for transport and permission ownership.
8
-
9
- On X11, `set_window_frame({pid, window_id, x, y, width, height})` sends an
10
- EWMH window-manager request and confirms it against `list_windows` geometry.
11
- Wayland has no portable protocol for setting another application's top-level
12
- geometry, so this tool refuses there unless a future compositor-owned adapter
13
- can provide exact targeting and readback.
14
-
15
- AT-SPI is talked to natively over D-Bus (the `atspi`/zbus crate): no
16
- `pyatspi` or GObject-introspection typelibs are required at runtime.
17
-
18
- ## Delivery
19
-
20
- Background window input must not activate or raise the target. AT-SPI actions
21
- can reach semantic controls without raw pointer delivery; X11 pixel dispatch
22
- can use AT-SPI hit-testing or a virtual-pointer route. Do not assume all input
23
- uses XSendEvent or that every toolkit accepts it. Inspect the result's public
24
- route and independently verify the application.
25
-
26
- `delivery_mode:"foreground"` is a user-visible takeover. Never select it automatically.
27
- Use explicitly authorized `delivery_mode:"foreground"` only after evidence
28
- that the chosen background route is unavailable or ineffective. Target-specific
29
- activation and restoration depend on the compositor adapter. If activation
30
- cannot be proven, accept the refusal instead of sending keys to whatever is focused.
31
-
32
- The overlay is separate from the physical pointer; cursor-bearing and
33
- keyboard actions re-show it automatically. Distinct overlays do not isolate
34
- desktop input. Keep one controller for a global-input workflow.
35
-
36
- ## Capture recovery
37
-
38
- `get_window_state` requests both AT-SPI and a window screenshot by default.
39
- A valid image is not guaranteed. If `screenshot_error.code` is
40
- `surface_identity_unproven`, the driver cannot attest that output pixels
41
- belong to the requested surface. Preserve that distinction from an empty or
42
- untrusted accessibility tree. Never crop a desktop image and label it an
43
- attested window capture.
44
-
45
- 1. Read any returned tree and `degraded_reason`; semantic interaction may still
46
- be possible without pixels.
47
- 2. Do not retry a window-pixel action without a valid window image. Changing
48
- `capture_mode`, inventing bounds, or repeatedly increasing timeouts cannot
49
- establish surface identity.
50
- 3. If the task permits full-display capture and visible desktop control,
51
- explain the broader scope and obtain authorization if not already given.
52
- Use `get_desktop_state`, then
53
- `target:{"kind":"desktop","display_id":"primary"}` on input, and verify
54
- through another desktop snapshot. See [the desktop loop](WORKFLOW.md#desktop-loop).
55
- 4. If desktop scope is not admitted, report the limitation and stop that route.
56
-
57
- A capture request may be waiting for an OS/portal permission dialog. Inspect
58
- window discovery for a pending prompt, or ask the user to check the desktop.
59
- Let the user approve or deny it. Do not repeatedly start captures, automate
60
- approval, or change security settings as a workaround. After approval, take a
61
- fresh capture and verify its dimensions/content before continuing. A timeout
62
- alone does not prove which permission or backend failed.
63
-
64
- Supporting smoke evidence: Driver 0.23.2 on KDE/KWin Wayland opened an Electron
65
- music app, searched, selected an album track, and showed playback through this
66
- desktop route after user screenshot approval. The window route returned
67
- `surface_identity_unproven`; desktop actions returned `global_input` and
68
- `unverifiable`, so screenshots and user confirmation established the result.
69
- This is not certification of background targeting, other compositors, or video.
70
-
71
- ## X11 observation and input details
72
-
73
- **What is open over the window.** `get_window_state` lists the pid's transient
74
- dialogs (`dialogs: [{window_id, title, transient_for, modal, bounds}]`) and
75
- override-redirect popups (`popups: [...]`) that are mapped, with a `follow_up`
76
- sentence naming the call that targets each one
77
- (`get_window_state(pid, window_id=<that id>)`). When one overlaps the window
78
- the screenshot is taken from the screen (`screenshot_composited:true`) so the
79
- menu or dialog is visible; the window's own drawable never shows them. The
80
- payload states its frame (`coordinate_frame:"window"`, plus `frame_note` with `verbose:true`): `x`/`y`
81
- of the pointer tools are pixels of THIS screenshot. Closed menus are listed
82
- with a `description` ("closed menu with N items…") and are not walked;
83
- click the menu (a real press) and read the popup by its window_id.
84
- `press_key` / `hotkey` that map a new top-level report it as `window_opened`
85
- with `window_change` evidence. Action results carry the same text as
86
- `summary` inside `structuredContent`, for clients that only show that.
87
-
88
- **Screenshot scale.** The window screenshot is delivered at or below 1.15
89
- megapixels (long edge ≤ `max_image_dimension`, 1568 by default): larger
90
- images are downsized before a model reads them, and its pixel coordinates
91
- would then be uniformly short. Pointer `x`/`y` and each element's
92
- `screenshot_frame` are pixels of the delivered image (the element's `frame`
93
- stays in screen coordinates, as on every platform); `frame_scale` < 1 and
94
- `screenshot_original_width` report the downsizing, and the driver scales your
95
- pixels back to the window.
96
- An explicit per-call `max_image_dimension` (0 = native) replaces this cap.
97
-
98
- **Budget the pixels before you aim.** The cap is a pixel budget, so on a
99
- high-resolution window the delivered image is a small fraction of native and
100
- fine controls stop being readable. Measured on a 3840x2342 window: `frame_scale`
101
- 0.357, so a 24px toolbar icon arrives at ~8.6px and a 1px border at ~0.36px:
102
- sub-pixel for any reader, sighted or not. Check `frame_scale` in the
103
- `get_window_state` payload and, when a target is smaller than roughly 30px, frame
104
- it with `zoom` before choosing a coordinate. Zooming a 196x728 window-px region
105
- returned a 235x873 image (about 1.2x native), which restores a 24px icon to
106
- ~29px. `zoom` takes screenshot pixels and the follow-up action needs
107
- `from_zoom: true`. It also requires a screenshot-owning snapshot from the same
108
- session first, and refuses with `screenshot_context_missing` otherwise, so
109
- `get_window_state` with a screenshot must precede the first `zoom`.
110
-
111
- **When the active model takes no images.** Some clients drop image content
112
- entirely, so `get_window_state` and `zoom` return an image the reader never sees.
113
- The loop still closes for most questions, and none of this needs a vision model:
114
- `verify_state` proves state and returns a real `satisfied` / `unsatisfied` /
115
- `unknown` verdict; an out-of-band read such as
116
- `xprop -root _NET_ACTIVE_WINDOW` proves which window holds focus; and scanning the
117
- written capture for colour transitions (PIL or equivalent) proves coarse layout.
118
- What none of them prove is that a specific small control was activated. For that
119
- use the `cua-perception` extension (see `VISUAL.md`) or an app that exposes a
120
- usable accessibility tree.
121
-
122
- **Windows without `_NET_WM_PID`.** Tk, many Java/AWT builds, Wine, and legacy
123
- Xlib/Xt clients do not publish `_NET_WM_PID`. On X11, `list_windows` then asks
124
- the X server's X-Resource extension (XRes 1.2 `LocalClientPID`) which local
125
- process created the window, so these windows still carry a `pid` and accept
126
- `get_window_state` / `click` by `pid` + `window_id`. The driver never guesses:
127
- `pid` stays `null` when XRes is missing or older than 1.2, when the client
128
- is remote (TCP, or SSH-forwarded with a `WM_CLIENT_MACHINE` naming another
129
- host), or when the X server cannot report the driver's own PID correctly
130
- (remote `DISPLAY`, container PID namespace). A `pid: null` window can only be
131
- reached through desktop scope. An SSH-forwarded client that publishes
132
- neither `_NET_WM_PID` nor `WM_CLIENT_MACHINE` is attributed to the local
133
- `ssh` process, because that is the socket peer the server sees.
134
-
135
- **Keys while the app's own popup is open.** A Qt combo list / completer or a
136
- GTK/VCL menu holds a keyboard grab that makes the X server drop keys from the
137
- virtual keyboard. `press_key` / `hotkey` / `type_text` / `set_value` then go
138
- through the core keyboard (`path: "xtest_core_grab"`, the result names the
139
- popup and states that the core focus and active window were verified
140
- unchanged), or, when another application holds the core focus, are refused
141
- with `code: "popup_keyboard_grab"` and a hint: dismiss the popup (click
142
- outside it, or click one of its rows by element_token after
143
- `get_window_state(pid, window_id=<popup>)`) and retry. Typing an absolute path
144
- into a Qt file dialog opens its completer after the first `/`; prefer
145
- `set_value` on the "File name" field, which writes the path in one go.
146
-
147
- **Popup walks, labels, descriptions.** `get_window_state(pid, window_id=<popup>)`
148
- returns the popup's own rows (list / tree / menu items), never the main
149
- window's menubar. Elements carry `description` when the toolkit publishes one
150
- (Qt keeps a button's tooltip there: `push button "" (description "Pause")`;
151
- `label` falls back to it). A control's `label` is never its value: a spin
152
- button or slider nobody names is `unlabelled: true` with its place in
153
- `description` (`unlabelled spin button; 3rd of 4 spin buttons in this panel`,
154
- in visual order). `parent_index` is the nearest indexed real ancestor.
155
-
156
- **Grid presses.** After a click that lands on a table cell (LibreOffice Calc),
157
- the result appends `focus: cell D2` (`focused_cell`, evidence) read from the
158
- focus log, so a one-row miss is visible before you type.
159
-
160
- **Multi-click.** `click` takes `count: 2` (double) or `count: 3` (triple, a
161
- line/paragraph selection in editors) as one press train with real double-click
162
- cadence in both delivery modes; there is no `triple_click` tool.
163
-
164
- **Typing throughput.** Key-event typing (XTest in foreground, the virtual
165
- keyboard in background) runs at roughly 45-60 characters per second, so a
166
- 1,300-character script takes about 30 s: scale a client-side `type_text`
167
- deadline with the text length instead of using a flat one (0.04 s per
168
- character leaves margin over those rates). A terminal can still be echoing when the call returns; read the
169
- result again before retyping text that looks truncated.
170
-
171
- **Cross-application drops.** A pointer action whose point lies over another
172
- application's window (a drag dropped onto VLC) reports that window's title
173
- change and the windows its pid opened as `foreign_window` / `window_change`
174
- evidence; the focus guard alone only watches the target pid.
175
-
176
- ## Native application menus
177
-
178
- Use `invoke_menu({pid, window_id, path:[...]})` for a known GTK/Qt application
179
- menu command. It activates the exact target only for the duration of the
180
- operation, resolves each labelled AT-SPI menu descendant again after the prior
181
- menu expands, and refuses missing, duplicate, disabled, or non-actionable
182
- segments. It works through AT-SPI on both X11 and Wayland and never falls back
183
- to coordinates. Verify the command's semantic effect from fresh state; the
184
- native `do_action` acknowledgement alone is not task completion.
185
-
186
- ## AT-SPI needs the session bus (headless / containers / `runuser`)
187
-
188
- AT-SPI (the accessibility tree behind `get_window_state`, `element_token`
189
- clicks, and focus-free `type_text`) lives **entirely on the desktop
190
- session's D-Bus**. cua-driver reaches it via `DBUS_SESSION_BUS_ADDRESS`. When
191
- the daemon is started _inside_ a normal desktop login that variable is already
192
- exported and everything works. When it is started **outside** the session
193
- (a container entrypoint, a headless box, `runuser`/`su` into the desktop user,
194
- a systemd _system_ unit, or a VNC session running its own ad-hoc bus), the
195
- variable is unset, the AT-SPI registry walk comes back empty, and
196
- `get_window_state` reports **every** window as having no elements.
197
-
198
- cua-driver now **auto-discovers the session bus at startup** (mirroring the
199
- `XAUTHORITY` recovery): if `DBUS_SESSION_BUS_ADDRESS` is unset it adopts
200
- `/run/user/<uid>/bus`, or reads the address out of a running desktop-session
201
- process's `/proc/<pid>/environ` (`xfce4-session`, `gnome-session`, …). So the
202
- common headless cases now "just work". The two things that still must be true:
203
-
204
- 1. **An accessibility bus must be running** in that session, and
205
- **`toolkit-accessibility` must be on**: cua-driver advertises a screen
206
- reader at startup to flip it, but a session with no a11y bus at all
207
- (`/usr/libexec/at-spi-bus-launcher`) can't expose a tree. `cua-driver
208
- doctor` now probes `org.a11y.Bus` for real (not just "is there a bus?")
209
- and tells you which of the two is missing.
210
- 2. The daemon must run **as the desktop user** (so it can read that user's
211
- session-process environ and the `/run/user/<uid>/bus` socket). Running the
212
- daemon as root against a user session is the Linux analogue of the Windows
213
- "Session 0" isolation problem.
214
-
215
- `get_window_state` returns one compact markdown tree capped at 250 actionable
216
- nodes by default (`full_output:true` restores 5 000 nodes and both forms), and
217
- `since:<snapshot_id>` returns only added/changed/removed rows. The focused
218
- element is not reported on Linux yet, so an unchanged read says only
219
- `no change since …`.
220
-
221
- An empty AT-SPI walk is now surfaced honestly: `get_window_state` sets
222
- `degraded: true` + a `degraded_reason` (instead of a bare `elements: []`) so a
223
- caller can tell "this window genuinely has no controls" apart from "the a11y
224
- bridge isn't up / the daemon isn't on the session bus".
225
-
226
- ## The validated modality matrix (X11 / XFCE)
227
-
228
- Each input rung and its stable public route:
229
-
230
- | Modality | `delivery_mode` | `route` | Postcondition proof |
231
- | ------------------------------- | ------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------- |
232
- | Element click (`element_token`) | `background` | `accessibility` | Use `verify_state`; invocation alone is not confirmation |
233
- | **element px action (x,y)** | `background` | `accessibility` when AT-SPI-at-point lands, otherwise `global_input` | Use `verify_state` or multimodal reading |
234
- | Pixel (px) click, escalated | `foreground` | `global_input` | Use `verify_state` or multimodal reading |
235
- | `type_text` into editable | `background` | `accessibility` | `confirmed` only with `value_readback` evidence |
236
- | `type_text`, non-editable focus | `background`/`foreground` | `synthetic_events` or `global_input` | Use `verify_state` or multimodal reading |
237
-
238
- **A background element px action does land on X11**: for an AX-exposing app it
239
- takes the focus-free AT-SPI `do_action`-at-point path (`x11_atspi`), exactly
240
- like the macOS/Windows background pixel click. It falls to the MPX
241
- virtual-pointer path (`x11_pixel`) only for non-AX surfaces, **and that path
242
- needs a real Xorg + `/dev/uinput`**: under Xvnc / minimal containers without
243
- uinput, escalate to `delivery_mode:"foreground"`. The AT-SPI path only fires
244
- a control under the point: when the hit test finds nothing deeper than the
245
- application's own frame or window (Chromium page content before its AT-SPI
246
- tree is populated), no action is fired. Chromium/Electron targets without a
247
- real focus-free pointer return `background_unavailable` before the capture is
248
- consumed, so retry the same capture-bound click with
249
- `delivery_mode:"foreground"` when foreground input is authorized. (`type_text` in the
250
- `background` rung is focus-dependent for non-editable widgets; that's the one
251
- genuine background limitation, and `foreground` is the documented escalation.)
252
-
253
- ## Wayland
254
-
255
- Set `CUA_DRIVER_RS_ENABLE_WAYLAND=1` to enable native Wayland support. The
256
- driver selects a backend from compositor capabilities:
257
-
258
- - Sway and other wlroots compositors use foreign-toplevel discovery,
259
- wlr-screencopy, virtual pointer, and virtual keyboard protocols.
260
- - Hyprland has separate discovery and capture adapters. Its optional plugin
261
- defaults to discovery-only; the opt-in input v3 source candidate has the
262
- qualification and validation limits below. Do not inherit Sway coverage.
263
- - GNOME/Mutter uses the bundled WinRects Shell helper for target geometry and
264
- activation, plus portal/libei for foreground raw input.
265
- - KDE/KWin uses AT-SPI and portal facilities where available. Target-specific
266
- foreground activation remains experimental, so unsafe raw input refuses.
267
- - The optional `cua-compositor` is a separate nested session enabled
268
- explicitly for controlled automation. GNOME and KDE never switch into it.
269
-
270
- Sway recording works through the wlroots recorder path and is exercised by the
271
- canonical harness runner. Portal-backed GNOME recording is still an evidence
272
- gap. Capture and recording availability therefore depend on the compositor,
273
- installed helpers, and portal grant.
274
-
275
- Standard Wayland has no general client protocol for raw input to an arbitrary
276
- occluded surface. Background AX actions can still deliver through AT-SPI, and
277
- a PX left click can deliver when hit-testing resolves to an actionable AT-SPI
278
- control. Other focus-bound background pointer and keyboard shapes return an
279
- exact `background_unavailable` result. They do not report success after a
280
- silent drop.
281
-
282
- Outside an explicitly enabled, qualified compositor-owned background route,
283
- raw Wayland input requires explicitly authorized `delivery_mode:"foreground"`.
284
- The driver activates the selected target through a verified compositor adapter
285
- before dispatch. If
286
- the compositor has no target-addressable activation or input backend, the call
287
- refuses before sending input. Reconstructing coordinates alone does not make
288
- raw background PX possible on a standard compositor.
289
-
290
- ### Hyprland input v3 source candidate
291
-
292
- [PR #3572](https://github.com/trycua/cua/pull/3572) records dated, exact-source
293
- validation results for the experimental opt-in input v3 candidate. Acceptance
294
- requires the unchanged complete Linux canonical runner on native Hyprland and
295
- separate bounded qualified-app proof. The default plugin build remains
296
- discovery-only.
297
- The candidate source reports Driver `0.23.2`; published Driver `0.23.2` does not
298
- include these branch changes. Switching Driver channels does not install or
299
- enable the plugin. Build and loading require the exact Hyprland ABI and compiler
300
- toolchain; v3 uses `CUA_HYPRLAND_INPUT=ON`, separate from the historical
301
- `CUA_HYPRLAND_TEST_INPUT` experiment.
302
-
303
- Driver admits each action through its normal shared permission, resource, and
304
- lifecycle policy. There is no additional Omarchy approval panel or external
305
- signer. The plugin accepts the trusted desktop account over same-user local
306
- sockets; this does not sandbox native code running as that user. Application
307
- qualification is a compatibility check, not authorization.
308
-
309
- The initial native qualification scope is Calc from `libreoffice-fresh 26.2.5-3`
310
- and Inkscape `1.4.4-6`, subject to per-operation native evidence. Before each
311
- action, Driver matches `/proc/<pid>/exe` to the canonical executable path
312
- (`/usr/lib/libreoffice/program/soffice.bin` or `/usr/bin/inkscape`), checks the
313
- exact package name and version in the local pacman database and its executable
314
- file listing, and rechecks process identity. Unknown or unavailable package
315
- identity refuses. Package eligibility does not certify every LibreOffice
316
- application or operation.
317
-
318
- The plugin separately binds the exact live native surface and checks geometry,
319
- desktop availability, and primary-client and other-lane conflicts. Each
320
- background lane publishes a private canonical `evdev`/`pc105`/`us` keymap, so
321
- user options such as Caps Lock remapped to Ctrl or Super do not alter agent key
322
- semantics. A physical keymap transition cancels existing authority; use a fresh
323
- action afterward. Multiple agent layout groups, Unicode, IME input, arbitrary
324
- held-key streams, and modified pointer gestures remain outside this scope.
325
- Chromium, Electron, and XWayland raw background input are outside this scope.
326
- AT-SPI routes retain their separate behavior.
327
-
328
- Two compositor seats, `Cua-Agent` and `Cua-Agent-2`, persist across configuration
329
- disable/re-enable. Each connection claims one lane, and each admitted action
330
- requires a fresh target binding. Plugin replacement requires a desktop restart;
331
- do not treat historical experiment reload workarounds as a supported lifecycle.
332
- Refusals never authorize a hidden foreground fallback, display wake, or session
333
- unlock. A dispatch acknowledgement is `effect:"unverifiable"`; verify the
334
- application effect from fresh state. Do not replay canceled, partial, or unknown
335
- actions.
336
-
337
- The candidate also adds an explicitly requested foreground route, advertised
338
- by the plugin as `foreground_target:true`. It binds the exact native top-level
339
- surface on the compositor thread and intentionally changes primary focus and,
340
- for pointer actions, cursor position. It does not restore the previous focus or
341
- cursor. This route has no Calc/Inkscape background package gate. The canonical
342
- native harness covers defined GTK3, Electron, and Tauri foreground cases. It refuses
343
- held physical input, grabs, constraints, drag-and-drop, ambiguous primary seat
344
- bindings, and non-neutral keyboard modifiers. Background refusal never selects
345
- this route automatically. Driver expands bounded ASCII text under the exact
346
- US keymap; Unicode and IME remain outside its raw-input scope. Foreground
347
- pointer-only actions are layout-independent. Foreground keyboard actions leave
348
- the user's Num Lock and Caps Lock untouched. They work with Num Lock on and with
349
- keymap options that leave every typing and modifier key unchanged, such as
350
- `compose:caps`. They refuse before any input under Caps Lock
351
- (`foreground_keyboard_caps_lock`), for a keypad key that Num Lock changes
352
- (`foreground_keyboard_numlock_keypad`), and for a different layout or remapped
353
- key (`foreground_unsupported_layout`). Ask the user to turn Caps Lock off, or
354
- use the equivalent non-keypad key, instead of retrying the same call.
355
-
356
- The retained bounded app evidence at source
357
- `f180e8828b8f31cc153e3c44eaa89a9c13c5bc68` includes instrumented Calc/Inkscape
358
- proof on both seats and an uninstrumented smoke. The plugin tree and
359
- uninstrumented module hash are unchanged at
360
- `1133a06e4f205cf80188a7ac9e41102f37611fea`. The proof covers recorded actions
361
- and observation intervals, not every application operation or release package.
362
- Portable tests and historical experiments do not replace complete native
363
- harness acceptance. Compatible release artifacts and final image
364
- packaging and lifecycle validation require separate evidence. Physical Omarchy
365
- parity requires separate acceptance; it is not a gate for publishing a validated
366
- image.
367
-
368
- ## Quick triage
369
-
370
- If a tool call surprises you on Linux:
371
-
372
- 1. `cua-driver doctor`: reports the display server (X11 / Wayland),
373
- **whether `org.a11y.Bus` actually answers on the session bus** (not just
374
- "is there a bus"), the discovered `DBUS_SESSION_BUS_ADDRESS`, and
375
- `ffmpeg` availability (for recording).
376
- 2. Check `XDG_SESSION_TYPE`: X11 still has toolkit-specific delivery limits; `wayland`
377
- needs `CUA_DRIVER_RS_ENABLE_WAYLAND=1` for the native backend,
378
- else XWayland.
379
- 3. **Empty AT-SPI tree** (`get_window_state` returns `degraded:true`): in
380
- order of likelihood: (a) the daemon isn't on the desktop session bus
381
- (headless / container / `runuser` / root-against-user-session; see
382
- _AT-SPI needs the session bus_ above; doctor will say
383
- `DBUS_SESSION_BUS_ADDRESS unset`); (b) the a11y bridge is off
384
- (`gsettings set org.gnome.desktop.interface toolkit-accessibility true`);
385
- (c) GTK4 / Qt6 / Chromium populate lazily: re-snapshot after an
386
- interaction or an AX-enable settle.
387
-
388
- ## Forbidden vectors
389
-
390
- Same idea as macOS / Windows: don't shell out to anything that
391
- foregrounds a target:
392
-
393
- - `wmctrl -a <window>` / `wmctrl -R <window>`: activates / raises.
394
- - `xdotool windowactivate <wid>`: activates.
395
- - `xdotool key --window <wid> alt+Tab`: focus churn.
396
-
397
- Prefer cua-driver tools with an explicit `window_id`. When in doubt,
398
- ask the user.
399
-
400
- ## What to expect
401
-
402
- | Environment | Proven baseline | Main limits |
403
- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
404
- | X11/Openbox | AT-SPI trees and actions, foreground pointer and keyboard input, window and desktop capture, and video | Raw background delivery remains toolkit-specific; unsupported shapes refuse |
405
- | Sway/wlroots | AT-SPI, native discovery, full-display and cropped-window screencopy, foreground input, semantic background actions, and video | Raw background pointer and keyboard input remains focus-bound |
406
- | Hyprland/Omarchy | Experimental source candidate with separate discovery-foundation and bounded two-seat app evidence | Default plugin is discovery-only; raw background v3 qualification is limited to the exact native Calc/Inkscape packages and a private agent US keymap; user Caps-to-Ctrl/Super remaps do not alter agent semantics; complete native harness and release acceptance are separate gates |
407
- | GNOME/Mutter | AT-SPI, WinRects geometry and activation, capture, and portal/libei foreground input | Requires the helper and portal grant; portal video parity remains open |
408
- | KDE/KWin | AT-SPI and generic discovery where exposed | Target-specific activation and behavioral coverage remain experimental |
409
- | Nested `cua-compositor` | Versioned direct per-surface input, native GTK 31/31, capture/scope 5/5, and partial Electron coverage | The complete shared matrix remains experimental; do not infer standard-Wayland support |
410
-
411
- See [WORKFLOW.md](WORKFLOW.md) for exact targeting and verification and `RECORDING.md` for session
412
- recording.