File size: 29,672 Bytes
6aa76ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
---
title: Computer Use
sidebar_position: 16
---

# Computer Use

Hermes Agent can drive your desktop β€” clicking, typing, scrolling,
dragging β€” in the **background** on **macOS, Windows, and Linux**. Your
cursor doesn't move, keyboard focus doesn't change, and your virtual
desktops / Spaces don't switch on you. You and the agent co-work on the
same machine.

Unlike most computer-use integrations, this works with **any tool-capable
model** β€” Claude, GPT, Gemini, or an open model on a local
OpenAI-compatible endpoint. There's no Anthropic-native schema to worry
about.

## How it works

The built-in `computer_use` toolset is the recommended Hermes integration. It
speaks MCP over stdio to
[`cua-driver`](https://github.com/trycua/cua), an open-source background
computer-use driver. Each platform uses the appropriate accessibility +
input stack under the hood:

| Platform | Accessibility tree | Input dispatch |
|---|---|---|
| macOS | AX (private SkyLight SPIs) | `SLPSPostEventRecordTo` β€” pid-scoped, no cursor warp |
| Windows | UIAutomation | `SendInput` + `PostMessage` β€” no focus steal |
| Linux | AT-SPI (X11 + Wayland) | XTest (X11) / virtual-keyboard (Wayland) |

The result is the same on every platform: the agent can read the
accessibility tree of any visible window AND post synthesized events
without bringing it to front, switching virtual desktops, or moving the
real OS cursor.

For the underlying contract β€” *why* background mode matters, the
no-foreground invariant, click-dispatch internals β€” see
**[cua.ai/docs/explanation/the-no-foreground-contract](https://cua.ai/docs/explanation/the-no-foreground-contract)**.

## Enabling

**Fresh installs already have the driver.** The Hermes installer
(`install.sh` / `install.ps1`) pre-installs `cua-driver` (best-effort;
pass `--skip-computer-use` / `-SkipComputerUse` to opt out), so enabling
Computer Use is just a config flip:

- **`hermes tools`** β†’ pick `πŸ–±οΈ  Computer Use` β€” installs the driver
  automatically if it's still missing.
- **Dashboard / desktop app** β†’ toggle the Computer Use toolset β€” if the
  driver is missing, the toggle kicks off the install in the background
  automatically (watch progress in the toolset panel).

**Manual fallback (older installs, skipped installer step):**

```
hermes computer-use install
```

This fetches and runs the upstream cua-driver installer β€” `install.sh`
on macOS/Linux, `install.ps1` on Windows. Use `hermes computer-use
status` to verify the install.

Already have cua-driver? Hermes reuses it when it supports the 0.20 runtime
contract. During setup, toolset enablement, `hermes update`, and the first
`computer_use` call of a session, Hermes checks the local version and
manifest. It repairs an old or incomplete standard installation through
the upstream installer (at most once per session at runtime). A binary
selected with `HERMES_CUA_DRIVER_CMD` stays
under your control, so Hermes reports the incompatibility and leaves it
unchanged.

If you install Cua Driver first, `cua-driver skills install` installs Cua's
skill pack under `~/.cua-driver/skills/cua-driver`. Hermes autodetection is a
planned cua-driver follow-up, so currently point Hermes at that directory or
symlink it into your skill space. You can also register raw Cua MCP tools as a
custom MCP server, but that is an alternative for users who need the low-level
interface. The built-in toolset provides Hermes actions, configuration,
approvals, and diagnostics.

After installing, regardless of which path you took, grant the
platform-appropriate prereqs:

| Platform | Prereqs |
|---|---|
| **macOS** | System Settings β†’ Privacy & Security β†’ **Accessibility** + **Screen Recording**. Grant the identity named by `hermes computer-use doctor`. Standard mode uses CuaDriver.app; bounded and unrestricted modes use the Hermes host identity. |
| **Windows** | None at install time. If you're driving over SSH (not RDP / console), you need the autostart pattern β€” see [cua.ai/docs/how-to-guides/driver/windows-ssh](https://cua.ai/docs/how-to-guides/driver/windows-ssh) for the Session 0 ↔ Session 1+ proxy. |
| **Linux** | A reachable display server: `DISPLAY` set for X11, or `XDG_SESSION_TYPE=wayland`. Wayland sessions need an XWayland bridge for capture. AT-SPI must be on (default on GNOME/KDE/Xfce). |

Then start a session with the toolset enabled:

```
hermes -t computer_use chat
```

or add `computer_use` to your enabled toolsets in `~/.hermes/config.yaml`.

## Permission modes and logged-in browser profiles

Hermes maps its existing approval UX onto cua-driver's immutable runtime
modes. Permission mode and capability manifest approval are launch settings.
They cannot change after the runtime starts:

| Hermes session | cua-driver mode | Human intervention |
|---|---|---|
| Manual or smart approvals (default) | `standard` | Normal Hermes approvals; Cua stops at its protected boundary |
| `computer_use.permission_mode: bounded` + reviewed manifest | private `bounded` daemon | You review and approve the capability manifest once, at launch |
| `--yolo`, `/yolo`, or `approvals.mode: off` | private `unrestricted` daemon | One explicit Hermes risk acceptance; no runtime Cua prompts |

Browser work β€” including pages in a signed-in profile β€” goes through the
`browser` toolset (`browser_exec`), not `computer_use`. The former
`computer_use.grant_existing_profile` opt-in was removed along with the typed
browser route; a leftover key in config.yaml is ignored.

### Bounded mode for repeatable automation

For recurring browser automation (cron jobs, scheduled research against an
authenticated app), `bounded` mode uses a capability manifest you review once:

```yaml
# config.yaml
computer_use:
  permission_mode: bounded
  capability_manifest: ~/.hermes/cua-manifest.yaml
```

The manifest names the apps, browser profile kinds, allowed origins, and
typed tools the session may use (see the
[cua-driver permission modes reference](https://cua.ai/docs/reference/cua-driver/permission-modes)
for the format). Hermes launches a private runtime with
`--capability-manifest ... --approve-capability-manifest`; anything outside
the manifest fails closed inside cua-driver. A missing or unreadable manifest
fails loudly at session start rather than silently downgrading. Session YOLO
still overrides bounded for that one session.

On macOS, private-session daemons launch through the installed
`CuaDriver.app` bundle (so permission grants attribute to the driver's own
identity instead of resetting with every Hermes build), and Hermes verifies
the bundle's code signature β€” exact `com.trycua.driver` identifier and the
official signing team β€” before launching it. If you build cua-driver from
source (unsigned), opt in explicitly:

```yaml
# config.yaml
computer_use:
  allow_unsigned_driver: true   # local driver development only
```

Each MCP transport owns a private lifecycle session inside its runtime. A
public session name is only a label for cursor identity and session-scoped
state. It does not select, share, or keep a runtime alive. Turning `/yolo` off,
resetting or closing the Hermes session, cancellation cleanup, or process exit
closes that transport session. Hermes also stops private runtimes that it
launched for bounded or unrestricted access. One Hermes
conversation cannot change another runtime's mode or grants. Bounded and
unrestricted modes use a private
embedded service under the Hermes host identity.

`smart` approval remains `standard`: an LLM classification cannot stand in for
a reviewed manifest.

<div class="alert alert--warning">

YOLO/unrestricted mode does not protect against prompt injection or unintended
input. Use it only in a disposable VM or with accounts and data whose full
compromise you accept.

</div>

## `hermes computer-use doctor` β€” your first triage stop

`hermes computer-use doctor` runs cua-driver's structured
`health_report` MCP tool and prints a per-check matrix. It's the single
fastest way to find out *why* an action isn't working.

```
$ hermes computer-use doctor
⚠️  cua-driver VERSION on darwin: degraded
  βœ… binary_version: cua-driver VERSION
  βœ… platform_supported: macOS 26.4.1 (arm64)
  βœ… session_active: MCP session is active.
  ❌ bundle_identity: Process has no CFBundleIdentifier.
      β†’ Run the binary inside CuaDriver.app so TCC grants attribute correctly.
  βœ… tcc_accessibility: Accessibility is granted.
  βœ… tcc_screen_recording: Screen Recording is granted.
  βœ… ax_capability: AX is trusted and reachable.
  βœ… screen_capture_capability: ScreenCaptureKit reachable; 1 display(s) shareable.
```

- **Exit code 0** when overall is `ok` β€” everything's wired up.
- **Exit code 1** when `degraded` or `failed` β€” at least one check failed; the hint on each failure tells you what to fix.
- **Exit code 2** when the cua-driver binary itself isn't reachable.

Useful flags:

- `--include CHECK` β€” run only the listed checks (repeat for multiple)
- `--skip CHECK` β€” skip a check (wins over `--include`)
- `--json` β€” emit the raw structured payload, same shape as the
  `tools/call health_report` MCP response

The check matrix is platform-aware: `bundle_identity` / `tcc_*` are
`skip` on Windows + Linux because those concepts don't apply.
`ax_capability` checks AX on macOS, UIA on Windows, AT-SPI on Linux β€”
each with the right diagnostic hint when it can't reach.

## The agent cursor and sessions

When the agent acts, you'll see a **tinted overlay cursor** glide
across the screen to where each click / type / scroll lands. The real
OS cursor never moves. The overlay shows where the agent is acting. Each
Hermes run declares a public cua-driver **session name** (something like
`hermes-3a7b9c14d2e8`). The name labels cursor identity and related state, so
concurrent runs and subagents get distinct cursors. The MCP transport owns the
private lifecycle session inside the runtime; the public name does not.

The overlay cursor is cosmetic β€” captures, clicks, and typing all work
without it. Hermes disables it automatically where it is a known failure
mode: macOS (idle CPU burn), headless Linux / WSL2 / containers, and
**Linux X11 desktops** (the overlay is a fullscreen always-on-top window
that can get stuck over every workspace after an unclean session end,
wedging desktop input). Linux Wayland and Windows keep the overlay. Set
`computer_use.no_overlay: false` in `config.yaml` to force the cursor on
(or `true` to force it off) on any platform.

Tune the cursor with `cua-driver`'s CLI flags or the runtime
`set_agent_cursor_style` MCP tool β€” see
[cua.ai/docs/how-to-guides/driver/personalize-cursor](https://cua.ai/docs/how-to-guides/driver/personalize-cursor)
for the full menu (built-in `arrow` vs `teardrop` silhouette, custom
SVG / PNG / ICO via `--cursor-icon`, runtime gradient colors, bloom
halo).

## Going deeper β€” the cua-driver skill pack

Hermes keeps its wrapper skill (`skills/autonomous-ai-agents/computer-use/SKILL.md`)
focused on the Hermes-side `computer_use` workflow and action vocabulary. For
platform details, recording semantics, browser page interaction, and other
deep Cua behavior, install the skill pack that the cua-driver team ships and
maintains directly:

```
cua-driver skills install
```

The command links the pack into `~/.hermes/skills/cua-driver` (Hermes is one
of the agents `cua-driver skills status` reports). The wrapper remains the
workflow layer: the pack documents the driver's own MCP vocabulary
(`get_window_state`, `element_token`, `snapshot_id`), which the `computer_use`
wrapper translates to for you β€” keep calling `computer_use(action=...)`. The
pack contains:

| File | Topic |
|---|---|
| `SKILL.md` | The cross-platform core (snapshot invariant, no-foreground contract, click dispatch, AX-tree mechanics) |
| `MACOS.md` | macOS specifics: no-foreground contract, AXMenuBar navigation, SkyLight click dispatch, Apple Events JS bridge |
| `WINDOWS.md` | Windows specifics: UIA tree, UWP / `ApplicationFrameHost` hosting, Session 0 isolation, autostart pattern |
| `LINUX.md` | Linux specifics: AT-SPI tree, X11 / Wayland, terminal-emulator detection |
| `RECORDING.md` | Trajectory + video recording semantics |
| `WEB_APPS.md` | Browser-page interaction tips |
| `TESTS.md` | Replay-by-trajectory workflow |

These are **platform deep dives, not duplicates of the Hermes skill** β€”
when an agent reports "on Windows, my click landed on the wrong
element," it reads `WINDOWS.md` for the UIA / UWP context that
explains why and what to do differently.

`cua-driver skills status` shows what's installed and which agent
harnesses it's linked into. Today the autodetect list covers Claude
Code, Codex, OpenCode, OpenClaw, and Antigravity; **Hermes
autodetection is planned as a follow-up in `trycua/cua`** β€” until
then, run `cua-driver skills install` once and point your harness at
the resulting `~/.cua-driver/skills/cua-driver` directory (or symlink
it into your usual skill space).

## Quick example

User prompt: *"Find my latest email from Stripe and summarise what they want me to do."*

The agent's plan (this is the same shape on macOS / Windows / Linux β€”
the model substitutes the platform's idiomatic shortcut and app name):

1. `computer_use(action="capture", mode="som", app="Mail")` β€” gets a
   screenshot of the email app with every sidebar item, toolbar button,
   and message row numbered.
2. `computer_use(action="click", element=14)` β€” clicks the search field.
3. `computer_use(action="type", text="from:stripe")`
4. `computer_use(action="key", keys="return", capture_after=True)` β€”
   submit and get the new screenshot.
5. Click the top result, read the body, summarise.

During all of this, your cursor stays wherever you left it and the email
app never comes to front.

## Receiving the actual screenshot

Screenshots taken during computer control are normally internal β€” they exist
so the model can see the screen, and the agent replies in text. But every
image capture also saves a bounded, shareable copy under Hermes' image cache
and reports its path, so on attachment-capable surfaces (Telegram, Discord,
Desktop, and other gateway platforms) you can simply ask:

> *"Send me a screenshot of my screen."*

and the agent delivers the real image as a native attachment, not just a
description. On the CLI there is no attachment channel, so the agent gives
you the saved file's path instead.

Only the 20 most recent capture files are kept, and screenshots are never
sent automatically β€” only when you ask for one.

### Whole screen vs. desktop surface

"Screenshot my screen" captures **everything currently displayed** β€” a
composited grab of all visible windows, like pressing PrtScn. This image has
no clickable elements, so to *act* on something in it the agent re-captures
the specific app.

Asking for the **desktop** instead targets the OS shell surface itself β€”
wallpaper, desktop icons, taskbar β€” with its clickable elements, so requests
like "open the Recycle Bin on my desktop" still work.

## Provider compatibility

| Provider | Vision? | Works? | Notes |
|---|---|---|---|
| Anthropic (Claude Sonnet/Opus 3+) | βœ… | βœ… | Best overall; SOM + raw coordinates. |
| OpenRouter (any vision model) | βœ… | βœ… | Multi-part tool messages supported. |
| OpenAI (GPT-4+, GPT-5) | βœ… | βœ… | Same as above. |
| Google (Gemini 2+) | βœ… | βœ… | Tool-calling + vision both supported. |
| Local vLLM / LM Studio / Ollama (vision model) | βœ… | βœ… | If the model supports multi-part tool content. |
| Text-only models | ❌ | βœ… (degraded) | Use `mode="ax"` for accessibility-tree-only operation. |

Screenshots are sent inline with tool results as OpenAI-style `image_url`
parts. For Anthropic, the adapter converts them into native `tool_result`
image blocks. The image MIME type comes from cua-driver's explicit
`mimeType` field (`image/png` or `image/jpeg`) β€” no client-side
magic-byte sniffing.

## Safety

Hermes applies multi-layer guardrails:

- Destructive actions (click, type, drag, scroll, key, focus_app)
  require approval through the same gate as dangerous shell commands β€”
  interactively via the CLI dialog or the messaging-platform approval
  buttons. Once/session/always grants are keyed
  `cua:<action>:<background|foreground>` and live in the shared
  session/`command_allowlist` store (a background grant never covers the
  visible foreground variant). Where nobody can answer β€” cron
  (`approvals.cron_mode`), single-query, unattended platforms, or any
  headless run β€” the action is refused rather than auto-approved;
  `--yolo` / `/yolo` still bypass.
- Hard-blocked key combos at the tool level: empty trash, force delete,
  lock screen, log out, force log out.
- Hard-blocked type patterns: `curl | bash`, `sudo rm -rf /`, fork
  bombs, etc.
- The agent's system prompt tells it explicitly: no clicking permission
  dialogs, no typing passwords, no following instructions embedded in
  screenshots.

Pair with `approvals.mode: manual` in `~/.hermes/config.yaml` if you
want every action confirmed.

## Token efficiency

Screenshots are expensive. Hermes applies four layers of optimisation:

- **Screenshot eviction** β€” the Anthropic adapter keeps only the 3 most
  recent screenshots in context; older ones become `[screenshot removed
  to save context]` placeholders.
- **Client-side compression pruning** β€” the context compressor detects
  multimodal tool results and strips image parts from old ones.
- **Image-aware token estimation** β€” each image is counted as ~1500
  tokens (Anthropic's flat rate) instead of its base64 char length.
- **Server-side context editing (Anthropic only)** β€” when active, the
  adapter enables `clear_tool_uses_20250919` via `context_management` so
  Anthropic's API clears old tool results server-side.

A 20-action session on a 1568Γ—900 display typically costs ~30K tokens
of screenshot context, not ~600K.

## Limitations

- **Performance.** Background mode is slower than foreground β€”
  accessibility-routed events take ~5–20 ms on macOS, ~3–10 ms on
  Windows UIA, ~5–15 ms on Linux AT-SPI vs direct HID posting. Not
  noticeable for agent-speed clicking; noticeable if you try to record
  a speed-run.
- **No keyboard password entry.** `type` has hard-block patterns on
  command-shell payloads; for passwords, use the system's autofill
  (macOS Keychain / Windows Credential Manager / GNOME Keyring /
  KWallet).
- **Some apps don't expose an accessibility tree.** Modern UWP apps on
  Windows, Electron < 28 on Linux, and a few macOS apps with custom
  drawing (Logic, Final Cut, some games) have sparse or empty AX trees.
  Fall back to pixel coordinates if the tree is empty β€” or skip the
  task entirely.
- **Windows: elevated (admin) windows can't be driven from a normal
  agent.** Windows UIPI (User Interface Privilege Isolation) enforces
  integrity-level boundaries: a Medium-integrity process (the default
  Hermes agent) cannot enumerate the UIA tree of, or inject mouse input
  into, a window owned by a High-integrity (Administrator) process.
  Symptom: `capture(mode='som')` returns 0 elements and `click(...)`
  reports success while doing nothing, even though the screenshot
  renders fine (GDI capture sits below the integrity check). Keyboard
  events partially bypass UIPI, so Tab / Enter can still navigate an
  elevated dialog. This is an OS constraint, not a cua-driver bug β€” it
  affects every Windows automation stack. To drive elevated windows,
  run the Hermes agent itself at High integrity (launch from an
  elevated terminal); otherwise target non-elevated windows.
- **Windows: `hermes computer-use doctor` fails with "Access is denied"
  while the tool works.** A cua-driver installed under
  `C:\Program Files\WindowsApps` cannot be executed by the Hermes venv
  interpreter (WinError 5 from `CreateProcess`), even though the shell
  resolves the same binary fine. The doctor now reports this as a
  diagnosis instead of a traceback. Fix once: reinstall with the upstream
  installer (lands under your user profile) or set
  `HERMES_CUA_DRIVER_CMD` to a copy outside `WindowsApps`.
- **Platform-specific deployment gotchas:**
  - **macOS** uses private SkyLight SPIs. Apple can change them in any
    OS update. Hermes warns when the installed cua-driver is older than
    the version it was tested against.
  - **Windows** SSH sessions run in **Session 0**, which has no
    interactive desktop. Drive Hermes from inside the RDP / console
    session, or set up cua-driver's autostart Scheduled Task β€”
    [windows-ssh](https://cua.ai/docs/how-to-guides/driver/windows-ssh)
    has the recipe.
  - **Linux** requires a reachable display server. Headless servers
    need Xvfb (`Xvfb :99 -screen 0 1920x1080x24`) before
    `computer_use` can capture or inject events. Pure Wayland sessions
    need an XWayland bridge for screen capture (cua-driver's Wayland
    inject path handles input independently).

For cross-platform GUI automation without the desktop overhead (and
without TCC / Session 0 / X11 setup), the `browser` toolset uses a
real headless Chromium and is the right answer for web-only tasks.

## Configuration

Permission mode and manifest (see
[Permission modes](#permission-modes-and-logged-in-browser-profiles) above):

```yaml
computer_use:
  permission_mode: standard        # standard (default) | bounded
  capability_manifest: ""          # capability manifest path, required for bounded
```

On Linux, native Wayland support remains an explicit opt-in. Hermes passes the
opt-in to every cua-driver process, including gateway sessions, only when that
process also has `WAYLAND_DISPLAY`:

```yaml
computer_use:
  native_wayland: true
```

Restart a running gateway after changing this setting.

Override the driver binary path (tests / CI / local builds):

```
HERMES_CUA_DRIVER_CMD=/path/to/your/cua-driver
```

Swap the backend entirely (for testing):

```
HERMES_COMPUTER_USE_BACKEND=noop   # records calls, no side effects
```

### Telemetry

cua-driver ships with anonymous usage telemetry (PostHog) enabled by default
upstream. **Hermes disables it for you** β€” on every cua-driver invocation
(the MCP backend, `status`, `doctor`, and install) Hermes sets
`CUA_DRIVER_RS_TELEMETRY_ENABLED=0` in the driver's environment.

To opt back in (let cua-driver use its own default and send telemetry), set
this in `config.yaml`:

```yaml
computer_use:
  cua_telemetry: true   # default: false (telemetry off)
```

When it's on, `hermes computer-use doctor` reports `telemetry: enabled`;
when off (the default), it reports `telemetry: disabled via
CUA_DRIVER_RS_TELEMETRY_ENABLED`.

## Testing against a local cua-driver build

When you're developing cua-driver itself β€” or want to test an
unreleased fix β€” point Hermes at a binary you built from source instead
of the published release. Hermes resolves the driver with
`shutil.which("cua-driver")` and **does not enforce
`HERMES_CUA_DRIVER_VERSION`**, so a local build (reported as
`0.0.0-local-*`) is accepted as-is. Two approaches:

### Option A β€” `install-local` (build + put it on PATH)

From your `trycua/cua` checkout, run the upstream local installer. It
builds the Rust backend in release mode and drops `cua-driver` into the
same install layout the production installer uses, adding its bin dir
to your PATH:

```powershell
# Windows (PowerShell), from the cua repo root
./libs/cua-driver/scripts/install-local.ps1 -NoAutoStart
```

```bash
# macOS / Linux, from the cua repo root  (defaults to a debug build without --release)
./libs/cua-driver/scripts/install-local.sh --release
```

- Windows stages the build under `%USERPROFILE%\.cua-driver\packages\…`
  and junctions
  `%LOCALAPPDATA%\Programs\Cua\cua-driver\bin` (added to your User
  PATH) to it. macOS/Linux symlinks `cua-driver` into `~/.local/bin`
  (override with `--bin-dir <path>`).
- `-NoAutoStart` skips registering the `cua-driver-serve` logon daemon
  β€” you don't need it for Hermes testing (see notes).

Then open a fresh shell (so the PATH change is visible) and confirm:

```
cua-driver --version                 # local builds report 0.0.0-local-release
# Windows:      (Get-Command cua-driver).Source
# macOS/Linux:  which cua-driver
```

### Option B β€” point Hermes straight at the built binary (fastest loop)

Skip the install ceremony entirely: `cargo build` and set
`HERMES_CUA_DRIVER_CMD` to the resulting binary. Best for rapid
edit/build/test.

```bash
cargo build -p cua-driver            # add --release for a release build; run from libs/cua-driver/rust
```

```
# Windows (.env)
HERMES_CUA_DRIVER_CMD=C:\path\to\cua\libs\cua-driver\rust\target\debug\cua-driver.exe
# macOS / Linux (.env)
HERMES_CUA_DRIVER_CMD=/path/to/cua/libs/cua-driver/rust/target/debug/cua-driver
```

### Confirm Hermes is using your build

- `hermes computer-use status` prints the resolved binary path and
  version.
- `hermes computer-use doctor` confirms the binary is reachable and
  exercises the full MCP path end-to-end.
- In a session, `computer_use(action="capture")` exercises the spawned
  `cua-driver mcp` child process.

### Notes & gotchas

- **Hermes spawns a `cua-driver mcp` stdio proxy.** In a normal session the
  proxy connects to (and may start) the standard machine daemon. In explicit
  Hermes YOLO, Hermes instead owns a private `cua-driver serve --embedded`
  child and points the proxy at its private socket or named pipe. The Windows
  autostart/UIAccess pattern still matters for interactive Session 1+ input
  from SSH β€” see the Limitations section.
- **Locked binary on Windows.** A running `cua-driver-serve` daemon can
  hold `cua-driver.exe` and block an overwrite on rebuild.
  `install-local.ps1` renames the locked binary out of the way
  automatically; if you `cargo build` manually (Option B), stop it
  first with `cua-driver autostart disable` (or `schtasks /End /TN
  cua-driver-serve`).
- **Rebuild loop.** After editing cua-driver source, re-run
  `install-local` (rebuilds, restages, flips the `current` junction)
  for Option A, or just re-`cargo build` for Option B β€” no Hermes
  change needed either way.
- **Local builds skip the version check.** Hermes warns when the
  installed cua-driver is older than its per-OS tested baseline, but
  exempts `0.0.0-local-*` dev builds β€” so your local build never
  triggers that warning.

## Troubleshooting

**First action when anything's off: run `hermes computer-use doctor`.**
The structured per-check matrix tells you (and any agent helping you
debug) exactly what's wrong.

Specific failure modes the doctor doesn't catch:

**`computer_use backend unavailable: cua-driver is not installed`** β€”
Run `hermes computer-use install` to fetch the cua-driver binary, or
run `hermes tools` and enable the Computer Use toolset.

**Clicks seem to have no effect** β€” Capture and verify. A modal you
didn't see may be blocking input. Dismiss it with `escape` or the close
button.

**Element indices are stale** β€” SOM indices are only valid until the
next `capture`. Re-capture after any state-changing action. The
wrapper carries opaque `element_token`s for stale detection β€” you'll
see an explicit error rather than a wrong click.

**"blocked pattern in type text"** β€” The text you tried to `type`
matches the dangerous-shell-pattern list. Break the command up or
reconsider.

**Empty captures on Linux** β€” `DISPLAY` not set, or you're on pure
Wayland without an XWayland bridge. `hermes computer-use doctor` will
flag this as `ax_capability: fail` with a `Set DISPLAY (X11)…` hint.

**Empty captures on Windows over SSH** β€” You're in Session 0 (the
services session). Drive from RDP / console directly, or set up the
autostart pattern β€” see
[cua.ai/docs/how-to-guides/driver/windows-ssh](https://cua.ai/docs/how-to-guides/driver/windows-ssh).

## See also

- **Hermes-side skill** β€” `skills/autonomous-ai-agents/computer-use/SKILL.md` β€” teaches the
  Hermes `computer_use` action vocabulary; this is what the agent loads.
- **cua-driver skill pack** β€” for platform-specific deep dives
  (macOS no-foreground contract, Windows UIA + Session 0, Linux AT-SPI
  + X11/Wayland, recording, browser pages), run
  `cua-driver skills install` and read `MACOS.md` / `WINDOWS.md` /
  `LINUX.md` / `RECORDING.md` / `WEB_APPS.md`. Hermes autodetection is a
  planned follow-up; currently point Hermes at the installed pack directory
  or symlink it into your skill space.
- **cua.ai/docs** β€” the cua-driver project's documentation:
  - [What is computer use?](https://cua.ai/docs/explanation/what-is-computer-use) β€” concept intro
  - [The no-foreground contract](https://cua.ai/docs/explanation/the-no-foreground-contract) β€” *why* background mode matters
  - [Install reference](https://cua.ai/docs/how-to-guides/driver/install) β€” cross-platform install details
  - [Personalize the agent cursor](https://cua.ai/docs/how-to-guides/driver/personalize-cursor) β€” built-in shapes, custom assets, runtime overrides
  - [Drive Windows over SSH](https://cua.ai/docs/how-to-guides/driver/windows-ssh) β€” the Session 0 β†’ Session 1+ autostart pattern
  - [Keep cua-driver running](https://cua.ai/docs/how-to-guides/driver/keep-running) β€” autostart / daemon lifecycle
  - [Connect your agent](https://cua.ai/docs/how-to-guides/driver/connect-your-agent) β€” register cua-driver with various harnesses (Hermes among them)
- [cua-driver source (trycua/cua)](https://github.com/trycua/cua)
- [Browser automation](./browser.md) for cross-platform web tasks where you don't need to drive native apps.