Live, end-to-end testing of a built Windows .exe inside the agent-os Windows 11 VM: transfer
the build in, launch it, drive every feature, watch for crashes/hangs/error dialogs, review UI/UX,
and emit a structured works/doesn't-work report. Companion to web-app-testing and
android-app-testing — all three share one report format (references/report-format.md).
Drives the agent-os VM (container agent-os-win11, dockur/windows on dookie) through the
agent-os_windows-mcp upstream on the Lab gateway. Builds on the agent-os skill (which is the
general VM driver) but adds the testing harness: build transfer, feature enumeration, failure
taxonomy, evidence pipeline, and the report.
When to use vs. neighbors
- This skill — a test pass + report over a desktop app's features and UX.
agent-os— general driving of the Windows VM (install software, run PowerShell, one-off tasks).nircmd— the user's PERSONAL Windows on steamy, not the sandbox. Never target steamy here.
⚠️ Destructive-action gate — read first
Every drive action (PowerShell, Click, Type, App, Process, …) is destructive=true and
gated by the gateway. An authenticated admin (lab/lab:admin scope) passes — this was fixed in
lab commit e87940c0. If drive calls return confirmation_required: "...destructive=true...", the
gateway predates the fix; rebuild + redeploy (see references/windows-mcp-calls.md). Read-only
Screenshot/Snapshot are never gated, so a UI/UX review works even if the gate isn't lifted.
Prerequisites
- The agent-os VM running on dookie (the skill's preflight starts it if absent).
- The Lab gateway reachable with an execute-capable scope (for drive actions).
- The built
.exe/installer on this host (or a URL the guest can fetch).
Workflow
- Preflight.
- VM up?
ssh dookie 'docker ps --format "{{.Names}}" | grep agent-os-win11'. If absent:ssh dookie 'cd /home/jmagar/compose/windows && docker compose up -d'(boots existing install, ~5 min cold; Windows-MCP auto-starts via an in-guest scheduled task). - MCP ready? Call
Screenshot {}— an image back means ready. (Do NOT TCP-probe :8765, false negative.) - Drive gate? Do one cheap destructive call (
Process {mode:"list"}) — if it returns data, the gate is open; ifconfirmation_required, fix the gateway first. - Create run dir
~/.agents/docs/sessions/<app>-desktop-test/run_<id>/.
- VM up?
- Transfer the build into the VM (see
references/windows-mcp-calls.md): HTTP-pull via PowerShellInvoke-WebRequest(verified reachable) or SCP to the agent-os guest (scp ... agent-os:/ host forwardtootie:2222).Unblock-Filethe copied binary; pre-create a firewall allow rule if it binds a port. - Launch. Prefer
PowerShell {command:"Start-Process 'C:\\...\\app.exe'; ...return PID"}(Start-menuApp {name}is unreliable for arbitrary binaries). Confirm a PID came back. - Wait for ready, map controls.
WaitFor {condition:"active_window", window_name:"<title>"}(short timeout in a retry loop), thenSnapshot {}— enumerate menus, buttons, tabs, fields from the UI Automation tree. Build the feature checklist (merge with any user spec). Writeplan.md. - Exercise each feature — the act-by-label loop:
Snapshot→ pick the target element's integerlabel→Click {label}/Type {label, text}→Snapshotagain (UI changed, ids are stale) → repeat.Screenshotbetween steps for evidence (doesn't invalidate ids). UseShortcutfor keyboard ops.Type/ClickREQUIRElocorlabel— there is no implicit-focus typing. - Detect failures after each action:
- Crash/exit —
Process {mode:"list", name}shows the PID gone; checkGet-WinEvent -LogName Applicationfor Error/Critical. → FAIL. - Hang —
WaitFortimes out /Snapshotshows "(Not Responding)". → FAIL. - Error dialog —
Snapshotsurfaces dialog text; screenshot it. → FAIL/PARTIAL. - Wrong output / no feedback — expected UI change didn't happen. → PARTIAL/FAIL.
- Can't reach — needs creds/data/license the run lacks. → BLOCKED.
- Crash/exit —
- Reset between independent features —
Process {mode:"kill", name}then relaunch, so input/ mode state doesn't leak across tests. - UX/a11y pass — score the report-format rubric from snapshots + screenshots. Interactive elements with no accessible name in the UIA tree = accessibility findings.
- Write the report →
report.md+result.jsonin the run dir, perreferences/report-format.md. Save screenshots toevidence/and index them.
Gotchas (live-validated)
- Prefer
PowerShell Start-ProcessoverApp {name}to launch an arbitrary.exe. - Re-
Snapshotafter every UI change —labelids are valid only against the latest Snapshot. Snapshotoutput overflows the Code Mode envelope (~24KB) — filter/slice the tree text in the sandbox before returning; don't dump the whole tree.- Custom-rendered apps (GPUI, some Electron/canvas) expose little to UI Automation →
Snapshotis sparse; fall back toScreenshot+ coordinate clicks +SendKeys, and flag reduced confidence. - MCP calls can time out ~120s — chunk long operations; use short
WaitForin a retry loop. - Security prompts stall unattended runs —
Unblock-File,SEE_MASK_NOZONECHECKS=1, pre-create firewall rules before expecting hands-off captures.
References
references/windows-mcp-calls.md— verified tool names, params, call patterns, the destructive gate, build-transfer recipes, evidence capture.references/report-format.md— shared cross-platform report spec, run-dir layout, verdicts.