nexus-windows-codex
This MCP server lets Codex inspect and operate Windows desktop applications in the background, with verified postconditions and guarded fallback to real mouse/keyboard input.
List application windows and open dialogs, excluding password managers.
Inspect a window via its UI Automation tree and/or a native capture that works even when covered; zoom into a region and overlay tree line numbers.
Act on the last observed window with steps such as click, setValue, typeText, key, select, menu, secondary, scroll, drag, and hover.
Run one action or a batch of up to 32 steps, each with its own
expectpostcondition; stop at the first non-verified step and report ✓ verified, = already done, ~ unknown, or ✗ failed/refused.Prefer background techniques (Win32 messages, UI Automation, DevTools for Chromium) and use physical input only as a guarded fallback under a shared foreground token;
fallback:falseforbids physical input.Launch applications, folders, documents, or Settings pages and return the foreground to the user; close windows with one close message and report any save prompt without answering it.
Enforce safety guardrails: block password managers and password fields, require confirmation for sensitive actions, support an emergency stop, and stay local with no telemetry.
Targets OpenAI Codex as its host agent: exposes the Windows desktop-control session as an MCP server configured in Codex's config.toml, and can alternatively run as a Codex skill layered over Codex's Computer Use API (@oai/sky) inside Codex's Node REPL, driving windows, UI Automation, captures and input while the user keeps their mouse, keyboard and foreground window.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@nexus-windows-codexOpen Notepad in the background and type a short to-do list, then verify the text is there."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
NexusWindows for Codex

Windows computer use for Codex, in the background. An MCP server (nexus-windows-codex, one npx command) that
lets OpenAI Codex see and operate Windows desktop applications while the user keeps their mouse, keyboard and
foreground window. Codex's own Computer Use came to macOS first; on Windows, OpenAI's documentation says to keep the
target app visible on the active desktop while it runs (Codex docs).
NexusWindows for Codex has its own local .NET helper for everything: window inventory, UI Automation tree, PrintWindow
capture of covered windows, Win32 messages and UI Automation patterns without focus, and its own real mouse and
keyboard as the last resort, under a shared foreground token. Every action is judged from the application's real
state, and a batch needs an explicit postcondition per step. It also ships as a Codex skill that layers the same session over Codex's Computer Use API (@oai/sky).
Version 3.0.1 · Windows 10/11 · Node 22+ · .NET 8 · MIT licence
Part of the Nexus family: NexusWindows (Claude · Codex · Antigravity), NexusBrowser (repo), NexusAndroid (repo). Project page: julienpiron.fr/nexuswindows.
Why
Codex's built-in Computer Use acts with the physical mouse and keyboard: it brings the target window to the front and the user has to stop working while it acts. Many Windows applications can be driven without that. NexusWindows for Codex tries the background techniques first, judges the result from the application's real state, and only uses its helper's real mouse and keyboard as a fallback, after a pause in the user's own typing and under a token shared with the other agents on the PC.
It is an MCP server (Node, no npm dependency) with a self-contained .NET helper: no listening network port, no token and no private Electron API. The optional Codex skill runs the same session in Codex's Node REPL instead, over Codex's Computer Use API.
Related MCP server: codex-cua-mcp
NexusWindows family
Three MCP servers, one per agent, built separately because each model needs its tools shaped for it, with the same promise: the user keeps their mouse, keyboard and foreground window, and every action is read back.
Claude | Codex | Antigravity | |
Install |
|
|
|
Package | |||
Tools |
|
|
|
Repository |
Every step reports ✓ verified, = already done, ~ unknown (never replayed) or ✗ failed or refused. The three share the guardrail policy, the foreground token, the emergency stop (Ctrl+Alt+Shift+Esc), a common journal format and a common bench.
Installation
Windows 10 or 11 and the Codex app (or the Codex CLI). The server runs on Node.js 22 or later; the npm package carries a self-contained helper: no .NET install.
One step (installs Node.js LTS if missing, downloads and checks the server, registers it in Codex): open
Windows PowerShell (Start menu, type powershell) and paste:
irm https://raw.githubusercontent.com/pironjulien/NexusWindows-Codex/main/setup.ps1 | iexThen quit Codex completely and open it again. setup.ps1
is short and can be read first; running it again only does what is missing. Node.js comes from its official package
through winget (Windows asks once for approval).
Codex plugin (the same server; Node.js 22+ required). This repository is a plugin marketplace. In the Codex app:
Settings → Plugins → Add → Add a marketplace, source pironjulien/NexusWindows-Codex, then install
NexusWindows from the Plugins directory. Or in a terminal:
codex plugin marketplace add pironjulien/NexusWindows-Codex
codex plugin add nexus-windows@nexus-windows-codexBy hand (Node.js 22+ required, from the official installer). In the Codex app: Settings →
Plugins → Add → Add an MCP server, name nexus-windows, type STDIO, command npx, arguments -y and
nexus-windows-codex@latest. Or in a terminal:
codex mcp add nexus-windows -- npx -y nexus-windows-codex@latestOr in ~/.codex/config.toml (shared by the Codex app, CLI and IDE extension):
[mcp_servers.nexus-windows]
command = "npx"
args = ["-y", "nexus-windows-codex@latest"]Restart Codex, then ask: "Open Notepad and write a shopping list: milk, eggs, bread." Other MCP clients use the same
command (npx -y nexus-windows-codex@latest; a client that cannot start .cmd scripts needs cmd /c npx -y nexus-windows-codex@latest).
With @latest, npm checks for a new version at each start: Codex runs the newest release, nothing to reinstall.
Codex skill (alternative, from a clone)
The skill runs the same session inside Codex's Node REPL and can fall back on Codex's Computer Use API. It needs the Codex desktop app with its Computer Use plugin and the .NET 8 SDK:
git clone https://github.com/pironjulien/NexusWindows-Codex.git
cd NexusWindows-Codex
pwsh -NoProfile -File install.ps1 # build the helper, install the skill into %USERPROFILE%\.codex\skills\nexus-windows
pwsh -NoProfile -File install.ps1 -CheckOnly # verify the installation matches the sourcesinstall.ps1 keeps versioned helper builds under %LOCALAPPDATA%\NexusCodex\ComputerUse (or -StateRoot), writes a
source-linked entry.mjs next to the skill (so keep the clone where it is), checks the four .NET runtime files by
hash, and serialises concurrent installations. CODEX_HOME or -CodexHome changes the Codex folder. Re-run it after
updating the clone. Note: the build path must stay under the Windows 260-character limit. The MCP server also finds
this helper when it runs from a clone.
The skill is picked up by new Codex sessions. A REPL that already imported an older version must be reset, because the JavaScript module cache does not reload.
Tools
Tool | Purpose |
| Application windows (id, app, title, pid), like the taskbar, plus open dialogs with |
| One window by id or a unique part of its title or app: UI Automation tree, plus a capture that works on covered windows with |
| One step, or up to 32 each with its own |
| Start an application (name, path, Store app id), a folder, a document or a Settings page ( |
|
|
Step kinds: click (selector, or point and native capture id; button, count), setValue, typeText, key,
select, menu, secondary, scroll, drag, hover (one mouse move, no button). Each step reports ✓ verified, = already done, ~ unknown (look again,
never replayed) or ✗ failed or refused.
Usage
As an MCP server: windows, then look at one window, then act with selectors from that look and an expect
that proves the effect. An observation serves one act and expires after 60 s.
As a skill, the agent follows SKILL.md and the API reference. In Codex's Node REPL:
if (!globalThis.sky) { const { sky } = await import('@oai/sky'); globalThis.sky = sky; }
const home = nodeRepl.homeDir ?? (await import('node:os')).homedir();
globalThis.nexusWindows = await import('file:///' + home.replaceAll('\\', '/') + '/.codex/skills/nexus-windows/entry.mjs');
globalThis.win = nexusWindows.createWindowsSession(sky);
nodeRepl.write(await win.windows()); // pick exactly one window from this list
await win.bind({ id: chosenWindowId, app: chosenAppId });
globalThis.obs = await win.observe();
globalThis.result = await win.act(obs, {
kind: 'click', selector: { automationId: 'okButton', role: 'button' },
expect: { selector: { automationId: 'status' }, field: 'name', equals: 'Saved' }
});Read result.status, result.technique and result.foregroundTaken, then continue from result.observation.
Call await win.close() at the end.
Local files:
Location | Content |
| installed skill and |
| versioned helper builds |
| verified recipes (static UI labels only) |
| explicit measurements, no window content or typed text |
| native captures, 10 minutes and 32 files at most |
What it does
Background first, physical input last
Each semantic click, setValue, typeText, secondary, select and menu goes first to the helper:
UI family | Background technique | Never used |
Win32 |
| UIA Invoke (the Win32 proxy calls |
WinForms | UIA Invoke/Toggle; messages for Edit, ComboBox (same as Win32, open list included) and ListBox |
|
WPF, UWP/WinUI, Chromium/Electron | COM UI Automation with |
A measured detail drives the design: once the managed System.Windows.Automation client has been used in a process,
a COM Invoke or Toggle from that same process activates the target window despite AutoSetFocus = FALSE (WPF and
WinForms on .NET 8). UI Automation patterns are therefore sent from a child process (--com-worker) that never loads
the managed client. Since 1.4.0 the managed client is not loaded anywhere: the tree is read with the COM UI
Automation client in one round trip (CacheRequest, Subtree scope, control view; about 50 ms for the bench
forms instead of 150 to 300 ms). For an action, only the target and its ancestors are read again, and any difference
from the observation is refused.
The options of a Win32/WinForms combo box are read by messages (CB_GETCOUNT, CB_GETLBTEXT, CB_GETCURSEL), open
or not, as list/listitem nodes under it; expanded comes from CB_GETDROPPEDSTATE. Measured: the UIA subtree of
an open WinForms combo box answers "Malformed Cacheresponse" after about 7 s and then stops answering, so it is never
walked.
Each technique reads its effect back: applied, none (nothing changed) or sent (no read-back possible).
Physical fallback happens only when no technique applies, or when the expect is not met and nothing observable
changed. A partial effect is never repeated physically; fallback:false forbids the physical path. Every result says
which technique acted (background:messages, background:uia, foreground:uia, physical:sky, sky:semantic),
whether the foreground was taken, and every attempt.
Explicit postconditions
expect distinguishes verified, unmet, already-satisfied and unknown results. An observation is consumed once;
a stale observation, another window, a missing or ambiguous control, or a changed control identity aborts the action
before any input. A truncated UIA value cannot satisfy an exact equality, and an empty tree never proves that a
control disappeared. Native password fields are refused.
A postcondition already true before the action skips it (already-satisfied, nothing sent) only when it is a
precise state (equals) that the action changes: value, checked, selected, expanded or focused on the
target, or a result on another element. A postcondition that only restates the target ("the button exists") is
refused, and a non-precise one already true (exists, includes, the target's label) is refused before any input:
it could not tell the effect from the previous state. A combo box choice is proven by the combo box value, never by
its option element.
Clean capture with PrintWindow
observe({mode:'image', capture:'native'}) captures the bound window with PrintWindow(PW_RENDERFULLCONTENT)
without bringing it forward, even when covered: per-monitor DPI aware, cropped to the DWM frame, DPI-unaware windows
drawn at their logical size and scaled. In the Codex skill, a blank, minimized or failed capture falls back to Sky's
screenshot; the MCP server has no such fallback and reports the failure. Native images follow the common Nexus image
rule: at most 1568 px and 1.15 MP, lossless WebP from a built-in encoder (near-lossless above 200 KB, never over
500 KB), local files (32 at most, removed after 10 minutes at the next capture, at server start and at a clean stop):
evidence for the model, and the coordinate frame of a point action that names the image (screenshotId), scaled back
to the screen pixel. look(region=[x1, y1, x2, y2]) reads an area of the last full image at full resolution, enlarged
up to 2x for small text; its own screenshotId takes points. An image identical to the last one sent for that window
(same pixels and frame) is not attached again; the reply names the id that takes points, and mode="image" always
attaches it. look(mode="both", marks="auto"|"all") reads the tree just before the capture and draws on the image the
tree line number of each kept element (auto: unnamed controls; all: every element with a rectangle), at a constant
size after scaling; no number when the window moved between the two reads, on another window's popup, or when the
label does not fit whole. Default none. Numbers link the image to the tree; act still targets a selector or a point.
Verified batches (actBatch)
actBatch(obs, steps) runs up to 32 actions in one call. Every step needs an expect; all steps are validated before
any input; each step acts on the observation refreshed by the previous one; the batch stops at the first step that is
not verified or already-satisfied.
Multiple windows
The session follows dialogs and popups without a new bind: windows owned by the followed windows, windows that
disable the window in front (modal), and windows of the same process that appear during an action. When a dialog
closes, the session returns to its nearest open owner. Each observation reports windowStack and windowChange.
Transient popups (caption-less WS_POPUP windows with WS_EX_NOACTIVATE: an open drop-down list, a tooltip, a WPF
popup; or a Win32 ComboLBox) are never followed: they are read through the window's own tree and listed in
obs.popups.
Guardrails: one shared policy
Since 1.5.0 the guardrails come from the policy shared by the three NexusWindows editions (Codex, Claude,
Antigravity), garde-fous.json, with a codex entry. A copy is embedded at the root of this repository; inside the
author's private workspace the live shared file is read instead (a test checks both are byte-identical).
NEXUS_GARDE_FOUS can point to another file; an imposed path is never silently replaced. A missing or invalid policy
refuses every action (fail closed), and the .NET helper refuses every window request without a readable policy.
Hard block (refused before any read or input): the secure desktop (UAC, lock screen, sign-in), Windows credential prompts, password managers (KeePass, Bitwarden, 1Password, Dashlane, NordPass, RoboForm, LastPass, by process prefix), and Codex's own application (Codex, ChatGPT), because Codex Computer Use asks for app access inside its main window. Consoles and terminals, File Explorer and administration tools are no longer refused (they were until 1.4.1): the layer is meant for a user who already lets Codex run commands. Password fields stay refused everywhere, and their value is never read.
Confirmation (confirm:true on the action, set only on the user's explicit order or after their yes): paying,
calling, sending, publishing, deleting permanently, formatting, uninstalling, resetting, cancelling a subscription,
making a repository public, plus a generic verb (Validate, OK, Start) in a window whose title is about payment or
formatting. The check is on what the gesture triggers, not on its form, before any input and whatever technique
follows: a click by selector or by screenshot coordinates (single or double; a text or icon inside a button counts as
the button), Enter, Ctrl+Enter, Space, Alt+letter (access key or underlined letter), typed text containing a line
break, a menu command, a secondary action other than expand, collapse, toggle, select or scroll. The refusal
(error.confirmationRequired) sends nothing; a batch stops at that step. A learned recipe never carries
confirm. Direct calls to Sky bypass this layer: always go through the session.
The user's presence (Raw Input)
A long-lived --stop-guard process registers Raw Input (RIDEV_INPUTSINK, message-only window, no hook). It reports
only the instant of each physical keyboard or mouse input, never its content. Injected input, including Sky's own
SendInput, has no source device and is ignored. Before any physical input the session waits for 1.618 s without
user input (at most 8 s, otherwise the action is deferred and nothing is sent), then types in chunks of at most
48 graphemes and stops (interrupted, never resent) if the user takes the keyboard or mouse back. Without Raw
Input it falls back to GetLastInputInfo, excluding its own injections.
Application memory
A verified semantic click or secondary action can be saved as a recipe with its expected effect, a fingerprint of the executable's metadata and one of the control structure. Any change forces a new inspection. No control number or pixel is ever replayed, and typed content is never stored.
Agent at work
While an action runs (act, actBatch, activate; never an observation), a small logo spins on itself in the
bottom-right corner of the bound window's screen, like a game loading screen, with a breathing blue halo. It goes away
1.6 s after the last action. The emergency-stop guard, already alive for the whole REPL, draws it on the commands
busy <hwnd> and idle (native/BusyIndicator.cs): a layered window that is always on top, borderless,
click-through, never activated, absent from the taskbar and excluded from screen captures. Rendering is analytic
(halo, shadow, coin) from native/logo.png decoded by GDI+, with no added dependency. NEXUS_WINDOWS_INDICATOR=0
turns it off.
Working alongside other agents
This layer runs next to two other desktop agents on the same PC (a Claude MCP server, NexusWindows for Claude, and an Antigravity layer). They coordinate through two file-based protocols that any agent can implement:
Foreground token (%USERPROFILE%\.nexus\foreground.lock): held only while really using the mouse or the
foreground (Sky physical input, activation, the foreground UIA fallback), never for reads or background techniques.
Holding it means an exclusive LockFileEx on 1 byte at offset 2^32 (in C#: FileStream with
FileShare.ReadWrite | FileShare.Delete, then Lock(1L << 32, 1)). Windows releases it when the handle closes,
including when the process dies. The holder writes {"owner", "pid", "since", "purpose"} for diagnostics only. A
waiter waits at most 8 s, then reports a deferred action and sends nothing.
Emergency stop (Ctrl+Alt+Shift+Esc, files in %USERPROFILE%\.nexus\): one process per PC holds
RegisterHotKey(MOD_NOREPEAT) (others retry every 3 s) and beats in stop.owner every 3 s; a press rewrites stop
with {"by", "pid", "at", "hold_s": 120, "nonce"}. Here the --stop-guard helper takes the hotkey when nobody else
holds it, for as long as the Codex REPL lives. The JavaScript session watches stop every 0.2 s and before each
action, and the helper checks it again before each UIA action and token acquisition. A new version younger than 120 s
blocks every desktop action for the remaining time; observations stay allowed. The stop is latched in memory on a
monotonic clock: deleting the file or changing the clock does not lift it.
Architecture
flowchart LR
Codex["Codex"] --> MCP["MCP server bin and lib mcp.mjs"]
MCP --> Provider["lib native-provider.mjs"]
Provider --> Session["lib session.mjs"]
Codex --> Skill["skill entry.mjs in the Node REPL"]
Skill --> Session
Session -. skill only .-> Sky["Codex Computer Use API"]
Session --> Native["lib native.mjs"]
Native --> Helper["NexusCodex.UIA server"]
Helper --> Messages["Win32 messages"]
Helper --> ComWorker["COM only worker for UIA patterns"]
Helper --> Capture["PrintWindow capture"]
Session --> Guard["stop guard with Raw Input"]
Guard --> Shared["shared files in USERPROFILE nexus"]
Helper --> Sharedbin/nexus-windows-codex.mjs the MCP server command (stdio)
lib/
mcp.mjs MCP protocol and tools (no npm dependency)
native-provider.mjs window inventory by the helper, every window driven by the helper alone
session.mjs WindowsSession: bind, observe, act, actBatch, recipes, window following
native.mjs client for the .NET helper (one reused process, correlated requests, timeouts)
tree.mjs accessibility tree normalisation and digests
memory.mjs recipes and metrics (atomic, locked writes)
presence.mjs user presence from the stop guard
stop.mjs emergency stop watcher and guard process
native/ .NET 8 helper: Program.cs (modes --server, --com-worker, --stop-guard, --foreground-token),
Background.cs, ComUia.cs, ComWorker.cs, Capture.cs, Presence.cs, EmergencyStop.cs,
ForegroundToken.cs, Win32.cs
skill/nexus-windows/ SKILL.md and references (API, per-application notes)
tests/ node:test suites; tests/live: real validation fixture (WinForms, Win32, WPF)
setup.ps1 one-step setup: Node.js if missing, server from npm checked, registered in Codex
.codex-plugin/, .mcp.json, .agents/plugins/marketplace.json Codex plugin and its marketplace
install.ps1 builds the helper and installs the skill
test.ps1 offline check; -Full adds the real validationMeasurements
Real validation of October 15, 2026 on the repository's own fixture (tests/live, run by test.ps1 -Full). Windows shown without activation at the bottom of the z-order, the Win32 one covered by the WinForms one.
Each action: postcondition verified, event counted by the application, foreground unchanged, cursor still.
Action | Technique | Duration (input and read-backs) |
Win32 button, check box, typing, append at caret, combo box, list, menu | messages | 105 to 159 ms |
WinForms typing, combo box, list | messages | 292 to 338 ms |
WinForms check box, button, dialog opened then closed (followed automatically) | COM UIA Toggle / Invoke | 205 to 441 ms |
WPF button, check box, value | COM UIA Invoke / Toggle / Value | 193 to 241 ms |
Batch of 3 steps, stopped at step 2 (step 3 never sent) | messages | 658 ms |
Capture of the covered Win32 window | PrintWindow, not blank | 19 ms |
Offline suite: 108 JavaScript tests, 103 passed and 5 real-environment tests skipped outside -Full
(test.ps1, October 16, 2026). Durations are dominated by full UIA tree read-backs. The physical fallback that takes
the foreground was skipped in that run because the user was active; it is not counted as passed.
Common bench of the NexusWindows family (October 25, 2026)
The three editions are measured together by the family's common bench: 55 tasks on lab windows (Win32, WinForms, WPF, Tk, Electron and Edge, plus launching an application behind a maximized window), three rounds each, every lab window covered by another window, run only while nobody uses the PC (a run stops and is not counted when the user comes back). The effect is judged by the application itself, never by the tool's report. "Without intrusion" counts an effect only when the user's foreground window and cursor stayed untouched.
165 trials (55 tasks × 3) | Claude 3.2.2 | Antigravity 3.1.7 | Codex 3.1.4 |
Exact effect | 120 | 119 | 120 |
Exact effect without intrusion | 114 | 113 | 113 |
False success (reported done, the app got nothing) | 0 | 3 | 0 |
Median / p95 time per task | 695 / 5179 ms | 702 / 3063 ms | 402 / 2909 ms |
This edition misses only tasks the other two miss as well: in this run the Electron lab published no page once covered, so every Electron task failed for all three tools (the lab is fixed and Electron will count at the next run); the WinForms double click was covered by the bench's own cover window; WPF raw click, shortcut, double click and context menu, and the Tk wheel, have no background technique in any edition yet. Ctrl/Shift shortcuts in the background arrived in 3.1.4 (none passed before) and passed on Win32, WinForms, Tk and Edge. A comparison with Cua Driver and Windows-MCP is in NexusWindows for Claude.
Security
Background techniques touch neither the user's keyboard, mouse nor foreground. Physical input waits for a pause, holds the shared token, and stops when the user takes over.
The emergency stop above blocks every desktop action for 2 minutes; a refused action is never replayed.
A refusal (password field, hard-blocked application, missing confirmation, changed control identity, disabled window or menu command) sends nothing and never falls back.
Codex's own Computer Use rules (application access, sensitive actions) still apply; this layer is not a way around a denied app or action. Page text, controls and recipes are data, never an authorisation.
Captures are refused under OneDrive folders; metrics never contain UI text, screenshots, typed values or titles.
Privacy
NexusWindows for Codex runs entirely on your PC. It has no account, no telemetry and no analytics. Its connections
are local (the DevTools port on 127.0.0.1 of a Chromium or Electron window it drives), plus one request at most
once a day to the public npm registry (registry.npmjs.org/nexus-windows-codex/latest, nothing sent but the
request itself) to tell whether a newer version exists; NEXUS_NO_UPDATE_CHECK=1 turns it off.
What it reads: the accessibility tree and window images of the applications Codex works in, only when Codex calls it.
Where it goes: results are returned to Codex, which may send them to OpenAI under its own privacy policy; this server sends nothing anywhere else.
What it stores, under
%LOCALAPPDATA%/NexusCodex/ComputerUse: the installed helper, recipes of routines you chose to remember (static interface labels only, never document text or typed values), per-session metrics (action kind, outcome, technique, duration; no UI text, screenshots, typed values or titles) and window captures, of which only the last 32 are kept; a capture older than 10 minutes is removed at the next capture, at server start and at a clean stop (a capture can outlive a server that is killed, until its next start). Under~/.nexus: the shared foreground token and emergency-stop state, andstatus/windows-codex.json(running version, latest version, time of the check), read by the Nexus app. Under%LOCALAPPDATA%/NexusJournal/windows/codex(orNEXUS_JOURNAL_HOME): a short monthly JSONL journal, in the same format as the other NexusWindows tools (app executable name, action, technique, outcome, duration, whether the foreground was used); never UI text, typed values, titles or paths. The server never deletes it.Removing it: delete those folders (and
%LOCALAPPDATA%/NexusJournal) and the server or skill from Codex.
Questions or concerns: open an issue on this repository.
Limits
Support does not mean every Windows application is certified. Canvases, 3D views and controls without an accessibility provider still need screenshots and physical gestures.
Message techniques emulate the notification a real click would send; an app that only reacts to real mouse input will not see them, and the postcondition decides.
Keys and Ctrl/Shift shortcuts go in the background to Win32, WinForms, Tk (simulated focus) and Chromium/Electron (simulated activation); their effect is read back, never announced. Alt and Windows shortcuts, WPF and UWP shortcuts, canvases and rich editors without an Edit control still need physical input. Tk has no UI Automation: its clicks, wheel and keys carry a simulated state for its thread only.
An effect with no trace in the accessibility tree cannot be told from "no effect": give a postcondition that observes it, or
fallback:false.launchattributes a window to the launch by its process, and says how (proof):process, the process the shell returned; orapplication, for an application named by its executable or Store id (whose launcher may hand over to another process), a process of that application born after the request. Withapplication, another instance of the same application started by something else at the same moment could be taken for it. Files and folders need an absolute path; their windows come back as candidates unless the shell returned the process that shows them.In the skill, Sky's physical input cannot be tested outside the Codex REPL; its orchestration (pause, token, chunks, interruption) is covered by the offline tests only. The MCP server never uses Sky.
The skill, comments and some messages are written for one user (they name the user) and partly in French.
Development
pwsh -NoProfile -File test.ps1 # node tests + helper build in a temp folder; never touches %USERPROFILE%\.nexus
pwsh -NoProfile -File test.ps1 -Full # also real token/stop tests and the background validation on the fixtureLicence
MIT, see LICENSE. Copyright (c) 2026 Julien Piron.
Available Tools
5 toolsactAct in the windowADestructive
Steps on the window of the last look, in the background first (Win32 messages, UI Automation, DevTools for Chromium), the real mouse/keyboard only as a fallback under the shared foreground token. One step, or up to 32 each with its own expect; stops at the first step not verified. Per step: ✓ verified, = already done, ~ unknown (never replayed: look again), ✗ failed or refused.
| Name | Required | Description | Default |
|---|---|---|---|
| steps | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: discloses the try-in-background-first strategy (Win32/UIA/DevTools), the real mouse/keyboard only as fallback under a shared foreground token, a 32-step cap, stop-at-first-unverified semantics, per-step outcome markers (✓/=/~/✗), and the confirm/accord gate for sensitive actions. That is exactly the operational context destructiveHint/openWorldHint alone cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but every clause carries load — fallback policy, batching limit, stop condition, result legend — and the batching/stop rules are front-loaded. It is a single run-on block rather than broken into scannable segments, which costs a point.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully encodes return semantics via the ✓/=/~/✗ legend and explains failure behavior (stops at first unverified step). Remaining gaps are the omission of the per-kind parameter contract and the explicit dependency on a prior observation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Top-level schema coverage is 0%, and the description only gestures at a few parameters (expect, timeoutMs range, refresh, fallback, confirm/accord). The ten-value 'kind' enum, selector/point requirements per kind, and screenshotId are not explained in the description text, so it only partially compensates for the coverage gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the verb (steps/acts) and the resource (the window of the last look) and names the execution layers it drives. An agent can tell it apart from the observing sibling 'look', though the phrasing 'Steps on the window of the last look' is jargon-heavy rather than plainly declarative.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It implies the prerequisite (acting on the state produced by the last 'look') and routes back with '~ unknown (never replayed: look again)'. However it never explicitly says 'call look first' or contrasts itself with look/window/launch by name, so the when-to-use decision is inferred rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
launchLaunch an app, folder or documentA
Open an application (name, absolute path or Store app id), a folder or a document (absolute path) or a Settings page (ms-settings:...) and give the foreground back to the user. Returns the windows attributed to this launch, each with its proof: "process" (the process the shell returned) or "application" (the requested application, started after the request: another instance started at the same moment could be taken for it); other new windows come back as candidates (outcome unknown). Look at one before acting.
| Name | Required | Description | Default |
|---|---|---|---|
| app | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare non-read-only, open-world, non-idempotent, non-destructive, so the description focus on outcome attribution is the valuable addition: it explains the 'process' vs 'application' proof types and flags other new windows as candidates with unknown outcome. It does not address failure modes (app not found, permission issues) or what 'give the foreground back to the user' means practically.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the launchable input forms, then the return semantics. It is one dense run-on sentence with parentheticals, which makes it heavier to parse than necessary, but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter launch tool with no output schema, the description covers accepted inputs, the shape of the return value (attributed windows with proof types) and the ambiguity caveat, which is what an agent needs. Missing are error/partial-success behavior and any note on blocking versus async launch timing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% for the single required `app` parameter, so the description must carry it – and it does, enumerating the accepted forms (name, absolute path, Store app id, ms-settings: URI). It stops short of specifying format edge cases such as quoting or how relative paths are resolved.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and full resource scope: applications (by name, absolute path or Store app id), folders, documents and ms-settings pages. An agent can tell this apart from siblings like windows/look/act because the description is clearly about initiating a launch and the windows it produces, though it never names the siblings directly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is implied rather than stated: it's the tool to call when you want something started, and 'Look at one before acting' hints at following up with an inspection tool. There is no explicit when-not-to-use or named alternative among windows/look/window, so the agent must infer routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookLook at a windowARead-onlyIdempotent
See a window in the background, without bringing it forward: UI Automation tree (roles, names, ids, values, states) and, with mode image or both, a native capture that works even when the window is covered (WebP, at most 1568 px; unchanged since the last image sent: not attached again, mode image always attaches it). Selects that window for act; an observation serves one act and expires after 60 s.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | text (UI Automation tree, default), image (native capture), both | |
| marks | No | Numbers drawn on the image of mode both, each the index of its tree line: none (default), auto (unnamed controls), all | |
| region | No | [x1, y1, x2, y2] in pixels of the last native image of this window: that area enlarged up to 2x (small text); its own screenshotId takes points | |
| window | No | Window id from windows, or a unique part of its title or app; omitted: the window of the last look |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent annotations, it discloses genuinely non-obvious traits: the native capture works even when the window is covered, WebP capped at 1568 px, an unchanged image is not re-attached (except in mode image), and observations expire in 60 s. This is exactly the operational context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in the first clause and every clause carries information. It is a single dense semicolon-chained paragraph, which packs a lot into a small space but borders on overloaded for a reader scanning quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-value burden and does describe the two output shapes (tree fields, WebP image) and the caching rule. Remaining gaps are minor: it does not describe error behavior for an invalid or closed window, nor the exact size/format of the tree output.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter including marks and region is already documented, making 3 the baseline. The description adds some meaning for image/both and the region-relative-to-last-image behavior, but it never mentions 'marks' and largely restates schema content for the rest.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('See a window in the background, without bringing it forward') and immediately names the two payloads: UI Automation tree and optional native capture. It also differentiates itself from the sibling 'act' by declaring it selects the window that act will operate on.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context for each mode (text default, image, both) and an explicit lifecycle rule ('an observation serves one act and expires after 60 s'), which tells the agent when it must re-look. It references 'windows' as the source of window ids but does not explicitly contrast when to use 'look' vs 'window' or 'windows', so a small inference remains.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
windowManage a windowBDestructiveIdempotent
close: close the window (one close message, read back; a "save?" prompt is reported, never answered).
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | ||
| window | No | Window id from windows, or a unique part of its title or app; omitted: the window of the last look |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, but the description adds real behavioral detail beyond them: exactly one close message is sent, the result is read back, and a 'save?' prompt is reported but never answered. That last point is important context for a destructive action, since the agent learns it cannot resolve a blocking dialog. It does not say what happens to unsaved changes if the prompt is ignored.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded clause with a parenthetical qualifier; the action verb comes first and nothing is padded. The 'close:' label implies a multi-action structure that isn't delivered, which is a minor structural inefficiency.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, open-world operation with no output schema, the description covers the interaction sequence and the dialog behavior, which is the most important part. It omits what a matching window returns, what happens when several windows match the title fragment, and whether closing is reversible or discards state.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50%; the 'window' parameter is well documented in the schema (id, title fragment, or app name, defaulting to the last look), and the description covers the 'action' enum value by naming 'close'. However, the description adds no matching or resolution semantics of its own, so it neither compensates for nor improves on the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description does state a specific verb and resource ('close the window'), but the tool is named 'window' and titled 'Manage a window', implying a broader surface than the single documented action. The 'close:' prefix suggests a list of actions that is never expanded, so an agent cannot tell from the description whether other actions exist or how this differs from siblings like 'windows' or 'look'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: if you want to close a window, use this. There is no explicit when/when-not guidance and no mention of alternatives such as 'act' or 'launch' for other window interactions. The save-prompt note hints at a decision point but doesn't frame it as a usage rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
windowsList windowsARead-onlyIdempotent
Application windows on the desktop (id, app, title, pid), like the taskbar, plus open dialogs (a file "Open" box…) with dialogOf: the window that owns them; look at a dialog by its id or title. Password managers are never listed. filter: part of a title or app.
| Name | Required | Description | Default |
|---|---|---|---|
| filter | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/idempotent/non-destructive, yet the description adds a real behavioral disclosure: password managers are never listed, which matters for interpreting incomplete results. It also explains the dialog↔owner relationship via dialogOf. Missing are ordering, whether dialogs are flat or nested, and any staleness/refresh caveat.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One sentence, front-loaded with the resource and its fields, with the filter rule at the end. The parentheticals ('like the taskbar', 'a file "Open" box…') buy useful intuition without much bloat, though the ellipsis and analogy cost a little precision.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description does the work by naming the returned fields and the dialogOf relation, and by flagging the password-manager exclusion. It leaves the result shape ambiguous (are dialogs separate entries or nested?) and says nothing about ordering, which a listing tool arguably should.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must carry the single parameter — and it does, defining filter as 'part of a title or app', i.e. substring matching against either field. It doesn't state case sensitivity or that omission means all windows, but the semantics are substantially clarified.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (application windows on the desktop) and enumerates the data each entry carries (id, app, title, pid), plus the distinct dialog case with dialogOf. It stops short of explicitly contrasting itself with the sibling 'window' (single-window) or 'act' tools, so an agent still infers the enumeration-vs-inspection split.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'look at a dialog by its id or title' implies this listing is a discovery step that feeds the 'look' tool, and 'filter: part of a title or app' hints at narrowing. But there is no explicit statement of when to use this versus 'window', 'act' or 'launch', and no stated preconditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v3.1.7- Changed
act2 fields changed- changed
Input schema / properties / steps / items / descriptionPrevious value: -"One action on the last observation. kind: click (selector, or point + screenshotId of a native capture; button left|right|middle; count 1|2), setValue (selector, value), typeText (text; focus: selector), key (key: \"ctrl+s\", \"enter\"), select (selector, option), menu (path: \"File > Save\"), secondary (selector, action), scroll (point, screenshotId, scrollX, scrollY), drag (from, to, screenshotId). Optional: expect (postcondition), timeoutMs (0-15000), refresh (text|image|both), fallback (false forbids real mouse/keyboard), confirm and accord for sensitive actions (see the refusal)."New value: +"One action on the last observation. kind: click (selector, or point + screenshotId of a native capture; button left|right|middle; count 1|2), setValue (selector, value), typeText (text; focus: selector), key (key: \"ctrl+s\", \"enter\"), select (selector, option), menu (path: \"File > Save\"), secondary (selector, action), scroll (point, screenshotId, scrollX, scrollY), drag (from, to, screenshotId), hover (selector, or point + screenshotId: one mouse move, no button; give expect or refresh \"image\" to read the tooltip or menu it reveals). Optional: expect (postcondition), timeoutMs (0-15000), refresh (text|image|both), fallback (false forbids real mouse/keyboard), confirm and accord for sensitive actions (see the refusal)." - changed
Input schema / properties / steps / items / properties / kind / enumPrevious value: -[ - "click", - "setValue", - "typeText", - "key", - "select", - "menu", - "secondary", - "scroll", - "drag" -]New value: +[ + "click", + "setValue", + "typeText", + "key", + "select", + "menu", + "secondary", + "scroll", + "drag", + "hover" +]
5 tool updates
v0.1.0- First observed
act - First observed
launch - First observed
look - First observed
window - First observed
windows
TDQS
Scored across 5 tools
The core actions are mostly distinguishable: windows lists windows, look inspects one, act operates on the last looked window, and launch opens apps. However, the near-identical names windows and window are confusing, especially since window only closes a window rather than managing one generically. look also overlaps conceptually with windows because both are observation tools, though at different levels of detail.
The set mixes plural/singular nouns (windows, window) with bare verbs (act, launch, look), and act is especially vague on its own. There is no predictable verb_noun or resource_action pattern. The names are readable only because of their descriptions, not because of a consistent convention.
Five tools is well-scoped for a desktop automation server: observe windows, inspect a window, act, launch, and close. Each tool appears to have a distinct role in the workflow. The count is neither thin nor bloated.
The surface covers the core loop of listing windows, looking at one, acting on it, launching apps, and closing windows. However, window management is notably thin: close is the only explicit window operation, with no obvious focus, move, resize, minimize, or maximize operations. Agents can likely work around some gaps through act, but the window lifecycle is not fully represented.
Maintenance
Related MCP Connectors
Use your Mac, Windows or Linux computer from ChatGPT, Claude or Codex: files, commands, documents.
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Eyes and hands on real Windows PCs — observe, click, type via Glasswarp API.
Remote Desktop Commander: use files, terminal and processes on your own computers from any AI app.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables AI coding agents to automate Windows desktop applications through semantic UI Automation instead of brittle coordinate clicks, with tools for discovering windows, finding controls by stable identifiers, and verifying actions.45 PyPI3MIT
- AlicenseBqualityDmaintenanceEnables AI agents to control Windows desktop applications by wrapping Codex's Computer Use capability.1312 npm11MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to see, locate UI elements, and operate any Windows desktop app through natural language, using accessibility-tree matching with optional vision-model fallback, plus an autonomous visual loop with introspection and meta-learning.3MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to drive Windows desktop automation — opening and interacting with applications, native UI controls, keyboard/mouse input, files, processes, clipboard, and Chrome/Edge browsing via UI Automation and CDP. All actions pass through a safety policy with human approval, emergency stop, and deterministic verification.MIT