Skip to content

Releases: straygizmo/winuse

winuse 0.2.7

Choose a tag to compare

@straygizmo straygizmo released this 30 Oct 10:45

winuse 0.2.7 makes select_item and set_checked answer for themselves: both read the result back and say what reached the app, and a single_action switch stops them from acting twice for callers that must not resend an unconfirmed action. The winuse-gate plugin gains the winuse-operator subagent, which drives the app for Claude Code's main conversation so UI trees and screenshots stay out of its context.

Changes

  • select_item reads the selection back. The result reports item (the label that was matched and acted on), selected (what the container reports afterwards), method (mouse, selection, dom), actions (how many inputs reached the app) and outcome. done means the read-back named the item. A read-back that names another item is an error quoting what is selected, so a success result always means the item is selected. outcome: "unknown" with note means the container exposes no way to read its selection (no UIA Selection / Value pattern or SelectionItem state, no Java AccessibleSelection). The read-back is retried for about half a second for apps that update asynchronously.
  • UIA combo boxes are committed with a click. Selecting a popup item through the SelectionItem pattern and collapsing the popup leaves Win32 and Qt combo boxes on their old value, which earlier versions reported as success. select_item now clicks the item in the open popup, the way a user commits it, with the pattern path as the fallback; lists, tabs and trees keep the pattern first and the click as the fallback.
  • select_item single_action. With single_action: true the tool stops after the first path that delivered an input instead of trying the other one when the read-back disagrees; the mismatch error then says that no other method was tried. A mismatch error always names the paths delivered (2 actions delivered: mouse, selection).
  • set_checked reads the state back. The result reports method (toggle, selection_item, action, dom), toggles (0 when the control already had the state), checked (the state read back) and outcome. A toggle now gets about half a second to take before the next one is sent, so an asynchronously updating control is no longer toggled three times in a row; the default still sends up to 3 and then fails naming the toggles delivered and the state seen. single_action: true sends at most one toggle and reports outcome: "unknown" with note when the state still differs, instead of toggling again or failing.
  • winuse-gate plugin 0.2.0: the winuse-operator subagent. The main Claude Code conversation hands it the window and the goal; it reads trees and screenshots, drives the app and runs the assertions in its own context, and returns a short text report. Its passing assertions count for the gate (the hooks fire inside the subagent with the parent session id). The winuse-e2e skill now delegates the driving to it. Update the plugin with /plugin update winuse-gate@winuse.

Scenarios recorded with 0.2.6 replay unchanged. Behaviour changes for existing clients: select_item on a UIA combo box clicks the popup item instead of selecting it through the pattern, and a selection the app refused is now an error instead of a success; set_checked returns an object instead of a bare success, and takes up to about half a second longer when a toggle does not take at once.

Install

  1. Install the .NET 10 runtime (or SDK).
  2. Unzip winuse-0.2.7-win-x64.zip into a folder.
  3. Register with Claude Code: claude mcp add winuse -- <folder>\winuse.exe --mcp
  4. Set JEV_API_KEY, or CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, as user environment variables, then run winuse doctor.

Upgrading: unzip over the previous folder; no settings change.

Known issues

  • The combo box read-back and single_action are verified against Win32 controls and the Swing test fixture, not yet on the Qt app that reported them.
  • The operator subagent is Claude Code only; other MCP clients keep calling the tools directly.

Full changelog: CHANGELOG.md

winuse 0.2.6

Choose a tag to compare

@straygizmo straygizmo released this 30 Oct 05:15

winuse 0.2.6 answers the third round of feedback from driving Java Swing apps: every action tool now says what it did and whether the target confirmed it, Java elements that are scrolled out of view or beyond the window edge are recognised as such, a ref click checks where it would land before clicking, and window_close separates the request from the effect.

Changes

  • invoke reports how it acted. method (action, mouse, selection), the accessibility action name when one ran, and outcome: done when the target confirmed it, unknown when the request was delivered but never answered. On Swing that is what an action that opened a modal dialog looks like (it returns only when the dialog closes), so the result then carries note, foreground and new_windows instead of a misleading Action 'click' failed. method: "action" / "mouse" force one path.
  • Swing push buttons are clicked with the mouse by default. A button's click action runs on the JVM's event thread and answers only when it returns, so a button that opens a modal dialog used to hold the Java Access Bridge for the whole life of the dialog, which then could only be driven blind. invoke now brings the window to the front, checks that the point belongs to the app and clicks the visible button; menu items, check boxes, tabs and anything not on screen keep the accessibility action, and method: "action" restores it for buttons. The timeout diagnosis carries blocked_by_action_at and says how to proceed when an action did block the bridge.
  • set_text reports the path taken. method is value_pattern (UIA) or accessible_text (Java) when the accessibility API took the text and the field saw no key events, keyboard when the field was focused and the text typed (key listeners such as upper-casing run), fill for the DOM. method: "keyboard" forces typing, method: "api" fails instead of falling back. The text itself is never in the result.
  • window_close separates the request from the effect. close_requested, closed, window_exists_after_request, process_alive (when the window is gone), new_windows (windows the same process opened after the request, with refs: the exit confirmation or save prompt), foreground and a hint saying how to answer the prompt and wait for the window.
  • Explicit completeness flags and server identity. Every get_ui_tree result carries backend (java_access_bridge or uia) and server_version, and a Java tree always states node_limit_reached, depth_limit_reached and unreadable_nodes (false / 0 when the walk was complete), so a complete tree from this version is distinguishable from an older server that did not report them.
  • Clipped Java elements. Swing reports showing for everything in a displayed hierarchy, including what a scroll pane has scrolled out of view or what lies beyond the window's edge after a resize. Java elements are now clipped to their window and viewport ancestors: rect is the part on screen, an element with no on-screen part is offscreen: true (listed only with include_offscreen, with its full rect so you know where to scroll), and click / invoke resolve the same visibility at call time and refuse such an element with the reason.
  • Click hit check. click on a ref checks, before clicking, that the resolved point lies on a window of the process that owns the ref (popups and dialogs of the same process count). A point on another process's window (the taskbar or Start button after the screen shrank, a window covering the target) or on no window fails with the reason and nothing is clicked; the result names the window under the point as lands_on. Coordinates are clicked as given.

Scenarios recorded with 0.2.5 replay unchanged. Behaviour changes for existing clients: invoke on a visible Swing push button clicks it instead of running its action (pass method: "action" for the old behaviour); Java elements scrolled out of view are no longer listed by default (pass include_offscreen: true); a ref click that would land outside the app's windows now fails instead of clicking.

Install

  1. Install the .NET 10 runtime (or SDK).
  2. Unzip winuse-0.2.6-win-x64.zip into a folder.
  3. Register with Claude Code: claude mcp add winuse -- <folder>\winuse.exe --mcp
  4. Set JEV_API_KEY, or CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, as user environment variables, then run winuse doctor.

Upgrading: unzip over the previous folder; no settings change.

Known issues

  • The modal-dialog outcome and the clipping are verified against a fake bridge and the Swing test fixture, not yet on the live app that reported them.
  • Clipping follows viewport ancestors and the window only; a container that clips its children some other way is not detected.

Full changelog: CHANGELOG.md

winuse 0.2.5

Choose a tag to compare

@straygizmo straygizmo released this 30 Oct 02:01

winuse 0.2.5 answers the second round of feedback from driving Java Swing apps: get_table can skip the column header and tells a read failure from an empty cell, and the Java tree says when it may be incomplete for a reason other than the node limit.

Changes

  • get_table without the header. include_header: false never reads the column header (no bridge call, nothing in the result or the log) and rows holds data rows only. The result always carries column_count, so max_rows: 0, include_header: false returns the table size alone.
  • Read failure vs. empty cell. A cell the Java Access Bridge (or UIA) could not hand out or describe is null instead of "", and unreadable_cells counts them. An empty cell stays "", so a caller that decides on a cell value no longer mistakes a failed read for a blank.
  • Depth limit. get_ui_tree on a Java window reports depth_limit_reached: true when an element at max_depth had children that were not walked. A leaf at the limit does not set it.
  • Unreadable children. Children the bridge gave no handle or no context info for were already skipped; get_ui_tree now reports unreadable_nodes: n and the server logs a warning. Together with node_limit_reached these fields say when an element that exists may be missing from the tree; treat "element absent" as unknown while any of them is set.

Scenarios recorded with 0.2.4 replay unchanged. The one behaviour change for existing clients: a get_table cell that fails to read is null where it used to be "".

Install

  1. Install the .NET 10 runtime (or SDK).
  2. Unzip winuse-0.2.5-win-x64.zip into a folder.
  3. Register with Claude Code: claude mcp add winuse -- <folder>\winuse.exe --mcp
  4. Set JEV_API_KEY, or CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, as user environment variables, then run winuse doctor.

Upgrading: unzip over the previous folder; no settings change.

Known issues

  • The new fields are verified against a fake bridge in the test suite, not yet on a live Swing app with a failing bridge call.

Full changelog: CHANGELOG.md

winuse 0.2.4

Choose a tag to compare

@straygizmo straygizmo released this 30 Oct 01:11

winuse 0.2.4 answers the feedback from driving Java Swing apps: get_table reads Swing tables, a Java window the bridge cannot read comes with a diagnosis that says where the connection stopped, the internal node limit of the Java tree is reported, and passwords can be typed without landing in the log.

Changes

  • get_table on Swing tables. A JTable is read through the bridge's table interface: the header row first, then every cell (boolean cells as true / false). max_rows caps the data rows; row_count and omitted_rows are reported for UIA grids as well, so an empty list is row_count: 0. A JTable is one Table node in the interactive tree (its cells no longer eat the node budget); scope get_ui_tree to the table ref to list the cells.
  • Bridge diagnostics. When a Java window cannot be read, get_ui_tree returns java_access_bridge_diagnostics next to the java_access_bridge reason: stage (client_unavailable, no_hello, handshake_failed, timeout, send_failed, no_answer, not_owned), jvm_pid, jvm_connected, bridge_module, wire_format, bitness, client_window, timeout_ms and connected_jvms with the last failed request of each. The reason names the JVM pid and the failed step instead of a generic "not responding"; winuse doctor prints the same reason. No window titles or element data are included.
  • Node limit flag. get_ui_tree reports node_limit_reached: true and node_limit: 5000 when the Java tree walk stopped at its internal bridge round-trip limit (previously only a log warning).
  • Secrets. get_ui_tree takes include_values: false (no element value is read, so field contents stay out of the result and the log). set_text, type_text, paste_text and clipboard_set take secret: true: the text is used but the log, the journal and saved scenarios hold "***"; replaying such a step stops with secret text was not recorded until the scenario names the value as ${NAME}.

Scenarios recorded with 0.2.3 replay unchanged. The one behaviour change for existing clients: the cells of a Swing table are no longer listed in the default (interactive_only) tree.

Install

  1. Install the .NET 10 runtime (or SDK).
  2. Unzip winuse-0.2.4-win-x64.zip into a folder.
  3. Register with Claude Code: claude mcp add winuse -- <folder>\winuse.exe --mcp
  4. Set JEV_API_KEY, or CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, as user environment variables, then run winuse doctor.

Upgrading from 0.2.3: unzip over the old folder and restart the AI client.

Known issues

The bridge reports no position for a Swing table cell, so a cell listed in a scoped tree carries the table's rectangle. Unchanged from 0.2.3: a JRE without the Java side of the bridge cannot be read; type_text with Japanese text can be garbled under the Japanese IME (intermittent).

Full changelog: CHANGELOG.md

winuse 0.2.3

Choose a tag to compare

@straygizmo straygizmo released this 29 Oct 22:40

winuse 0.2.3 closes the ten usability issues filed against 0.2.2 (#9 to #18): modal dialogs and fresh frames in screenshots, an honest window_close, a title regex that survives SPA re-titling, and new tools for waiting, the clipboard, window-relative input and filtered UI trees.

Changes

  • Dialogs and stale frames in screenshots (#10, #11). A window is now copied from the screen whenever it or a dialog it owns is in the foreground, so Office save prompts and WebView2 overlays are in the picture and Chromium windows no longer hand out a PrintWindow frame that predates the last input. screenshot takes method (auto / screen / print) and settle_ms, and reports which method was used. get_ui_tree reads once more after a short wait when a dialog that just opened has no content yet.
  • window_close tells the truth (#16). It waits for the window to go away (timeout_ms, default 2 s) and returns closed: false with reason: "still_open" plus the foreground window (the save prompt) when the window is still there.
  • Title regex after wait_for (#9). A title that matches nothing is retried for 1.5 s before No window matches; the error and the wait_for description point at the win{n} ref as the reliable handle.
  • Primary monitor by default (#18). screenshot {target: "screen"} captures the primary monitor at origin (0,0); the former whole-desktop image is target: "virtual"; monitor: <index> picks one, and screen captures report monitors with rect, work area and primary flag.
  • sleep {ms} and wait_for {condition: "time"} (#12).
  • Clipboard tools (#13). clipboard_get, clipboard_set, clipboard_set_image (image file under the allowed roots, put on the clipboard as CF_DIB plus PNG), paste_text and paste_image (set the clipboard, press ctrl+v, restore the previous text).
  • Window-relative input (#14, #15). click, hover, scroll and drag take window: the window is activated first and x/y are relative to its rect, so a pixel of a window screenshot can be passed as is. type_text and press_keys take window too: the window is activated before the input and the call fails when it cannot take the foreground; the result reports where the input went.
  • Filtered, compact UI trees (#17). get_ui_tree takes control_type (comma-separated), name (regex), compact and max_nodes; matching nodes are hoisted, compact drops null / default fields and packs rect as x,y,w,h, and a truncated result reports omitted_nodes.

Scenarios recorded with 0.2.2 replay unchanged. The only behaviour change for existing clients is screenshot {target: "screen"}, which is now the primary monitor instead of the whole virtual screen.

Install

  1. Install the .NET 10 runtime (or SDK).
  2. Unzip winuse-0.2.3-win-x64.zip into a folder.
  3. Register with Claude Code: claude mcp add winuse -- <folder>\winuse.exe --mcp
  4. Set JEV_API_KEY, or CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, as user environment variables, then run winuse doctor.

Upgrading from 0.2.2: unzip over the old folder and restart the AI client.

Known issues

Unchanged from 0.2.2: get_table does not read Swing tables yet; a JRE without the Java side of the bridge cannot be read; type_text with Japanese text can be garbled under the Japanese IME (intermittent).

Full changelog: CHANGELOG.md

winuse 0.2.2

Choose a tag to compare

@straygizmo straygizmo released this 29 Oct 00:29

winuse 0.2.2 makes window refs stable across calls and reports the frame the user actually sees, so a client can track one window through a session and crop or record exactly it. It also ships the winuse-gate Claude Code plugin in the repository.

Changes

  • Stable win{n} refs. list_windows re-numbered its refs on every call, so a client could not look a window up again by the ref it had been given. A window now keeps its win{n} ref for the whole session: observing the same HWND again (list_windows, get_ui_tree, process_run, ...) returns the ref already handed out, with the stored locator refreshed to the current title. Element refs (u{n}, j{n}, ...) still number up per observation.
  • visible_rect. list_windows, get_element and the window object of get_ui_tree report the DWM extended frame bounds: the frame the user sees, without the invisible resize borders that rect includes. get_ui_tree's window object now also carries pid, rect and state.
  • winuse-gate plugin (plugins/winuse-gate, listed in .claude-plugin/marketplace.json). Hooks that block Claude's turn end once per change, and deny git commit, while UI files changed in the session have no passing winuse assertion, plus the winuse-e2e skill that tells Claude how to verify. Configured per project with .claude/winuse-gate.json. Install with /plugin marketplace add straygizmo/winuse then /plugin install winuse-gate@winuse.

Scenarios recorded with 0.2.1 replay unchanged.

Install

  1. Install the .NET 10 runtime (or SDK).
  2. Unzip winuse-0.2.2-win-x64.zip into a folder.
  3. Register with Claude Code: claude mcp add winuse -- <folder>\winuse.exe --mcp
  4. Set JEV_API_KEY, or CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, as user environment variables, then run winuse doctor.

Upgrading from 0.2.1: unzip over the old folder and restart the AI client.

Known issues

Unchanged from 0.2.1: get_table does not read Swing tables yet; a JRE without the Java side of the bridge cannot be read; type_text with Japanese text can be garbled under the Japanese IME (intermittent).

Full changelog: CHANGELOG.md

winuse 0.2.1

Choose a tag to compare

@straygizmo straygizmo released this 23 Oct 10:24

winuse 0.2.1 is a small follow-up to 0.2.0: every MCP tool now declares its annotation hints, so MCP hosts can tell at a glance which tools only observe and which can change or destroy something.

Changes

  • Tool annotations on all 48 tools. Every tool declares readOnlyHint, destructiveHint, idempotentHint and openWorldHint explicitly. Hosts that confirm before destructive or open-world calls (Claude Code, Codex CLI, Copilot CLI, ...) get a real answer per tool instead of a default.
    • Tools that act on the live desktop are open-world; where a single call can trigger anything in the target app (act, click, drag, type_text, press_keys, invoke, window_close, process_run, process_kill, scenario_run) they are destructive.
    • File tools stay inside the allowed roots and are closed-world; write_text, copy, move, delete, unzip and scenario_save are destructive because they can replace existing files.
    • Observation, find / check, wait_for and the assert_* tools are read-only.

No behaviour of the tools themselves changed. Scenarios recorded with 0.2.0 replay unchanged.

Install

  1. Install the .NET 10 runtime (or SDK).
  2. Unzip winuse-0.2.1-win-x64.zip into a folder.
  3. Register with Claude Code: claude mcp add winuse -- <folder>\winuse.exe --mcp
  4. Set JEV_API_KEY, or CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, as user environment variables, then run winuse doctor.

Upgrading from 0.2.0: unzip over the old folder and restart the AI client.

Known issues

Unchanged from 0.2.0: get_table does not read Swing tables yet; a JRE without the Java side of the bridge cannot be read; type_text with Japanese text can be garbled under the Japanese IME (intermittent).

Full changelog: CHANGELOG.md

winuse 0.2.0

Choose a tag to compare

@straygizmo straygizmo released this 22 Oct 08:10

winuse 0.2.0 adds Java Swing support: Swing windows are read and operated through Java Access Bridge like UI Automation apps, and winuse speaks the bridge's wire protocol itself, so 32-bit Java 7/8 JREs that ship only the legacy bridge work too.

Highlights

  • Java Swing through Java Access Bridge. Swing windows (SunAwt*) are read into the same element model as UIA (j{n} refs), so get_ui_tree, act / find / check, click, invoke, set_text, set_checked, select_item, get_text, get_list_items, assert_*, wait_for and scenario replay work on them. Menu items are listed and invokable while their menu is closed.
  • Built-in bridge client, no DLL. winuse talks the Java Access Bridge wire protocol directly (hidden client window, hello handshake, one memory-mapped file per JVM). Both wire formats are spoken: the wide one of JavaAccessBridge-32/64.dll and Java 9+'s javaaccessbridge.dll, and the legacy one of the suffix-less JavaAccessBridge.dll that 32-bit Java 7/8 JREs ship. Several JVMs of mixed formats at once. Tested on Temurin 21 x64, Temurin 8 x86 and Temurin 8 x86 on its legacy bridge, and confirmed on a 32-bit Java 7 application.
  • Enabling accessibility without touching the JRE. Apps started with process_run get JAVA_TOOL_OPTIONS=-Djavax.accessibility.assistive_technologies=com.sun.java.accessibility.AccessBridge (WINUSE_JAVA_ACCESSIBILITY=off disables it); for apps started any other way, winuse jab enable|disable|status manages %USERPROFILE%\.accessibility.properties.
  • Diagnostics. winuse doctor reports the client window and the JVMs connected to it, the user-profile enablement, and every Java window with its JVM: jvm.dll path and version, bitness, which JavaAccessBridge*.dll it loaded and its wire format, the Java and bridge versions the JVM reports, and whether the bridge answers. When a Java window cannot be read, get_ui_tree returns java_access_bridge with the reason and act reports no elements (java access bridge: ...); the window then falls back to visual grounding.
  • Settings: WINUSE_JAB (auto / off), WINUSE_JAVA_ACCESSIBILITY (on / off).

Install

  1. Install the .NET 10 runtime (or SDK).
  2. Unzip winuse-0.2.0-win-x64.zip into a folder.
  3. Register with Claude Code: claude mcp add winuse -- <folder>\winuse.exe --mcp
  4. Set JEV_API_KEY, or CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, as user environment variables, then run winuse doctor.

Upgrading from 0.1.0: unzip over the old folder. Java apps need accessibility enabled in their JVM when they start (see above); restart them after winuse jab enable.

Known issues

  • get_table does not read Swing tables yet (get_table is not supported for Java elements yet).
  • A JRE without the Java side of the bridge (trimmed Java 8 without JavaAccessBridge-32.dll / access-bridge-32.jar, or a jlink image without jdk.accessibility) cannot be read, and a JVM on such a JRE fails to start when accessibility is requested (AWTError: Assistive Technology not found): set WINUSE_JAVA_ACCESSIBILITY=off for apps on such a JRE and do not use winuse jab enable. doctor reports the missing files. A Java app running elevated or as another user is out of reach.
  • type_text with Japanese text can be garbled under the Japanese IME (intermittent, under investigation).

Full changelog: CHANGELOG.md

winuse 0.1.0

Choose a tag to compare

@straygizmo straygizmo released this 20 Oct 13:57

First release of winuse, an MCP server and CLI that lets an AI observe and operate Windows desktop apps.

Highlights

  • MCP server over stdio (winuse --mcp) with 48 tools: observe (screenshot, UI Automation tree, WebView2 DOM via Playwright over CDP), intent (act, find, check), input, element, window, wait, process, file, assert and scenario tools.
  • Scenario replay without AI (winuse run, scenario_run): recorded locators resolve deterministically; --heal re-grounds act steps whose element is gone.
  • Two decision models: TypeSafe Jev (JEV_API_KEY) or Cloudflare Clef on Workers AI (CLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_API_TOKEN), chosen automatically or forced with WINUSE_DECISION_PROVIDER.
  • Visual grounding for windows without UI elements (VM consoles, emulators, VNC): act / find / check work from a screenshot, return pt{n} refs, and replay from a window-relative point (WINUSE_SCREENSHOTS, WINUSE_VISUAL_LOCATOR).
  • winuse doctor reports the decision model, keys, endpoint, probe, UIA, WebView2 and the Playwright driver; winuse --version prints the version.

Install

  1. Install the .NET 10 runtime (or SDK).
  2. Unzip winuse-0.1.0-win-x64.zip into a folder.
  3. Register with Claude Code: claude mcp add winuse -- <folder>\winuse.exe --mcp
  4. Set JEV_API_KEY, or CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, as user environment variables, then run winuse doctor.

Known issues

  • type_text with Japanese text can be garbled under the Japanese IME (intermittent, under investigation).
  • Clef and visual grounding are covered by unit tests with a fake model; they have not yet been exercised against a live Cloudflare account or a real VM window.

Full changelog: CHANGELOG.md