Skip to content

feat(cua-driver-rs/windows): cua-driver-uia worker for UWP automation (uiAccess prototype)#1604

Merged
f-trycua merged 1 commit into
mainfrom
feat/cua-driver-rs-windows-uiaccess-worker
May 20, 2026
Merged

feat(cua-driver-rs/windows): cua-driver-uia worker for UWP automation (uiAccess prototype)#1604
f-trycua merged 1 commit into
mainfrom
feat/cua-driver-rs-windows-uiaccess-worker

Conversation

@f-trycua
Copy link
Copy Markdown
Collaborator

@f-trycua f-trycua commented May 20, 2026

Summary

Adds a Windows-only sibling binary, cua-driver-uia.exe, that runs at UIAccess integrity to bypass UIPI for UWP apps. The main cua-driver.exe (CLI + MCP) stays a normal asInvoker PE so all existing CreateProcess-based entrypoints keep working — UWP-blocked tool calls transparently route through the sibling worker over its own named pipe when present.

Status: prototype. Production needs an EV cert to sign cua-driver-uia.exe (#1602). Without trust, the worker fails to elevate on default-policy machines and UWP automation falls back to the existing Medium-integrity (UIPI-blocked) behavior. The main binary is fully unaffected — it never required uiAccess.

Architecture

Component Integrity Pipe Launched via
cua-driver.exe serve Medium \\.\pipe\cua-driver autostart Scheduled Task (CreateProcess)
cua-driver-uia.exe (auto-spawned by serve) UIAccess \\.\pipe\cua-driver-uia ShellExecute child of serve

CLI (cua-driver call X) and MCP stdio (cua-driver mcp) both prefer the uia pipe when listening, with byte-identical JSON protocol so the client doesn't need to know which one it's talking to.

Empirical evidence (Windows 11 VM, self-signed cert + EnableSecureUIAPaths=0)

  • element_count = 30 for modern Notepad's UIA tree via uia worker (vs 0 in-process Medium integrity → UIPI blocking)
  • type_text via UIA ValuePattern.SetValue across UIPI returns 0x00000000 (success)
  • MCP stdio routing confirmed end-to-end: cua-driver mcp over JSON-RPC → daemon proxy → uia pipe → 30-element response
  • Auto-spawn confirmed: cua-driver autostart kick fires cua-driver-serve → serve ShellExecutes sibling → worker process at TokenUIAccess=1 in Session 2

Calculator stays unreachable — architectural limit (#1601).

Files

New: crates/cua-driver-uia/ — 4 files, ~200 LOC. Hosts the platform-windows tool registry over a named pipe. Embeds uiAccess manifest via embed-manifest (no mt.exe / rc.exe needed).

Edited:

  • crates/cua-driver/src/cli.rs — pipe-preference for run_call, should_use_daemon_proxy, run_mcp_via_daemon_proxy
  • crates/cua-driver/src/serve.rsmaybe_spawn_uia_worker() ShellExecutes the sibling at startup
  • crates/cua-driver/src/autostart.rsdisable cleans up legacy second-task entries for upgrade idempotency
  • libs/cua-driver/scripts/install.ps1 — copies uia binary when present in release stage
  • .github/workflows/cd-rust-cua-driver.yml — builds both binaries, zips both
  • docs/.../autostart.mdx — new "UWP automation and the uiAccess worker" section

What this does NOT include (deferred to #1602)

Test plan

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Windows support for automating modern UWP/XAML applications using an elevated worker component that enables UIAccess-level automation.
    • Enhanced the Windows driver to intelligently route tool calls through the new automation worker when available.
  • Documentation

    • Added comprehensive guide explaining Windows UIAccess automation capabilities, supported scenarios, limitations, and requirements for proper setup.

Review Change Stack

… (uiAccess prototype)

Adds a Windows-only sibling binary, `cua-driver-uia.exe`, that runs at
UIAccess integrity to bypass UIPI for UWP apps (modern Notepad, Settings,
File Explorer). The main `cua-driver.exe` (CLI + MCP) stays a normal
`asInvoker` PE so all existing CLI / stdio MCP entrypoints keep working
via CreateProcess — UWP-blocked tool calls just transparently route through
the sibling worker over its own named pipe when present.

This is a prototype: production rollout still needs an EV cert to sign
`cua-driver-uia.exe` (tracked in #1602). Without a trusted signature the
worker fails to elevate on default-policy machines and UWP tool calls
fall back to the Medium-integrity path (UIPI blocking, same as today).
The main binary is unaffected — it never required uiAccess.

## What changed

- `crates/cua-driver-uia/` — new crate (~200 LOC). Tiny PowerShell-style
  pipe server hosting the same `platform_windows::register_tools()` registry
  over `\\.\pipe\cua-driver-uia`. Build script embeds a manifest with
  `requestedExecutionLevel level="asInvoker" uiAccess="true"` via
  `embed-manifest` (no `mt.exe` / `rc.exe` required).
- `cli.rs` — `run_call`, `should_use_daemon_proxy`, and
  `run_mcp_via_daemon_proxy` all prefer `\\.\pipe\cua-driver-uia` on
  Windows when it's listening, falling back to the main daemon pipe.
  The CLI / MCP transport doesn't need to know which one it's talking to:
  both pipes speak identical line-delimited JSON.
- `serve.rs` — when `cua-driver serve` starts, it auto-spawns the sibling
  worker via `ShellExecute` (PowerShell wrapper, no new deps). This works
  because the spawn originates from a Session-2 process with an
  interactive desktop attached — Task Scheduler's own action paths fail
  with ERROR_NOT_LOGGED_ON for uiAccess binaries.
- `autostart.rs` — single task only (`cua-driver-serve`); the worker is
  serve's child, not a separately-scheduled task. Old standalone
  `cua-driver-uia` task is best-effort-cleaned-up by `disable` for
  upgrade idempotency.
- `install.ps1` — copies `cua-driver-uia.exe` from the release stage dir
  when present (older releases without the worker still install cleanly).
- CD workflow — builds both binaries and zips both into the Windows
  release archive.
- Docs — new "UWP automation and the uiAccess worker" section in
  `autostart.mdx` covering when the worker kicks in, what it unlocks
  (modern Notepad UIA tree, SendInput across UIPI), what it doesn't fix
  (Calculator-class DirectComposition surfaces — #1601), and the signing
  prerequisite for production.

## Empirical evidence (Windows 11 VM, self-signed cert + EnableSecureUIAPaths=0)

| Scenario | element_count | Result |
|---|---|---|
| Modern Notepad UIA tree, in-process Medium integrity | 0 | UIPI blocking |
| Modern Notepad UIA tree, via uia worker (TokenUIAccess=1) | 30 | Full tree |
| `type_text` via UIA `ValuePattern.SetValue` across UIPI | — | `0x00000000` (success) |
| MCP stdio (`cua-driver mcp`) routed through uia pipe | 30 | Routing confirmed end-to-end |

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment May 20, 2026 1:11pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 20, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 79cb2bc4-423f-4a17-841a-19f23da3ce68

📥 Commits

Reviewing files that changed from the base of the PR and between f83c43c and 222af2b.

⛔ Files ignored due to path filters (1)
  • libs/cua-driver-rs/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • .github/workflows/cd-rust-cua-driver.yml
  • docs/content/docs/cua-driver/guide/getting-started/autostart.mdx
  • libs/cua-driver-rs/Cargo.toml
  • libs/cua-driver-rs/crates/cua-driver-uia/Cargo.toml
  • libs/cua-driver-rs/crates/cua-driver-uia/build.rs
  • libs/cua-driver-rs/crates/cua-driver-uia/cua-driver-uia.manifest
  • libs/cua-driver-rs/crates/cua-driver-uia/src/main.rs
  • libs/cua-driver-rs/crates/cua-driver/src/autostart.rs
  • libs/cua-driver-rs/crates/cua-driver/src/cli.rs
  • libs/cua-driver-rs/crates/cua-driver/src/serve.rs
  • libs/cua-driver/scripts/install.ps1

📝 Walkthrough

Walkthrough

This PR introduces a Windows UIAccess-elevated worker binary (cua-driver-uia) to enable automation of modern UWP/XAML applications. The worker runs as a separate process with elevated privilege, listens on a named pipe for JSON requests, and forwards tool calls to a registry. The daemon spawns it on startup, and the CLI automatically discovers and routes tool calls through it when available.

Changes

UIAccess Worker Implementation and Integration

Layer / File(s) Summary
New cua-driver-uia crate definition
libs/cua-driver-rs/Cargo.toml, libs/cua-driver-rs/crates/cua-driver-uia/Cargo.toml, build.rs, cua-driver-uia.manifest
New workspace crate with Windows-only async dependencies, manifest declaring UIAccess elevation with asInvoker level, and build-time manifest embedding.
Named-pipe worker server protocol and request handling
libs/cua-driver-rs/crates/cua-driver-uia/src/main.rs
Windows named-pipe server listening at \\.\pipe\cua-driver-uia handling JSON-RPC-like requests (list, describe, call, shutdown); routes requests to tool registry and returns structured JSON responses with tool metadata and invocation results.
Daemon worker spawning and pipe path export
libs/cua-driver-rs/crates/cua-driver/src/serve.rs
Exports default_uia_pipe_path() for pipe path lookup, implements maybe_spawn_uia_worker() to locate and spawn the sibling binary via PowerShell ShellExecute on daemon startup (non-blocking, ignores failures).
CLI proxy selection to prefer worker pipe on Windows
libs/cua-driver-rs/crates/cua-driver/src/cli.rs
Updates should_use_daemon_proxy, run_mcp_via_daemon_proxy, and run_call to detect and prefer the UIAccess worker named-pipe when listening, falling back to the regular daemon socket.
CI/CD and installer integration
.github/workflows/cd-rust-cua-driver.yml, libs/cua-driver/scripts/install.ps1
Windows CI builds and packages both cua-driver.exe and cua-driver-uia.exe together in release zips; Windows installer optionally copies the worker binary when present.
Autostart lifecycle and user documentation
libs/cua-driver-rs/crates/cua-driver/src/autostart.rs, docs/content/docs/cua-driver/guide/getting-started/autostart.mdx
Clarifies that the UIAccess worker is not registered as a separate scheduled task, adds legacy task cleanup in disable logic, and provides user docs describing UWP automation capabilities, limitations (e.g., cross-session injection), and Authenticode signing prerequisites.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • trycua/cua#1602: Implements the Windows uiAccess-enabled binary and manifest embedding to enable UIA/SendInput, the same core capability being built here.
  • trycua/cua#1601: Documents UIPI/uiAccess gating that the UIAccess worker directly addresses by spawning an elevated sibling with uiAccess named-pipe routing.

Possibly related PRs

  • trycua/cua#1580: Modifies cua-driver/src/cli.rs daemon-proxy selection logic; this PR extends that pattern to route through the UIAccess worker pipe.
  • trycua/cua#1550: Introduced scheduled-task autostart logic in autostart.rs; this PR extends it with cleanup of legacy cua-driver-uia scheduled tasks.
  • trycua/cua#1530: Established the macOS TCC proxy routing pattern in cli.rs that this PR reuses for Windows UIAccess worker detection.

Poem

A rabbit hops with privilege high,
On Windows paths where UIAccess flies,
A worker spawned, a pipe so keen,
Modern apps now dance between
The daemon and the UWP screen! 🐰✨

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cua-driver-rs-windows-uiaccess-worker

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant