Local VM UI testing
Run PowerToys .Next UI tests in a persistent, interactive Windows VM while keeping product and test
execution off the host. Use this skill as the execution complement to
ui-tests-migration. Restore the baseline checkpoint or recreate the
guest when clean-profile behavior must be validated.
The guest is a Hyper-V virtual machine. Nothing runs nested, so the same scaffold works on x64 and on
Windows on ARM, where nested virtualization is unavailable to any Linux-hosted emulator.
A module is done when the full suite is green on Windows 10 and on Windows 11, in two
separate VMs. Run Windows 10 Enterprise LTSC 2021 first because it gives the fastest feedback, then
run the same unfiltered suite on Windows 11. Differences in the shell, compositor, theming, and
timing break tests that contain nothing Windows 11-specific, and those are exactly the failures
worth catching locally instead of in CI. On a Windows on ARM host, Windows 11 ARM64 is the only
practical guest; run it with -Platform ARM64 and get the Windows 10 half from an x64 host.
Start guests with the default resource profile: 4 vCPUs and 8 GB RAM. Get the target suite fully
green before lowering resources with the Constrained profile (1 vCPU and 4 GB RAM).
How the host reaches the guest
| Concern |
Mechanism |
| Control channel |
PowerShell Direct over VMBus. No listener, port, certificate, or firewall rule in the guest. |
| Bulk payload |
Copy-VMFile over the Guest Service Interface, ~82 MB/s. The session copy is a fallback and stalls on archives near a gigabyte. |
| Exchange |
Guest-local C:\PowerToysUiTestExchange\<name>, mirrored by the controller. The host never shares a folder with the guest. |
| Host privilege |
Hyper-V access: an elevated shell, or an account in the local Hyper-V Administrators group. Creating a guest additionally requires real elevation. |
| Console |
scripts/Get-VmConsoleImage.ps1 renders the framebuffer to PNG, so an agent can read boot and desktop state without VMConnect. |
When to use this skill
Use it when asked to:
- Create or migrate UI tests and iterate repeatedly without reprovisioning Windows each run.
- Validate Explorer, hotkey, WebView2, shell-extension, foreground, or composed-visual behavior in a
real interactive desktop.
- Run tests as a true standard user while retaining a separate administrator control channel.
- Reuse unchanged PowerToys, winappcli, and .NET payloads and refresh only changed archives.
- Keep a reproducible local VM baseline with optional .NET 10, WebView2, diagnostics, or
msvsmon.
- Collect durable
status.json, TRX, transcripts, logs, screenshots, and failure attachments.
- Compare revisions in one stable VM before confirming the result from a restored checkpoint.
Do not treat a persistent VM as proof of clean-profile behavior. Caches, registrations, settings, and
first-run state survive between runs. Restore the baseline checkpoint or recreate the VM when those
are the behavior under test.
Relationship to other UI-test skills
| Skill |
Owns |
ui-tests-migration |
Test design, project scaffolding, framework APIs, assertions, lifecycle, and CI stability. |
ui-tests-local-vm |
Fast persistent-VM setup, deployment, interactive execution, evidence export, and iteration. |
Do not modify stabilized tests merely to make the local VM green. First prove that the suite executes,
produces assertion-bearing TRX, and has a useful success rate. Classify environment-specific failures
separately unless the task explicitly asks for stabilization.
Guest OS policy
- Two guests, two full suites. Windows 10 Enterprise LTSC 2021 (build 19044/21H2, newer than the
Windows 10 20H2 baseline) and Windows 11. Both must be fully green before a module is done.
LTSC is not available through Fido;
-Source Fido -Windows 10 automates Microsoft's official
mobile-user-agent ISO page and is the practical public default. The public ISO/MCT images are too
old for .NET 10 CET, so Setup Dynamic Update must bring Win10 to 1904x.5007+ before the baseline.
Use licensed Microsoft subscription media for LTSC when available, and always record the edition,
ISO hash, and installed full build (references/setup.md §3).
- Windows 10 runs first: it is the faster loop and surfaces most defects. Windows 11 then runs the
same suite, unfiltered - not only the tests that look Windows 11-specific. A test with no
Windows 11 content can still fail there, which is the whole reason for the second pass.
- Narrow filters belong to iteration and diagnosis. They are never the evidence for the Windows 11
pass.
- Give each OS its own VM name,
vm.config.psd1, VHDX, checkpoints, and exchange. Never upgrade or
repurpose the Windows 10 guest into the Windows 11 guest; the two baselines must stay independent.
- Surfaces that exist only on Windows 11, such as the tier-1 Explorer context menu, need no special
handling: the full Windows 11 run already covers them.
- On a Windows on ARM host, use a Windows 11 ARM64 guest with
-Platform ARM64. Hyper-V does not
emulate a foreign architecture, so that host cannot supply the Windows 10 x64 pass - run it on an
x64 host and report both.
- A Windows 11 host requirement does not make Windows 11 the first guest target.
-Platform is not cosmetic: it flows to the guest as the platform environment variable, names
visual baselines, and marks the run as pipeline-like. Use only x64Win10, x64Win11, or ARM64.
Required reads
Read only what the task needs:
- references/setup.md - host requirements, scaffolding, media acquisition,
unattended guest creation, credentials, standard-user desktop, and checkpoint baselines.
- references/agentic-loop.md - payload contract, controller usage,
focused-to-suite iteration, evidence, verdicts, and reset strategy.
- references/customization.md - persistent image customization,
.NET 10, WebView2,
msvsmon, resource profiles, and golden-baseline guidance.
- references/troubleshooting.md - guest creation, PowerShell Direct,
interactive session, scheduled-task, focus, timeout, and export failures.
- references/shell-extensions-and-signing.md - read
for any shell-extension module (context menu, preview/thumbnail handler). Why unsigned CI PR
builds cannot register a sparse MSIX (0% on CI), classic (registry-COM, signing-free) vs modern
(sparse-MSIX) surfaces, Debug vs Release/
NDEBUG gating, runtime detection, and reproducing CI's
classic scenario on a local signed VM.
- ui-tests-migration - required whenever test code or framework
behavior is being created, migrated, or stabilized.
Default agentic cycle
flowchart LR
A[Design or edit test] --> B[Host build]
B --> C[Package changed payload]
C --> D[Start or reuse VM]
D --> E[Probe standard-user desktop]
E --> F[Run focused test]
F --> G[Export status TRX evidence]
G --> H{Need test change?}
H -- Yes --> A
H -- No --> I[Run full suite on Win10]
I --> J[Run same full suite on Win11]
J --> K{Both fully green?}
K -- No --> A
K -- Yes --> L[Optional checkpoint restore]
Create and maintain this task list:
- [ ] 0. Verify host setup FIRST: `Initialize-LocalVmHost.ps1 -VmRoot <root> -CheckOnly`. If it reports
IsReady=false, STOP and ask the user to run the elevated command it prints - Hyper-V group
membership, the DPAPI credential, and guest creation all need a human. Never autopilot past it
- [ ] 1. Read ui-tests-migration guidance for the target test surface
- [ ] 1a. Read the target module's dev docs — `doc/devdocs/modules/<module>.md` (search `doc/devdocs/`,
including `common/`, if the exact file is missing) — for development-cycle gotchas such as
Release/`NDEBUG` registration gating, signed sparse-MSIX context menus, and Explorer restarts,
so a module's registration/deployment requirements do not surface as opaque test failures.
For shell-extension modules also read references/shell-extensions-and-signing.md.
- [ ] 2. Scaffold or verify the local VM - references/setup.md
- [ ] 3. Build product and test projects on the host to exit code 0
- [ ] 4. Package a lean exchange and verify archive hashes
- [ ] 5. Run the controller with -PlanOnly and inspect its request/plan
- [ ] 6. Probe the non-admin interactive desktop before test execution
- [ ] 7. Run one focused test synchronously; keep the agent turn attached, read the controller
result's `.Failed` array (non-passed tests + first error line) instead of re-parsing TRX, and
use `scripts/Invoke-GuestScript.ps1` for guest-state inspection
- [ ] 8. Diagnose the first controlling failure without weakening assertions
- [ ] 9. Rebuild and rerun with -ReuseStagedPayload
- [ ] 10. Widen to the full module suite on Windows 10 and report pass rate/root-cause groups
- [ ] 11. Run the same full suite in the Windows 11 VM; both must be green before the module is done
- [ ] 12. Restore the baseline checkpoint for clean-profile confirmation when required
Quick start
Host setup is a one-time, human-only step: Hyper-V group membership, the DPAPI guest credential,
and guest creation all need elevation or a password. Check it before anything else - this needs no
elevation and changes nothing:
pwsh .github\skills\ui-tests-local-vm\scripts\Initialize-LocalVmHost.ps1 -VmRoot X:\PowerToysUiTestVm -CheckOnly
If it reports IsReady=false, stop and ask the user to run the elevated command it prints (see
references/setup.md §0). Otherwise scaffold
the VM directory outside the repository:
pwsh .github\skills\ui-tests-local-vm\scripts\Initialize-LocalVm.ps1 `
-DestinationRoot X:\PowerToysUiTestVm
The scaffold and its shared exchange can live on any volume, including a Dev Drive. Only the VHDX
and VM configuration paths, set separately in vm.config.psd1, should point at NTFS.
Follow references/setup.md to write the untracked vm.config.psd1, save the
administrator credential with Windows DPAPI, obtain install media, and create the guest with
New-UiTestVm.ps1. Then stage the archives described in
references/agentic-loop.md and run:
pwsh .github\skills\ui-tests-local-vm\scripts\Invoke-LocalVmUiTest.ps1 `
-VmName PowerToysUiTest-Win10 `
-VmRoot X:\PowerToysUiTestVm `
-ExchangeRoot X:\PowerToysUiTestVm\shared\PowerToysUiTests\MyModule `
-TestExecutable MyModule.UITests.Next.exe `
-Filter 'Name=MyModule.FocusedTest' `
-Platform x64Win10 `
-BuildLabel (git rev-parse HEAD) `
-SuiteTimeout 15m `
-TimeoutMinutes 25 `
-ReuseStagedPayload
The controller starts the VM if needed, requests automatic host sleep prevention, verifies the
interactive standard-user desktop, dispatches the guest runner, and waits synchronously for matching
status.json. It reports whether sleep prevention succeeded, fails early if the guest task never
starts or exits without status, summarizes TRX, and leaves the persistent VM running by default.
Non-negotiable rules
- Complete host setup before anything else and never autopilot around it. Hyper-V group
membership, the DPAPI guest credential, and guest creation are human-only: two need elevation that
no tool call can approve, one needs a password that must never reach a model.
Initialize-LocalVmHost.ps1 performs all three; agents run it -CheckOnly, and on
IsReady=false report BLOCKED, print the elevated command it emits, and wait. Do not ask for a
password, do not substitute a weaker channel, do not proceed on a partial setup.
Invoke-LocalVmUiTest.ps1 enforces the same check.
- Keep the guest's VHDX and VM configuration on NTFS. On this project's host, keeping them on a Dev
Drive wedged the VM management service twice -
vmms at 0% CPU, even Get-VM hanging, host reboot
to recover - and moving to NTFS fixed it. This is an observation on one host, not a property of
ReFS: Hyper-V on plain ReFS is supported, so -AllowReFsVolume overrides the default refusal. The
scaffold and the exchange are unaffected and run fine on a Dev Drive.
- Build on the host; run PowerToys and tests only in the VM when host execution is prohibited.
- Invoke every focused, full-suite, and constrained controller run synchronously. Keep the active
agent turn attached until the controller returns matching status/TRX evidence; never background
the controller or end the turn while it runs.
- Finish on two green full suites: Windows 10 and Windows 11, in separate VMs. Windows 10 runs first
for speed; Windows 11 runs the same unfiltered suite, never a Win11-only subset. Narrow filters are
for iteration, not for sign-off. On a Windows on ARM host the ARM64 Windows 11 guest covers the
Windows 11 half and the Windows 10 half needs an x64 host.
- Establish a fully green correctness baseline with the default (4 vCPU / 8 GB) resources before
running the same tests under
Constrained (1 vCPU / 4 GB) resources.
- Keep VM files and writable exchange folders outside the repository.
- Keep the guest's default inbound network posture. The control channel does not need connectivity,
so do not enable remoting, open ports, or attach the guest to a routable network for test dispatch.
- Use a DPAPI-protected credential file. Never put credentials in prompts, scripts, request JSON,
unattend files kept after install, source control, or command-line arguments.
- Run UI tests in an already logged-on standard-user desktop, never in session 0 or as
SYSTEM.
- Keep a separate administrator account only for VM control and scheduled-task registration.
- Verify user, token integrity, Explorer presence, session ID, and display size before tests.
- Run product/tests from guest-local storage under
C:\PowerToysUiTestRun.
- Use PowerShell 7 for interactive probe/test scheduled tasks. PowerShell Direct and OEM bootstrap
remain PS5.1-compatible by design; do not enable a remoting endpoint merely to use PS7.
- Reuse payloads by per-component hashes; refresh only changed tests/product/tools.
- Preserve assertions and visual thresholds. Classify VM-specific failures from evidence.
- Always parse TRX and require
total > 0 plus executed == total. A process exit code alone cannot
distinguish assertions, skipped/inconclusive tests, zero tests, timeout, or infrastructure failure.
- Keep the VM after normal runs for iteration. Stop it explicitly when idle; delete its VHDX only for
an intentional baseline reset.
- The controller requests automatic host sleep prevention and reports
HostSleepPrevented; failure
is a warning. It cannot override manual sleep, lid-close policy, reboot, shutdown, or power loss.
- Final clean-profile claims require a restored baseline checkpoint or a recreated guest. Restore with
Reset-LocalVm.ps1 -Restore.
1---2name: ui-tests-local-vm3description: Set up and run PowerToys UITest.Next suites in persistent local Hyper-V VMs driven over PowerShell Direct, created unattended from Windows install media. A module is done only when the full suite is green on both Windows 10 LTSC and Windows 11, in separate VMs, plus Windows 11 ARM64 on Windows on ARM hosts. Use for fast agentic UI-test iteration, reusable interactive desktops, non-admin scenarios, payload staging and refresh, evidence export, VM customization, checkpoint-based clean baselines, or hosts without nested virtualization. Keywords: Hyper-V, local VM, virtual machine, PowerShell Direct, Copy-VMFile, VMBus, checkpoint, unattend, autounattend, ISO, Windows 10, Windows 11, ARM64, Windows on ARM, UI tests, UITest.Next, winappcli, TRX.4license: MIT5---6
7# Local VM UI testing
8
9Run PowerToys `.Next` UI tests in a persistent, interactive Windows VM while keeping product and test
10execution off the host. Use this skill as the execution complement to
11[ui-tests-migration](../ui-tests-migration/SKILL.md). Restore the baseline checkpoint or recreate the
12guest when clean-profile behavior must be validated.
13
14The guest is a Hyper-V virtual machine. Nothing runs nested, so the same scaffold works on x64 and on
15Windows on ARM, where nested virtualization is unavailable to any Linux-hosted emulator.
16
17A module is done when the **full** suite is green on Windows 10 **and** on Windows 11, in two
18separate VMs. Run Windows 10 Enterprise LTSC 2021 first because it gives the fastest feedback, then
19run the same unfiltered suite on Windows 11. Differences in the shell, compositor, theming, and
20timing break tests that contain nothing Windows 11-specific, and those are exactly the failures
21worth catching locally instead of in CI. On a Windows on ARM host, Windows 11 ARM64 is the only
22practical guest; run it with `-Platform ARM64` and get the Windows 10 half from an x64 host.
23
24Start guests with the default resource profile: 4 vCPUs and 8 GB RAM. Get the target suite fully
25green before lowering resources with the `Constrained` profile (1 vCPU and 4 GB RAM).
26
27## How the host reaches the guest
28
29| Concern | Mechanism |
30|---|---|
31| Control channel | PowerShell Direct over VMBus. No listener, port, certificate, or firewall rule in the guest. |
32| Bulk payload | `Copy-VMFile` over the Guest Service Interface, ~82 MB/s. The session copy is a fallback and stalls on archives near a gigabyte. |
33| Exchange | Guest-local `C:\PowerToysUiTestExchange\<name>`, mirrored by the controller. The host never shares a folder with the guest. |
34| Host privilege | Hyper-V access: an elevated shell, or an account in the local **Hyper-V Administrators** group. Creating a guest additionally requires real elevation. |
35| Console | `scripts/Get-VmConsoleImage.ps1` renders the framebuffer to PNG, so an agent can read boot and desktop state without VMConnect. |
36
37## When to use this skill
38
39Use it when asked to:
40
41- Create or migrate UI tests and iterate repeatedly without reprovisioning Windows each run.
42- Validate Explorer, hotkey, WebView2, shell-extension, foreground, or composed-visual behavior in a
43 real interactive desktop.
44- Run tests as a true standard user while retaining a separate administrator control channel.
45- Reuse unchanged PowerToys, winappcli, and .NET payloads and refresh only changed archives.
46- Keep a reproducible local VM baseline with optional .NET 10, WebView2, diagnostics, or `msvsmon`.
47- Collect durable `status.json`, TRX, transcripts, logs, screenshots, and failure attachments.
48- Compare revisions in one stable VM before confirming the result from a restored checkpoint.
49
50Do not treat a persistent VM as proof of clean-profile behavior. Caches, registrations, settings, and
51first-run state survive between runs. Restore the baseline checkpoint or recreate the VM when those
52are the behavior under test.
53
54## Relationship to other UI-test skills
55
56| Skill | Owns |
57|---|---|
58| `ui-tests-migration` | Test design, project scaffolding, framework APIs, assertions, lifecycle, and CI stability. |
59| `ui-tests-local-vm` | Fast persistent-VM setup, deployment, interactive execution, evidence export, and iteration. |
60
61Do not modify stabilized tests merely to make the local VM green. First prove that the suite executes,
62produces assertion-bearing TRX, and has a useful success rate. Classify environment-specific failures
63separately unless the task explicitly asks for stabilization.
64
65## Guest OS policy
66
67- Two guests, two full suites. Windows 10 Enterprise LTSC 2021 (build 19044/21H2, newer than the
68 Windows 10 20H2 baseline) and Windows 11. Both must be fully green before a module is done.
69 LTSC is not available through Fido; `-Source Fido -Windows 10` automates Microsoft's official
70 mobile-user-agent ISO page and is the practical public default. The public ISO/MCT images are too
71 old for .NET 10 CET, so Setup Dynamic Update must bring Win10 to 1904x.5007+ before the baseline.
72 Use licensed Microsoft subscription media for LTSC when available, and always record the edition,
73 ISO hash, and installed full build ([references/setup.md §3](references/setup.md#3-get-windows-media)).
74- Windows 10 runs first: it is the faster loop and surfaces most defects. Windows 11 then runs the
75 **same** suite, unfiltered - not only the tests that look Windows 11-specific. A test with no
76 Windows 11 content can still fail there, which is the whole reason for the second pass.
77- Narrow filters belong to iteration and diagnosis. They are never the evidence for the Windows 11
78 pass.
79- Give each OS its own VM name, `vm.config.psd1`, VHDX, checkpoints, and exchange. Never upgrade or
80 repurpose the Windows 10 guest into the Windows 11 guest; the two baselines must stay independent.
81- Surfaces that exist only on Windows 11, such as the tier-1 Explorer context menu, need no special
82 handling: the full Windows 11 run already covers them.
83- On a Windows on ARM host, use a Windows 11 ARM64 guest with `-Platform ARM64`. Hyper-V does not
84 emulate a foreign architecture, so that host cannot supply the Windows 10 x64 pass - run it on an
85 x64 host and report both.
86- A Windows 11 host requirement does not make Windows 11 the first guest target.
87- `-Platform` is not cosmetic: it flows to the guest as the `platform` environment variable, names
88 visual baselines, and marks the run as pipeline-like. Use only `x64Win10`, `x64Win11`, or `ARM64`.
89
90## Required reads
91
92Read only what the task needs:
93
941. [references/setup.md](references/setup.md) - host requirements, scaffolding, media acquisition,
95 unattended guest creation, credentials, standard-user desktop, and checkpoint baselines.
962. [references/agentic-loop.md](references/agentic-loop.md) - payload contract, controller usage,
97 focused-to-suite iteration, evidence, verdicts, and reset strategy.
983. [references/customization.md](references/customization.md) - persistent image customization,
99 .NET 10, WebView2, `msvsmon`, resource profiles, and golden-baseline guidance.
1004. [references/troubleshooting.md](references/troubleshooting.md) - guest creation, PowerShell Direct,
101 interactive session, scheduled-task, focus, timeout, and export failures.
1025. [references/shell-extensions-and-signing.md](references/shell-extensions-and-signing.md) - **read
103 for any shell-extension module** (context menu, preview/thumbnail handler). Why unsigned CI PR
104 builds cannot register a sparse MSIX (0% on CI), classic (registry-COM, signing-free) vs modern
105 (sparse-MSIX) surfaces, Debug vs Release/`NDEBUG` gating, runtime detection, and reproducing CI's
106 classic scenario on a local signed VM.
1076. [ui-tests-migration](../ui-tests-migration/SKILL.md) - required whenever test code or framework
108 behavior is being created, migrated, or stabilized.
109
110## Default agentic cycle
111
112```mermaid
113flowchart LR
114 A[Design or edit test] --> B[Host build]
115 B --> C[Package changed payload]
116 C --> D[Start or reuse VM]
117 D --> E[Probe standard-user desktop]
118 E --> F[Run focused test]
119 F --> G[Export status TRX evidence]
120 G --> H{Need test change?}
121 H -- Yes --> A
122 H -- No --> I[Run full suite on Win10]
123 I --> J[Run same full suite on Win11]
124 J --> K{Both fully green?}
125 K -- No --> A
126 K -- Yes --> L[Optional checkpoint restore]
127```
128
129Create and maintain this task list:
130
131```markdown
132- [ ] 0. Verify host setup FIRST: `Initialize-LocalVmHost.ps1 -VmRoot <root> -CheckOnly`. If it reports
133 IsReady=false, STOP and ask the user to run the elevated command it prints - Hyper-V group
134 membership, the DPAPI credential, and guest creation all need a human. Never autopilot past it
135- [ ] 1. Read ui-tests-migration guidance for the target test surface
136- [ ] 1a. Read the target module's dev docs — `doc/devdocs/modules/<module>.md` (search `doc/devdocs/`,
137 including `common/`, if the exact file is missing) — for development-cycle gotchas such as
138 Release/`NDEBUG` registration gating, signed sparse-MSIX context menus, and Explorer restarts,
139 so a module's registration/deployment requirements do not surface as opaque test failures.
140 For shell-extension modules also read references/shell-extensions-and-signing.md.
141- [ ] 2. Scaffold or verify the local VM - references/setup.md
142- [ ] 3. Build product and test projects on the host to exit code 0
143- [ ] 4. Package a lean exchange and verify archive hashes
144- [ ] 5. Run the controller with -PlanOnly and inspect its request/plan
145- [ ] 6. Probe the non-admin interactive desktop before test execution
146- [ ] 7. Run one focused test synchronously; keep the agent turn attached, read the controller
147 result's `.Failed` array (non-passed tests + first error line) instead of re-parsing TRX, and
148 use `scripts/Invoke-GuestScript.ps1` for guest-state inspection
149- [ ] 8. Diagnose the first controlling failure without weakening assertions
150- [ ] 9. Rebuild and rerun with -ReuseStagedPayload
151- [ ] 10. Widen to the full module suite on Windows 10 and report pass rate/root-cause groups
152- [ ] 11. Run the same full suite in the Windows 11 VM; both must be green before the module is done
153- [ ] 12. Restore the baseline checkpoint for clean-profile confirmation when required
154```
155
156## Quick start
157
158Host setup is a one-time, **human-only** step: Hyper-V group membership, the DPAPI guest credential,
159and guest creation all need elevation or a password. Check it before anything else - this needs no
160elevation and changes nothing:
161
162```pwsh
163pwsh .github\skills\ui-tests-local-vm\scripts\Initialize-LocalVmHost.ps1 -VmRoot X:\PowerToysUiTestVm -CheckOnly
164```
165
166If it reports `IsReady=false`, stop and ask the user to run the elevated command it prints (see
167[references/setup.md §0](references/setup.md#0-human-only-host-setup-one-command)). Otherwise scaffold
168the VM directory outside the repository:
169
170```pwsh
171pwsh .github\skills\ui-tests-local-vm\scripts\Initialize-LocalVm.ps1 `
172 -DestinationRoot X:\PowerToysUiTestVm
173```
174
175The scaffold and its `shared` exchange can live on any volume, including a Dev Drive. Only the VHDX
176and VM configuration paths, set separately in `vm.config.psd1`, should point at NTFS.
177
178Follow [references/setup.md](references/setup.md) to write the untracked `vm.config.psd1`, save the
179administrator credential with Windows DPAPI, obtain install media, and create the guest with
180`New-UiTestVm.ps1`. Then stage the archives described in
181[references/agentic-loop.md](references/agentic-loop.md) and run:
182
183```pwsh
184pwsh .github\skills\ui-tests-local-vm\scripts\Invoke-LocalVmUiTest.ps1 `
185 -VmName PowerToysUiTest-Win10 `
186 -VmRoot X:\PowerToysUiTestVm `
187 -ExchangeRoot X:\PowerToysUiTestVm\shared\PowerToysUiTests\MyModule `
188 -TestExecutable MyModule.UITests.Next.exe `
189 -Filter 'Name=MyModule.FocusedTest' `
190 -Platform x64Win10 `
191 -BuildLabel (git rev-parse HEAD) `
192 -SuiteTimeout 15m `
193 -TimeoutMinutes 25 `
194 -ReuseStagedPayload
195```
196
197The controller starts the VM if needed, requests automatic host sleep prevention, verifies the
198interactive standard-user desktop, dispatches the guest runner, and waits synchronously for matching
199`status.json`. It reports whether sleep prevention succeeded, fails early if the guest task never
200starts or exits without status, summarizes TRX, and leaves the persistent VM running by default.
201
202## Non-negotiable rules
203
204- Complete host setup before anything else and **never autopilot around it**. Hyper-V group
205 membership, the DPAPI guest credential, and guest creation are human-only: two need elevation that
206 no tool call can approve, one needs a password that must never reach a model.
207 `Initialize-LocalVmHost.ps1` performs all three; agents run it `-CheckOnly`, and on
208 `IsReady=false` report `BLOCKED`, print the elevated command it emits, and wait. Do not ask for a
209 password, do not substitute a weaker channel, do not proceed on a partial setup.
210 `Invoke-LocalVmUiTest.ps1` enforces the same check.
211- Keep the guest's VHDX and VM configuration on NTFS. On this project's host, keeping them on a Dev
212 Drive wedged the VM management service twice - `vmms` at 0% CPU, even `Get-VM` hanging, host reboot
213 to recover - and moving to NTFS fixed it. This is an observation on one host, not a property of
214 ReFS: Hyper-V on plain ReFS is supported, so `-AllowReFsVolume` overrides the default refusal. The
215 scaffold and the exchange are unaffected and run fine on a Dev Drive.
216- Build on the host; run PowerToys and tests only in the VM when host execution is prohibited.
217- Invoke every focused, full-suite, and constrained controller run synchronously. Keep the active
218 agent turn attached until the controller returns matching status/TRX evidence; never background
219 the controller or end the turn while it runs.
220- Finish on two green full suites: Windows 10 and Windows 11, in separate VMs. Windows 10 runs first
221 for speed; Windows 11 runs the same unfiltered suite, never a Win11-only subset. Narrow filters are
222 for iteration, not for sign-off. On a Windows on ARM host the ARM64 Windows 11 guest covers the
223 Windows 11 half and the Windows 10 half needs an x64 host.
224- Establish a fully green correctness baseline with the default (4 vCPU / 8 GB) resources before
225 running the same tests under `Constrained` (1 vCPU / 4 GB) resources.
226- Keep VM files and writable exchange folders outside the repository.
227- Keep the guest's default inbound network posture. The control channel does not need connectivity,
228 so do not enable remoting, open ports, or attach the guest to a routable network for test dispatch.
229- Use a DPAPI-protected credential file. Never put credentials in prompts, scripts, request JSON,
230 unattend files kept after install, source control, or command-line arguments.
231- Run UI tests in an already logged-on standard-user desktop, never in session 0 or as `SYSTEM`.
232- Keep a separate administrator account only for VM control and scheduled-task registration.
233- Verify user, token integrity, Explorer presence, session ID, and display size before tests.
234- Run product/tests from guest-local storage under `C:\PowerToysUiTestRun`.
235- Use PowerShell 7 for interactive probe/test scheduled tasks. PowerShell Direct and OEM bootstrap
236 remain PS5.1-compatible by design; do not enable a remoting endpoint merely to use PS7.
237- Reuse payloads by per-component hashes; refresh only changed tests/product/tools.
238- Preserve assertions and visual thresholds. Classify VM-specific failures from evidence.
239- Always parse TRX and require `total > 0` plus `executed == total`. A process exit code alone cannot
240 distinguish assertions, skipped/inconclusive tests, zero tests, timeout, or infrastructure failure.
241- Keep the VM after normal runs for iteration. Stop it explicitly when idle; delete its VHDX only for
242 an intentional baseline reset.
243- The controller requests automatic host sleep prevention and reports `HostSleepPrevented`; failure
244 is a warning. It cannot override manual sleep, lid-close policy, reboot, shutdown, or power loss.
245- Final clean-profile claims require a restored baseline checkpoint or a recreated guest. Restore with
246 `Reset-LocalVm.ps1 -Restore`.