nexus-windows-claude 3.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. nexus_windows_claude-3.0.1/PKG-INFO +508 -0
  2. nexus_windows_claude-3.0.1/README.md +477 -0
  3. nexus_windows_claude-3.0.1/pyproject.toml +107 -0
  4. nexus_windows_claude-3.0.1/pyproject.toml.orig +80 -0
  5. nexus_windows_claude-3.0.1/src/nexus_windows/__init__.py +3 -0
  6. nexus_windows_claude-3.0.1/src/nexus_windows/__main__.py +3 -0
  7. nexus_windows_claude-3.0.1/src/nexus_windows/act_base.py +809 -0
  8. nexus_windows_claude-3.0.1/src/nexus_windows/act_chromium.py +487 -0
  9. nexus_windows_claude-3.0.1/src/nexus_windows/act_confirm.py +361 -0
  10. nexus_windows_claude-3.0.1/src/nexus_windows/act_pointer.py +482 -0
  11. nexus_windows_claude-3.0.1/src/nexus_windows/act_uia.py +858 -0
  12. nexus_windows_claude-3.0.1/src/nexus_windows/act_wait.py +71 -0
  13. nexus_windows_claude-3.0.1/src/nexus_windows/act_win32.py +311 -0
  14. nexus_windows_claude-3.0.1/src/nexus_windows/actions.py +74 -0
  15. nexus_windows_claude-3.0.1/src/nexus_windows/agentlock.py +186 -0
  16. nexus_windows_claude-3.0.1/src/nexus_windows/assets/logo.png +0 -0
  17. nexus_windows_claude-3.0.1/src/nexus_windows/capture.py +308 -0
  18. nexus_windows_claude-3.0.1/src/nexus_windows/cdp.py +444 -0
  19. nexus_windows_claude-3.0.1/src/nexus_windows/codeprint.py +52 -0
  20. nexus_windows_claude-3.0.1/src/nexus_windows/foreground.py +694 -0
  21. nexus_windows_claude-3.0.1/src/nexus_windows/freshness.py +61 -0
  22. nexus_windows_claude-3.0.1/src/nexus_windows/indicator.py +379 -0
  23. nexus_windows_claude-3.0.1/src/nexus_windows/journal.py +80 -0
  24. nexus_windows_claude-3.0.1/src/nexus_windows/keys.py +153 -0
  25. nexus_windows_claude-3.0.1/src/nexus_windows/launch.py +1292 -0
  26. nexus_windows_claude-3.0.1/src/nexus_windows/log.py +160 -0
  27. nexus_windows_claude-3.0.1/src/nexus_windows/methods.py +1072 -0
  28. nexus_windows_claude-3.0.1/src/nexus_windows/notifications.py +124 -0
  29. nexus_windows_claude-3.0.1/src/nexus_windows/ocr.py +89 -0
  30. nexus_windows_claude-3.0.1/src/nexus_windows/offwindows.py +94 -0
  31. nexus_windows_claude-3.0.1/src/nexus_windows/packages.py +118 -0
  32. nexus_windows_claude-3.0.1/src/nexus_windows/physical.py +165 -0
  33. nexus_windows_claude-3.0.1/src/nexus_windows/policy.py +224 -0
  34. nexus_windows_claude-3.0.1/src/nexus_windows/postcond.py +168 -0
  35. nexus_windows_claude-3.0.1/src/nexus_windows/py.typed +0 -0
  36. nexus_windows_claude-3.0.1/src/nexus_windows/realinput.py +348 -0
  37. nexus_windows_claude-3.0.1/src/nexus_windows/reloader.py +454 -0
  38. nexus_windows_claude-3.0.1/src/nexus_windows/routines.py +446 -0
  39. nexus_windows_claude-3.0.1/src/nexus_windows/server.py +1504 -0
  40. nexus_windows_claude-3.0.1/src/nexus_windows/session.py +304 -0
  41. nexus_windows_claude-3.0.1/src/nexus_windows/shared/garde-fous.json +176 -0
  42. nexus_windows_claude-3.0.1/src/nexus_windows/shared/garde_fous.py +448 -0
  43. nexus_windows_claude-3.0.1/src/nexus_windows/snapshot.py +1249 -0
  44. nexus_windows_claude-3.0.1/src/nexus_windows/steam.py +168 -0
  45. nexus_windows_claude-3.0.1/src/nexus_windows/stop.py +249 -0
  46. nexus_windows_claude-3.0.1/src/nexus_windows/uia.py +423 -0
  47. nexus_windows_claude-3.0.1/src/nexus_windows/wgc_helper.py +63 -0
  48. nexus_windows_claude-3.0.1/src/nexus_windows/win32.py +778 -0
  49. nexus_windows_claude-3.0.1/src/nexus_windows/worker.py +107 -0
@@ -0,0 +1,508 @@
1
+ Metadata-Version: 2.4
2
+ Name: nexus-windows-claude
3
+ Version: 3.0.1
4
+ Summary: Background Windows desktop control for Claude: an MCP server that sees and acts without taking the user's mouse, keyboard or foreground
5
+ Keywords: mcp,mcp-server,windows,computer-use,ui-automation,desktop-automation,claude
6
+ Author: Julien Piron
7
+ License-Expression: MIT
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: Microsoft :: Windows
11
+ Classifier: Programming Language :: Python :: 3.14
12
+ Classifier: Topic :: Desktop Environment
13
+ Requires-Dist: comtypes>=1.4.17 ; sys_platform == 'win32'
14
+ Requires-Dist: mcp>=2.3.0
15
+ Requires-Dist: pillow>=13.0.0
16
+ Requires-Dist: websockets>=17.2
17
+ Requires-Dist: windows-capture>=2.0.1 ; sys_platform == 'win32'
18
+ Requires-Dist: winrt-runtime>=3.2.1 ; sys_platform == 'win32'
19
+ Requires-Dist: winrt-windows-foundation>=3.2.1 ; sys_platform == 'win32'
20
+ Requires-Dist: winrt-windows-foundation-collections>=3.2.1 ; sys_platform == 'win32'
21
+ Requires-Dist: winrt-windows-globalization>=3.2.1 ; sys_platform == 'win32'
22
+ Requires-Dist: winrt-windows-graphics-imaging>=3.2.1 ; sys_platform == 'win32'
23
+ Requires-Dist: winrt-windows-media-ocr>=3.2.1 ; sys_platform == 'win32'
24
+ Requires-Dist: winrt-windows-storage-streams>=3.2.1 ; sys_platform == 'win32'
25
+ Requires-Python: >=3.14
26
+ Project-URL: Homepage, https://julienpiron.fr/nexuswindows/claude/
27
+ Project-URL: Repository, https://github.com/pironjulien/NexusWindows-Claude
28
+ Project-URL: Changelog, https://github.com/pironjulien/NexusWindows-Claude/blob/main/CHANGELOG.md
29
+ Project-URL: Issues, https://github.com/pironjulien/NexusWindows-Claude/issues
30
+ Description-Content-Type: text/markdown
31
+
32
+ # NexusWindows for Claude
33
+
34
+ <!-- mcp-name: io.github.pironjulien/nexus-windows-claude -->
35
+
36
+ [![Release](https://img.shields.io/github/v/release/pironjulien/NexusWindows-Claude)](https://github.com/pironjulien/NexusWindows-Claude/releases)
37
+ [![PyPI](https://img.shields.io/pypi/v/nexus-windows-claude)](https://pypi.org/project/nexus-windows-claude/)
38
+ [![Tests](https://github.com/pironjulien/NexusWindows-Claude/actions/workflows/tests.yml/badge.svg)](https://github.com/pironjulien/NexusWindows-Claude/actions/workflows/tests.yml)
39
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/pironjulien/NexusWindows-Claude/badge)](https://scorecard.dev/viewer/?uri=github.com/pironjulien/NexusWindows-Claude)
40
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://github.com/pironjulien/NexusWindows-Claude/blob/main/LICENSE)
41
+ [![Python 3.14](https://img.shields.io/badge/python-3.14-blue?logo=python&logoColor=white)](https://github.com/pironjulien/NexusWindows-Claude/blob/main/pyproject.toml)
42
+ [![MCP](https://img.shields.io/badge/MCP-server-7ee2a8)](https://modelcontextprotocol.io)
43
+ [![Windows 10/11](https://img.shields.io/badge/Windows-10%20%7C%2011-0078D4)](#installation)
44
+
45
+ [![NexusWindows: Windows computer use for AI agents, in the background. Works with Claude, Codex and Antigravity.](https://raw.githubusercontent.com/pironjulien/NexusWindows-Claude/main/docs/assets/banner.webp)](https://julienpiron.fr/nexuswindows/)
46
+
47
+ ![NexusWindows: an AI agent fills and submits a form in a window that stays behind another one, then reports five verified steps](https://raw.githubusercontent.com/pironjulien/NexusWindows-Claude/main/docs/assets/demo.webp)
48
+
49
+ **Windows computer use for Claude, in the background.** An MCP server (`nexus-windows-claude`) that lets Claude Desktop
50
+ and Claude Code see and operate Windows desktop applications while the user keeps their mouse, keyboard and
51
+ foreground window.
52
+
53
+ Version 3.0.1 · Windows 10/11 · Python 3.14 · MIT licence
54
+
55
+ Part of the Nexus family: [NexusWindows](https://julienpiron.fr/nexuswindows/)
56
+ ([Claude](https://github.com/pironjulien/NexusWindows-Claude) ·
57
+ [Codex](https://github.com/pironjulien/NexusWindows-Codex) ·
58
+ [Antigravity](https://github.com/pironjulien/NexusWindows-Antigravity)),
59
+ [NexusBrowser](https://julienpiron.fr/nexusbrowser/) ([repo](https://github.com/pironjulien/NexusBrowser)),
60
+ [NexusAndroid](https://julienpiron.fr/nexusandroid/) ([repo](https://github.com/pironjulien/NexusAndroid)).
61
+ Project page: [julienpiron.fr/nexuswindows](https://julienpiron.fr/nexuswindows/).
62
+
63
+ ## Why
64
+
65
+ Anthropic's own computer use (in Cowork and Claude Code inside Claude Desktop) is a beta for Pro and Max
66
+ subscribers: "Team and Enterprise plans don't have access to computer use at this time"
67
+ ([Claude Help Center](https://support.claude.com/en/articles/14128542-let-claude-use-your-computer-in-cowork)).
68
+ NexusWindows for Claude is a local MCP server, so it works with Claude Desktop and Claude Code on any plan that
69
+ allows local MCP servers, Team and Enterprise included.
70
+
71
+ Screenshot-and-click computer use moves the real cursor and brings windows to the front, so the person at the PC has
72
+ to stop working while the agent acts. Most Windows applications can be driven without that: native controls accept
73
+ window messages, modern frameworks expose UI Automation, and Chromium can be reached through its accessibility tree.
74
+ This server picks, per UI family, a technique that was **measured** not to steal focus, reads the effect back, and
75
+ only falls back to the real mouse or keyboard when the user explicitly allows it.
76
+
77
+ ## NexusWindows family
78
+
79
+ Three MCP servers, one per agent, built separately because each model needs its tools shaped for it, with the same
80
+ promise: the user keeps their mouse, keyboard and foreground window, and every action is read back.
81
+
82
+ | | Claude | Codex | Antigravity |
83
+ |---|---|---|---|
84
+ | Install | `uvx --python 3.14 nexus-windows-claude` | `npx -y nexus-windows-codex` | `uvx --python 3.14 nexus-windows-antigravity` |
85
+ | Package | [PyPI](https://pypi.org/project/nexus-windows-claude/) | [npm](https://www.npmjs.com/package/nexus-windows-codex) | [PyPI](https://pypi.org/project/nexus-windows-antigravity/) |
86
+ | Tools | `windows` `look` `act` `launch` `window`, plus `notifications` and `logs` | `windows` `look` `act` `launch` `window` | `windows` `look` `act` `launch` `window` |
87
+ | Repository | [NexusWindows-Claude](https://github.com/pironjulien/NexusWindows-Claude) | [NexusWindows-Codex](https://github.com/pironjulien/NexusWindows-Codex) | [NexusWindows-Antigravity](https://github.com/pironjulien/NexusWindows-Antigravity) |
88
+
89
+ Every step reports ✓ verified, = already done, ~ unknown (never replayed) or ✗ failed or refused. The three share the
90
+ guardrail policy, the foreground token, the emergency stop (Ctrl+Alt+Shift+Esc), a common journal format and a common
91
+ bench.
92
+
93
+ ## Installation
94
+
95
+ Requirements: Windows 10 or 11, [uv](https://docs.astral.sh/uv/), Python 3.14.
96
+
97
+ From [PyPI](https://pypi.org/project/nexus-windows-claude/), with Claude Code (no clone needed):
98
+
99
+ ```powershell
100
+ claude mcp add --scope user -e PYTHONUTF8=1 --transport stdio nexus-windows -- uvx --python 3.14 nexus-windows-claude
101
+ ```
102
+
103
+ Until 3.0.0 the package was named `nexus-windows`; that name still works and installs `nexus-windows-claude`.
104
+
105
+ For Claude Desktop, in `claude_desktop_config.json`:
106
+
107
+ ```json
108
+ {
109
+ "mcpServers": {
110
+ "nexus-windows": {
111
+ "command": "uvx",
112
+ "args": ["--python", "3.14", "nexus-windows-claude"],
113
+ "env": { "PYTHONUTF8": "1" }
114
+ }
115
+ }
116
+ }
117
+ ```
118
+
119
+ From a clone (development):
120
+
121
+ ```powershell
122
+ git clone https://github.com/pironjulien/NexusWindows-Claude.git
123
+ cd NexusWindows-Claude
124
+ $env:UV_PROJECT_ENVIRONMENT = "$env:LOCALAPPDATA\claude-windows-computer-use\venv" # optional: venv outside the clone
125
+ uv sync --frozen
126
+ ```
127
+
128
+ Register it with Claude Code (user scope):
129
+
130
+ ```powershell
131
+ claude mcp add --scope user `
132
+ -e "UV_PROJECT_ENVIRONMENT=$env:LOCALAPPDATA\claude-windows-computer-use\venv" -e PYTHONUTF8=1 `
133
+ --transport stdio nexus-windows '--' uv run --project "$PWD" --frozen python -m nexus_windows
134
+ ```
135
+
136
+ For Claude Desktop from a clone:
137
+
138
+ ```json
139
+ {
140
+ "mcpServers": {
141
+ "nexus-windows": {
142
+ "command": "uv",
143
+ "args": ["run", "--project", "C:/path/to/NexusWindows-Claude", "--frozen", "python", "-m", "nexus_windows"],
144
+ "env": { "PYTHONUTF8": "1" }
145
+ }
146
+ }
147
+ }
148
+ ```
149
+
150
+ Local state (logs, routines) lives in `%USERPROFILE%\.claude\nexus-claude\`; set
151
+ `NEXUS_WINDOWS_HOME` to use another folder.
152
+
153
+ ## Tools
154
+
155
+ | Tool | Purpose |
156
+ |---|---|
157
+ | `windows(filter)` | Application windows, front to back: hwnd, title, process, UI family, size; `[hidden]` Store apps launched in the background (never shown, still drivable); then the taskbar and the desktop |
158
+ | `look(window, show, query, region, detail, marks)` | Numbered `[N]` elements (role, name, value, state, position) plus an image, without bringing the window forward; also `window="taskbar"`, `"desktop"`, and `"screen"` (the whole screen with each window's place) |
159
+ | `act(steps, window, then, foreground, remember, routine, params)` | Several steps in one call, each read back, then the updated state; Windows panels `"quick settings"`, `"notifications"`, `"start"` with `foreground=true` |
160
+ | `launch(app, args, devtools, restart)` | Start an application (Start menu name, Store app, executable), a folder, a document or an address (`ms-settings:<page>`, `mailto:`, `https:`) without giving it focus; the opening is verified |
161
+ | `window(action, ...)` | Restore behind, minimize, maximize, close, move, resize |
162
+ | `notifications(limit, app)` | Windows notifications read from their database (read-only), nothing opened on screen; security codes masked |
163
+ | `logs(count, errors_only)` | Debug log: techniques tried, durations, errors, server state |
164
+
165
+ Step actions: `click`, `double_click`, `right_click`, `type`, `set`, `clear`, `key`, `select`, `check`, `uncheck`,
166
+ `toggle`, `expand`, `collapse`, `scroll`, `focus`, `menu`, `wait`, `drag`, `hover`. A target is an `[N]` from the last
167
+ `look`, a visible name (`"OK"`), a role-qualified name (`"button:OK"`, `"edit:Name"`, `"checkbox:Subscribe"`) or an
168
+ `x,y` point in the last image.
169
+
170
+ ## Usage
171
+
172
+ Typical flow: `look(window="Notepad")`, then one `act` with all the steps, then read the per-step report.
173
+
174
+ ```text
175
+ act(window="Settings form", steps=[
176
+ {"do": "set", "target": "edit:Name", "text": "Ada",
177
+ "check": {"target": "Name", "value": "Ada"}},
178
+ {"do": "check", "target": "Subscribe"},
179
+ {"do": "click", "target": "button:Save", "expect": "Saved"}
180
+ ], remember="save-form")
181
+ ```
182
+
183
+ Later: `act(window="Settings form", routine="save-form")`.
184
+
185
+ ## What it does
186
+
187
+ ### Only what changed (`then="changes"`, `show="changes"`)
188
+
189
+ After an action, `act(then="changes")` (or `look(show="changes")`) returns only what changed since the last list
190
+ shown for that window: `+` added, `~` changed (text, state or moved), `-` removed; every other element keeps its
191
+ `[N]`. A common scroll of many elements is one line naming them as ranges (`[2-21]`), not a full list. Comparison is
192
+ made in the window's own frame, so moving the window is not a change. A removed `[N]` is never given again, and an
193
+ element whose change was cut from a long report loses its `[N]` until the next `look`. When almost everything changed
194
+ (60 %), the full list is returned. Measured: 2 to 2.6 times shorter than the full list after a click.
195
+
196
+ ### Text read from the image (OCR fallback)
197
+
198
+ When a window publishes almost no UI Automation elements (fewer than 6: Tk, canvases) or a Chromium page stops
199
+ publishing its content, the text of the window image is read with the Windows built-in OCR engine
200
+ (`Windows.Media.Ocr`, local, offline) and listed as `[N] Text "…" (OCR)` with its position; such an element can be
201
+ targeted by number or by name (click at its position, recomputed if the window moved). Measured on the lab apps: 10 to
202
+ 21 ms per window; text correct 16/16 (WPF), 20/23 (Edge), 6/7 (Tk).
203
+
204
+ ### Four outcomes per step
205
+
206
+ Each step is reported as one of:
207
+
208
+ - `✓` the effect was read back (value, state, window, image);
209
+ - `=` the state requested by the step's `check` was already true, so nothing was sent;
210
+ - `~` the input was sent but its effect could not be read (never counted as a success);
211
+ - `✗` failure, refusal, or postcondition not met; the batch stops there.
212
+
213
+ A batch ends with a tally of the four counts.
214
+
215
+ ### Postconditions (`check`)
216
+
217
+ A step may carry `check`: one element and the state it must reach (`value`, `contains`, `checked`, `selected`,
218
+ `expanded`, `focused`, `enabled`, `exists`). Already true before the step: the step is skipped (`=`). True after: `✓`.
219
+ False after: `✗` and the batch stops. A state the element does not publish stays unknown, never false.
220
+
221
+ ### Routines
222
+
223
+ `act(remember="name")` saves a batch only if every step ended `✓` or `=` and every target is a visible name (never an
224
+ `[N]` or a point). `{{x}}` marks variable text, filled at replay with `params`. `act(routine="name")` finds each
225
+ target again by name and re-verifies every step; an application update is reported and a failed replay marks the
226
+ routine for review. Routines are stored per executable under `%USERPROFILE%\.claude\nexus-claude\routines`. An
227
+ optional mirror folder (`NEXUS_ROUTINES_MIRROR`) can share definitions between PCs; typed text is never mirrored in
228
+ clear (a routine whose text is not a `{{x}}` template stays local).
229
+
230
+ ### Verified opening of paths
231
+
232
+ `launch(app=<folder or document>)` opens through the file association (ShellExecuteEx, no activation requested), then
233
+ checks what actually opened: the folder shown in File Explorer (read through Shell.Application) or a window titled
234
+ with the file name. Scripts, shortcuts and installers are refused.
235
+
236
+ ### Per UI family
237
+
238
+ - **Native Win32**: direct messages to controls (`BN_CLICKED`, `CB_SETCURSEL`/`LB_SETCURSEL` with their notification,
239
+ `EM_REPLACESEL`, menu `WM_COMMAND`, `TCM_SETCURFOCUS`), read back. UI Automation is avoided where it was measured to
240
+ steal focus (button Invoke) or to fail silently (list Select).
241
+ - **Win32 and WinForms drop-down lists**: opened and closed with `CB_SHOWDROPDOWN`, read back with
242
+ `CB_GETDROPPEDSTATE` (`expand`, `collapse`, or `click` on the list). Choosing in an open list closes it first
243
+ (Windows treats that close as a cancel and would drop a choice made before it), then sends `CB_SETCURSEL`,
244
+ `CBN_SELCHANGE` and `CBN_SELENDOK` to the parent and reads the application back (index and label); an empty or other
245
+ value is `✗`. While a list is open its UI Automation tree is not walked (it chains to every top-level window of the
246
+ desktop): the options are read from the ComboLBox pop-up itself.
247
+ - **WinForms, WPF, UWP, WinUI**: UI Automation with `AutoSetFocus` disabled and bounded timeouts. A WPF drop-down list
248
+ left open by a choice is closed and the choice read back.
249
+ - **Chromium and Electron, without activation**: for an app already open without DevTools, multiline fields, rich
250
+ editors, `<select>`, keys and Ctrl/Alt shortcuts go through a *simulated activation*: `WM_NCACTIVATE` and
251
+ `WM_ACTIVATE` are sent to that window only (Chromium takes its activation state from these messages; Windows does
252
+ not change the foreground), DOM focus is set with MSAA `accSelect(SELFLAG_TAKEFOCUS)` and read back, characters go
253
+ as `WM_CHAR`, and the deactivation is *posted* so it is processed after them. The page receives trusted `keydown`
254
+ and `input` events. One caveat was measured: an app launched a moment ago may use its launch-time foreground right
255
+ once (about 10 ms, handed back by the guard), so the first simulated activation per process is treated like a brief
256
+ activation. Apps started with `launch(devtools=true)` are driven through the DevTools protocol instead.
257
+ - **Steam (CEF in an SDL frame)**: recognised as Chromium; `launch(app="Steam")` adds Steam's own
258
+ `-cef-disable-occlusion -cef-force-accessibility` switches so the UI stays readable while covered.
259
+ - **Tk**: no UI Automation and posted input has no effect (its buttons show up as Win32 `Button` but ignore
260
+ `BN_CLICKED`): refused in the background, real input with `foreground=true`; its text is found by the OCR fallback.
261
+
262
+ ### Capture
263
+
264
+ `PrintWindow` (10 to 26 ms, covered windows included), Windows.Graphics.Capture only as a fallback. Images are capped
265
+ at 1568 px and 1.15 MP (2000 px and 3.75 MP with `detail="high"`) so that Claude models do not downscale them, which
266
+ keeps coordinates exact. Coordinates are bound to the window: followed if it moves, refused if it was resized.
267
+
268
+ ### Agent at work
269
+
270
+ While an action runs (`act`, `launch`, `window`; never the reads), a small logo spins on itself in the bottom-right
271
+ corner of the driven window's screen, like a game loading screen, with a breathing blue halo. It goes away 1.6 s after
272
+ the last action. The overlay is always on top, borderless, click-through, never activated, absent from the taskbar
273
+ and excluded from screen captures (the model never sees it in `look`). `NEXUS_WINDOWS_INDICATOR=0` turns it off.
274
+
275
+ ### Real mouse and keyboard
276
+
277
+ Only with `act(foreground=true)`, which the user must approve. The window then stays in front for the whole batch;
278
+ cursor and foreground are handed back at the end; any physical input from the user during the batch stops it.
279
+
280
+ ## Working alongside other agents
281
+
282
+ The server cooperates with other desktop agents on the same PC (it is used next to a Codex layer,
283
+ [NexusWindows for Codex](https://github.com/pironjulien/NexusWindows-Codex), and an Antigravity layer)
284
+ through two small file-based protocols. Any agent can implement them.
285
+
286
+ **Foreground token** (`%USERPROFILE%\.nexus\foreground.lock`): taken only while really holding the mouse or the
287
+ foreground (real input, brief activation, window put in front), never for background actions. Holding it means an
288
+ exclusive `LockFileEx` on 1 byte at offset 2^32, opened with read, write and delete sharing; Windows releases it when
289
+ the handle closes, including when the process dies, so there is no stale token. The holder writes
290
+ `{"owner", "pid", "since", "purpose"}` at the start of the file for diagnostics only. Waiters wait at most a few
291
+ seconds (8 s here), then do nothing and say who holds it. A foreground guard that sees another agent holding the
292
+ token follows that agent's window instead of taking the foreground back.
293
+
294
+ **Emergency stop** (Ctrl+Alt+Shift+Esc, files in `%USERPROFILE%\.nexus\`): every agent tries
295
+ `RegisterHotKey(MOD_NOREPEAT)`; one gets it, the others retry every 3 s. The holder writes a heartbeat to
296
+ `stop.owner` every 3 s. On a press it rewrites `stop` with `{"by", "pid", "at", "hold_s": 120, "nonce"}`. Every agent
297
+ watches `stop` at least every 0.2 s and before each action: a new version younger than 120 s blocks all desktop
298
+ actions for the remaining time (reads stay allowed). The stop is latched in memory on a monotonic clock: deleting the
299
+ file or changing the clock does not lift it, a new press re-arms it.
300
+
301
+ ## Architecture
302
+
303
+ ```mermaid
304
+ flowchart LR
305
+ Claude["Claude Code or Claude Desktop"] -->|"MCP stdio"| Server["server.py MCP tools"]
306
+ Server --> Worker["COM worker thread with hard timeout"]
307
+ Worker --> Snapshot["snapshot and capture"]
308
+ Worker --> Actions["actions per UI family"]
309
+ Actions --> Win32["Win32 messages"]
310
+ Actions --> UIA["UI Automation"]
311
+ Actions --> Chromium["Chromium simulated activation and DevTools"]
312
+ Actions --> Real["real input only with foreground true"]
313
+ Server --> Safety["policy, emergency stop, foreground guard"]
314
+ Safety --> Shared["shared files in USERPROFILE nexus"]
315
+ Real --> Shared
316
+ ```
317
+
318
+ ```
319
+ src/nexus_windows/
320
+ reloader.py stdio supervisor: restarts the server on new code and replays the client handshake
321
+ server.py MCP tools, dedicated COM thread, per-call log
322
+ actions.py executor facade, assembled from the act_*.py modules
323
+ act_base.py targets read back live, technique chains, outcomes, shared refusals
324
+ act_win32.py Win32 messages
325
+ act_uia.py UI Automation (WinForms, WPF, UWP/WinUI) and dispatch per family
326
+ act_chromium.py Chromium/Electron/CEF: verified click, DevTools, simulated activation, <select>
327
+ act_pointer.py points, message clicks, scrolling, drag, hover
328
+ act_wait.py text presence and waiting
329
+ snapshot.py window + popups, [N] elements, image, coordinates, changes since the last list
330
+ ocr.py Windows built-in OCR (Windows.Media.Ocr) for windows without UI Automation
331
+ uia.py UI Automation with a single cross-process cache request
332
+ methods.py Win32 message techniques
333
+ cdp.py minimal Chrome DevTools Protocol client
334
+ capture.py PrintWindow / Windows.Graphics.Capture
335
+ foreground.py foreground monitoring and restoration, brief activation
336
+ agentlock.py shared foreground token
337
+ postcond.py step postconditions (check)
338
+ routines.py verified routines per application
339
+ physical.py the user's physical input (Raw Input, no hook), told apart from injected input
340
+ launch.py background launch, DevTools, throwaway browser profiles
341
+ steam.py Steam switches, clean restart, DevTools port
342
+ realinput.py real mouse/keyboard (SendInput), only when authorised
343
+ policy.py where to act and what to launch (hard blocks of the shared policy, launch switches)
344
+ act_confirm.py confirmation of irreversible gestures (confirm: true), whatever key or click triggers them
345
+ shared/ the guard-rail policy shared with NexusWindows for Antigravity (garde-fous.json)
346
+ packages.py resumes Store apps that Windows suspended in the background
347
+ offwindows.py outside Windows: the server starts and lists its tools, every desktop tool says Windows is required
348
+ stop.py shared emergency stop
349
+ freshness.py detects a server whose code changed on disk
350
+ codeprint.py code fingerprint and location of the shared policy (no dependencies)
351
+ worker.py COM thread with a hard timeout
352
+ log.py JSONL log, 14 days
353
+ lab/ test applications (Win32, WinForms, WPF, Tk, a web page for Electron/Edge)
354
+ bench/ technique benchmarks and raw results
355
+ tests/ unit tests (pytest) and end-to-end tests (pytest -m live)
356
+ ```
357
+
358
+ ## Measurements
359
+
360
+ All figures come from [`bench/RESULTS.md`](https://github.com/pironjulien/NexusWindows-Claude/blob/main/bench/RESULTS.md) and the raw files in `bench/results/` (measured on one
361
+ PC, October 2026; the notes in `RESULTS.md` are in French).
362
+
363
+ | What | Result |
364
+ |---|---|
365
+ | Capture, PrintWindow | 10 to 26 ms, covered windows included |
366
+ | Real MCP server, 73 actions on the lab apps (0.4.0 to 0.5.0) | 69 succeeded, 5 explicit refusals, 0 false success, 0 cursor move, clipboard never touched; median 78 ms, p90 321 ms |
367
+ | 2,000 characters with 20 line breaks | Win32 38 ms, WinForms 66 ms, WPF 141 ms, Electron/Edge with DevTools 82 to 108 ms |
368
+ | Chromium simulated activation, scenario of 18 steps (0.7.0) | Electron 18/18, 1 foreground take of 9 ms (launch right, first time); Edge 18/18, 0 foreground take |
369
+ | Same, Electron without switches, hidden | 17/18; the failure is a page that rebuilds 1,500 elements per keystroke, reported as ✗ |
370
+ | Typing 700 characters on 6 lines, simulated activation | 0.85 to 1.1 s (Electron, Edge), 1.9 to 2 s when occluded |
371
+ | Final render of an `act` (0.7.0 vs 0.6.1) | Win32 418 → 221 ms, Electron 341 → 205 ms (window-settle detection replaces a fixed 300 ms wait) |
372
+ | Open drop-down list, choose in it (WinForms and WPF forms, real MCP server) | 8/8 scenarios, the application received the choice every time; `select` in an open WinForms list 113 ms (was 22 s and a failure); 0 foreground take sampled every 5 ms, cursor never moved |
373
+
374
+ Offline test suite: see the Tests badge (`test.ps1` on Windows, plus a startup check on Linux).
375
+
376
+ ## Side by side with Cua Driver (October 20, 2026)
377
+
378
+ [Cua Driver](https://github.com/trycua/cua) 0.37.0 is the closest other tool: it also works in the background by
379
+ default. Both were driven through their real MCP servers (`bench/cua_vs_nexus.py`) on the same lab window, covered by
380
+ an opaque window, nobody at the PC; Cua was used the way its own agent guide says (background first, then clicks, then
381
+ its foreground fallback after a refusal). The effect is judged by the application (event received or value read
382
+ back), never by the tool's report. 48 tasks each across Win32, WinForms, WPF, Tk, Electron and Edge; only the 38
383
+ where the target was really covered before and after each attempt are counted (`bench/tally_cua.py` computes the
384
+ counts from the raw results).
385
+
386
+ | In the background, target covered (38 tasks each) | nexus-windows 0.15.7 | Cua Driver 0.37.0 |
387
+ |---|---|---|
388
+ | Effect proven | 29 | 17 (+2 by clicks, +5 after taking the foreground) |
389
+ | False success (reported done, the app got nothing) | 0 | 3 |
390
+ | Foreground taken | 1 (Edge raw click, handed back) | 7 |
391
+ | Real cursor moved | 0 | 0 |
392
+ | Median time of a successful action | 211 ms | 706 ms |
393
+
394
+ All 48 tasks: 39 proven against 25, false successes 0 against 3, foreground taken 1 against 8. nexus-windows is slower
395
+ than in 0.13 (138 ms): the focus and foreground read-backs added by the cross reviews are the price of safety.
396
+
397
+ Taken from Cua: reading only what changed (`then="changes"`). Not taken, with the measurement in `RESULTS.md`: its
398
+ injected WPF click (moves the user's real cursor), CDP clicks in an already open Chrome (turns on remote debugging in
399
+ the user's real profile). Tried and dropped because they do not work in the background or touch the user's window:
400
+ simulated activation for WPF shortcuts (WPF takes the foreground), `WM_POINTERWHEEL` (Windows refuses to post it),
401
+ `WM_VSCROLL` to the Chromium renderer (no effect), `InjectSyntheticPointerInput` (goes to the window on top).
402
+ CursorTouch/Windows-MCP, deploymenttheory/windows-mcp-server and microsoft/UFO² were read, not run: all three use the
403
+ real mouse or the foreground.
404
+
405
+ ## Cross-agent bench (October 16, 2026)
406
+
407
+ The same task was run by the three Windows desktop agents used on this PC (this server, the Codex layer and the
408
+ Antigravity layer) on WinForms and WPF forms created without activation at the bottom of the z-order, while the
409
+ user kept working: fill three fields, tick a box, open the "Formule" drop-down list, choose "Bravo" in the open
410
+ list, validate. Proof is the result label read back in the application. Physical input was forbidden and counted.
411
+
412
+ | | Morning | After fixes | Measured |
413
+ |---|---|---|---|
414
+ | This server (0.7.0 + drop-down fixes) | 17/20 | **19/20** | open list read back on both families; `select` in an open WinForms list 113 ms instead of 22 s; application received `Formule=Bravo;Envois=1`; 0 foreground take over 1,371 and 773 samples (20 ms), 0 cursor move, 0 physical input |
415
+ | [NexusWindows for Codex](https://github.com/pironjulien/NexusWindows-Codex) 1.4.0 | 16/20 | **19/20** | every step verified on both families; observe + batch 1.2 to 1.4 s |
416
+ | Antigravity layer | 18/20 | **19/20** | open WinForms list read and chosen; batch status is the worst step |
417
+
418
+ What still keeps this server from 20: clicking "Validate" stays `~` without an `expect` (the application did receive
419
+ it), and a `click` on a closed WPF list is `~` where `expand` is `✓`.
420
+
421
+ ## Security
422
+
423
+ - **Emergency stop**: Ctrl+Alt+Shift+Esc interrupts the running action at its next checkpoint (typing included) and
424
+ refuses every new action for 2 minutes, across conversations and for the other agents (protocol above).
425
+ - **Hard blocks** (shared policy, `src/nexus_windows/shared/garde-fous.json`, same file as NexusWindows for
426
+ Antigravity): the secure desktop (UAC, lock and sign-in screens) and password managers are never read nor driven. A missing or unreadable policy refuses every action (fail closed).
427
+ - **Confirmation of irreversible gestures**: paying, buying, ordering, transferring money, sending, publishing,
428
+ posting, deleting permanently, emptying the bin, formatting, uninstalling, resetting, cancelling a subscription,
429
+ deleting an account or making a repository public need `confirm: true` on the step, which the model sets only on the
430
+ user's explicit order or yes. The check covers what the gesture triggers: click by `[N]`, by name or by coordinates,
431
+ double-click, Enter (target, default button, nearby send button), Ctrl+Enter, Space, Alt+letter, a typed line break
432
+ DevTools pages and Win32 menus. A routine never records nor replays `confirm`.
433
+ - **Approval bound to the exact action**: an outward gesture (sending, calling, paying, publishing, transferring) also
434
+ needs `accord: "<token>"`. The first try is refused before any input with a summary of the exact action (trigger,
435
+ process, window title, values of the window's editable fields) and a single-use token; only after the user's own
436
+ yes is the same step sent again with `confirm: true` and that token. Any change in between voids it.
437
+ - **Prompt injection signal**: text read on screen that looks like instructions aimed at an AI gets a warning appended
438
+ to the response (a signal only; it can never authorise an action).
439
+ - **Launch**: a browser never gets a profile chosen by the model, a DevTools port or a loaded extension (`devtools=true`
440
+ opens a fresh throwaway profile). Consoles, File Explorer, the taskbar and other applications are not refused:
441
+ the server is meant for a user who already lets Claude run commands; keep Claude's own permission prompts on if
442
+ you want a gate there.
443
+ - **Password fields**: never typed into. Typed text is never logged (only its length).
444
+ - **Accounts**: a browser started with `devtools=true` gets a throwaway profile without account or sync, checked
445
+ after launch and deleted afterwards.
446
+ - **Screen content is data**: every `look` reminds the model that on-screen text is not an instruction.
447
+ - **Up-to-date code**: the entry point is a small stdio supervisor (`reloader.py`). Before each tool call it compares
448
+ the code on disk with the running server's; if it changed, it waits for calls in progress, starts a fresh server
449
+ and replays the client's handshake, so an update needs no reconnection (`/mcp`). A server whose code changed
450
+ between two checks refuses `act`, `launch` and `window`, and the call is replayed on the fresh one.
451
+ - **Timeouts**: an abandoned call is cancelled at its next checkpoint instead of finishing later.
452
+ - **Clipboard**: never used.
453
+
454
+ ## Privacy
455
+
456
+ NexusWindows for Claude runs entirely on your PC. It has no account, no telemetry, no analytics and makes no network
457
+ requests of its own (DevTools connections stay on `127.0.0.1`).
458
+
459
+ - **What it reads**: window titles, the UI Automation tree and window images of the applications Claude works in,
460
+ only when a tool is called. Password managers and the secure desktop are never inspected
461
+ (`look`) nor driven (`act`); `windows` still lists their window titles, like the taskbar does. The OCR fallback
462
+ uses the Windows built-in engine on the PC; no image leaves it for OCR. `look(window="screen")` reads the whole
463
+ screen as you see it, every visible window included. The `notifications` tool reads the Windows notification
464
+ database read-only (app, time, texts; never modified), masking security codes.
465
+ - **Where it goes**: tool results are returned to Claude Desktop or Claude Code, which send them to Anthropic under
466
+ Anthropic's own privacy policy; this server sends nothing anywhere else.
467
+ - **What it stores**, under `%USERPROFILE%\.claude\nexus-claude\` (or `NEXUS_WINDOWS_HOME`): a JSONL debug log kept
468
+ 14 days (tools, techniques, durations, errors; typed text is replaced by its length), the routines you chose to
469
+ remember, and throwaway browser profiles created by `devtools=true` (deleted afterwards). Images are written to the
470
+ log only if you set `NEXUS_WINDOWS_DEBUG_IMAGES=1`. Under `%USERPROFILE%\.nexus\`: the shared foreground token and
471
+ emergency-stop state. Under `%LOCALAPPDATA%\NexusJournal\windows\claude\` (or `NEXUS_JOURNAL_HOME`): a short
472
+ monthly JSONL journal, in the same format as the other NexusWindows tools (app executable name, framework, action,
473
+ technique, outcome, duration, whether the foreground was used, and the first words of an error, cut before any
474
+ quote, colon or bracket); never typed text, screen text, labels, titles or paths. The server never deletes it.
475
+ - **Removing it**: remove the server from Claude (`claude mcp remove nexus-windows`), then delete those folders (and `%LOCALAPPDATA%\NexusJournal`).
476
+
477
+ Questions or concerns: open an issue on this repository.
478
+
479
+ ## Limits
480
+
481
+ - Code comments are in French. Everything an MCP client receives (instructions, tool descriptions, step reports,
482
+ refusal messages) is in English.
483
+ - Windows only. Tested on Windows 11 with the lab apps and a handful of real applications; not every application has
484
+ been checked.
485
+ - Applications without UI Automation that ignore posted input (Tk, some games, canvases) need real input, so the user's
486
+ approval and the foreground; the OCR fallback finds their text but does not make background input possible.
487
+ - WPF: raw clicks on a point, the mouse wheel and keyboard shortcuts are refused in the background (WPF ignores posted
488
+ mouse input and takes the foreground when activated); controls with UI Automation patterns work.
489
+ - A mouse wheel on a point of a covered Chromium page has no effect (no `wheel` event; 8 variants measured); it is
490
+ reported as `~`, never as a success.
491
+ - Store apps that Windows suspends in the background are resumed (`IPackageDebugSettings.Resume`, no foreground);
492
+ one that Windows still does not render can only be shown by taking the foreground; this is reported.
493
+ - In Chromium, a page that reacts very slowly to each keystroke can exceed the read-back time and is reported as ✗.
494
+ - An effect with nothing readable (a file written by a button, for example) stays `~`; add a `check` that observes it.
495
+ - The end-to-end suite (`pytest -m live`) drives real windows and refuses to start if the PC was used less than
496
+ 2 minutes ago.
497
+
498
+ ## Development
499
+
500
+ ```powershell
501
+ pwsh -NoProfile -File test.ps1 # unit tests, ruff check and format; venv and caches outside the clone
502
+ pwsh -NoProfile -File test.ps1 -Full # also the end-to-end tests on the lab windows
503
+ uv run python bench/bench.py # technique benchmark (when nobody is using the PC)
504
+ ```
505
+
506
+ ## Licence
507
+
508
+ MIT, see [LICENSE](https://github.com/pironjulien/NexusWindows-Claude/blob/main/LICENSE). Copyright (c) 2026 Julien Piron.