Skip to content

Make closing winapp's Sandbox window end the Sandbox, after Windows asks - #1047

Merged
Zach Teutsch (zateutsch) merged 5 commits into
mainfrom
nmetulev-sandbox-close-ends-session
Oct 9, 2026
Merged

Zach Teutsch (zateutsch) merged 5 commits into
mainfrom
nmetulev-sandbox-close-ends-session

Conversation

@nmetulev

@nmetulev Nikola Metulev (nmetulev) commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Description

Problem. winapp started its Windows Sandbox with wsb start. That Sandbox has no window, and only wsb stop ends it. winapp then showed it with wsb connect, which only views it. So closing the Sandbox window left the Sandbox running out of sight. One left on a dev machine this way had about 3.9 GB of memory committed three days later. Opening Windows Sandbox from Start then failed with "Only one running instance of Windows Sandbox is allowed".

Change. winapp now opens a new Sandbox the same way Start does: it launches the Windows Sandbox app, with no arguments. That window owns the Sandbox. Closing it shows Windows' own confirmation, "Are you sure you want to close Windows Sandbox? Once Windows Sandbox is closed all of its content will be discarded and permanently lost.":

  • Ok ends the Sandbox. The next --on sandbox command starts a fresh one.
  • Cancel keeps it, and winapp keeps using it.

There is still exactly one Sandbox window. winapp still moves it behind your window.

winapp records the Sandbox as one it created only when the window it launched reaches a session. In any other case it uses the Sandbox as adopted, meaning started by something else, which winapp never ends. One example is opening Windows Sandbox from Start at the same moment.

Usage Example

winapp run . --on sandbox --detach
# Close the "Windows Sandbox" window.
# Before: no prompt; `wsb list` still shows the Sandbox, running with no window.
# After:  Windows asks to confirm. Ok ends it (`wsb list` is empty). Cancel keeps it.

Related Issue

Replaces #978, which ended the Sandbox from a hidden background process with no confirmation.

Type of Change

  • 🐛 Bug fix
  • 📝 Documentation
  • 🧪 Test update

Checklist

  • New tests added for new functionality (if applicable)
  • Tested locally on Windows
  • Shipped skills updated in plugins/winapp/skills/ (if CLI commands/workflows changed)

docs/sandbox-execution.md and the winapp-sandbox skill now say that closing the window of a Sandbox winapp started asks for confirmation and then ends it. No commands or options change, so docs/usage.md does not.

Screenshots / Demo

Measured on a real Windows Sandbox (Windows build 28000, Arm64, Windows Sandbox 0.8.107.0), with a NativeAOT build of this branch:

What I did What happened
winapp target exec sandbox -- cmd /c echo hello with nothing running Exit 0 in 25–41 s. One Sandbox window, recorded as created by winapp. Focus returned to my window.
The same command again Exit 0 in 0.2 s, same Sandbox and window
Closed the window, clicked Cancel Sandbox still listed; the next command reused it (1 s)
winapp ui list-windows --on sandbox, winapp ui screenshot --on sandbox -w <hwnd> Both worked through the window winapp opened
Closed the window, clicked Ok wsb list empty; the next command started a fresh Sandbox (35 s)
Killed winapp 8 s into a cold start The Sandbox kept running; the next command used it (25 s), still one window
Ran wsb start 0.7 s after winapp began a cold start, so the headless Sandbox won winapp's window showed "Only one running instance…". winapp used the headless Sandbox, connected one window to it, and exited 0 in 20 s

Before this change, closing the window showed no prompt and wsb list still listed the Sandbox.

Additional Notes

  • Only Sandboxes winapp opens change. A Sandbox started with wsb start, for example by another tool or by winapp 0.7.1 or earlier, still keeps running after its window is closed. The docs point those users to wsb stop --id <id>. If winapp 0.7.1 crashed mid-start and left a pending-start record, newer winapp still recovers it.
  • Ending the window's process ends the Sandbox. That is how Windows Sandbox works when started from Start. winapp never ends that process: it stops tracking it when a command is cancelled, and a winapp killed mid-start leaves the Sandbox running.
  • One window, even when winapp can't identify its own. If winapp's window takes over 30 s to show a session, winapp uses the Sandbox as adopted and doesn't connect a second window. If winapp's window instead shows Windows' "Only one running instance" error, another Sandbox won. winapp then treats that Sandbox like any other it adopts, and connects a window only if nobody is signed in.

winapp started its Sandbox with `wsb start`, which has no window and
ends only with `wsb stop`, then showed it with `wsb connect`, a viewer.
Closing that viewer left the Sandbox running out of sight: one found on
a dev machine had been holding about 3.9 GB for three days. Opening
Windows Sandbox from Start then failed with "Only one running instance".

winapp now opens a new Sandbox the way Start does, by launching the
Windows Sandbox client (the alias beside wsb.exe) with no arguments.
That window owns the Sandbox: closing it shows Windows' own "all of its
content will be discarded" confirmation and then ends the Sandbox.
Cancel keeps it. No `wsb connect` is added on top, so there is exactly
one window. `wsb share`, `wsb exec` and `wsb list` work against it
unchanged, and winapp already used the default configuration.

Windows assigns the instance ID, so winapp finds it with `wsb list`.
It claims the Sandbox as Created only when the window it launched
reached a session; otherwise, as when someone opens one from Start at
the same moment, it uses the Sandbox as adopted. Pending-start records
written by winapp 0.7.1 are still recovered.

Verified live: cold start (one window, focus returned, piped output
closed), warm reuse, close then Cancel (kept and reused), close then Ok
(ended, next command starts fresh), and winapp killed mid-start (the
Sandbox survives and the next command uses it).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@nmetulev Nikola Metulev (nmetulev) added the agent-preparing Agent is addressing feedback or completing required validation and CI label Oct 9, 2026
If the window winapp opened took longer than 30 s to show a session,
the new Sandbox was used as adopted, and a guest still signing in
reported no login session, so winapp ran `wsb connect` and put a second
window on screen. Closing that one would leave the Sandbox running.

A Sandbox the command just opened always has a window attached, either
winapp's or the one Start opened in the same moment, so the session
probe and `wsb connect` are now skipped whenever this command opened
one, not only when it could prove the window was its own.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Build Metrics Report

Validation passed. All required build and validation jobs succeeded.

Binary Sizes

Artifact Baseline Current Delta
CLI (ARM64) 57.78 MB 57.79 MB 📈 +9.5 KB (+0.02%)
CLI (x64) 57.80 MB 57.81 MB 📈 +8.5 KB (+0.01%)
MSIX (ARM64) 24.02 MB 24.01 MB 📉 -7.9 KB (-0.03%)
MSIX (x64) 25.46 MB 25.47 MB 📈 +10.4 KB (+0.04%)
NPM Package 50.05 MB 50.05 MB 📈 +4.0 KB (+0.01%)
NuGet Package 50.15 MB 50.15 MB 📈 +2.6 KB (+0.01%)

.NET Test Results (TRX reports)

Other suites are reflected in the overall validation status above.

✅ 8315 passed, 37 skipped out of 8352 tests in 1128.9s (-101.8s vs. baseline)

Test Coverage

✅ 86.7% line coverage, 81.3% branch coverage · ✅ no change vs. baseline

CLI Startup Time

61ms median (x64, winapp --version) · ✅ +8ms vs. baseline

Try This Build

Installs the MSIX for your architecture, replacing any previously installed build. Needs the GitHub CLI — the command offers to install it and sign you in if it is missing.

& ([scriptblock]::Create((irm https://raw.githubusercontent.com/microsoft/winappCli/main/scripts/winapp-pr.ps1))) 1047
Switching between builds often?

Put the tool on your PATH once:

& ([scriptblock]::Create((irm https://raw.githubusercontent.com/microsoft/winappCli/main/scripts/winapp-pr.ps1))) -AddToPath

Then this build is just:

winapp-pr 1047

Run winapp-pr with no arguments to pick from a list of open PRs.


Updated 2026-10-09 19:09:57 UTC · commit 506c32f · workflow run

@nmetulev
Nikola Metulev (nmetulev) marked this pull request as ready for review October 9, 2026 17:20
Copilot AI balanced review requested due to automatic review settings October 9, 2026 17:20
@nmetulev Nikola Metulev (nmetulev) added ready-for-review Agent work and technical checks complete; awaiting review or re-review, not approval or merge and removed agent-preparing Agent is addressing feedback or completing required validation and CI labels Oct 9, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A concurrent headless wsb start can be adopted without connecting a client, and the documentation overstates close-to-end behavior.

3 open findings
What changed in this PR

Updates Windows Sandbox startup so its owning window controls Sandbox lifetime and closing it triggers Windows’ confirmation.

Changes:

  • Launches Windows Sandbox directly instead of using headless wsb start.
  • Tracks the owning client window and safely adopts ambiguous instances.
  • Updates tests and user guidance for the new lifecycle.
File Description
WsbHResult.cs Removes start-specific HRESULT constants.
WindowsSandboxWindowController.cs Recognizes directly launched clients.
WindowsSandboxLifecycle.cs Reworks creation and ownership reconciliation.
WindowsSandboxHostProbe.cs Exposes execution-alias validation internally.
WindowsSandboxCli.cs Launches the Sandbox client directly.
WindowsSandboxBackend.cs Uses the owning window during bootstrap.
SandboxConnectAttempt.cs Documents direct-client ownership.
IWindowsSandboxCli.cs Replaces headless start with client launch.
TargetState.cs Documents legacy pending-start records.
WindowsSandboxWindowControllerTests.cs Tests direct-launch window matching.
WindowsSandboxLifecycleTests.cs Tests launch, adoption, and recovery behavior.
WindowsSandboxCliTests.cs Tests argument-free client launch.
WindowsSandboxCliClassificationTests.cs Removes obsolete start tests.
SandboxUxRegressionTests.cs Verifies one-window bootstrap behavior.
SandboxLiveAdoptionTests.cs Retains live headless-adoption coverage.
SandboxAdoptionTests.cs Tests unidentified-window adoption.
winapp-sandbox/​SKILL.md Updates Sandbox lifetime guidance.
sandbox-execution.md Documents close confirmation and termination.

🧠 Review effort: Balanced


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/sandbox-execution.md Outdated
Comment thread plugins/winapp/skills/winapp-sandbox/SKILL.md Outdated
@nmetulev Nikola Metulev (nmetulev) added agent-preparing Agent is addressing feedback or completing required validation and CI and removed ready-for-review Agent work and technical checks complete; awaiting review or re-review, not approval or merge labels Oct 9, 2026
If a headless `wsb start` won the Sandbox singleton in the same moment
winapp opened its own window, winapp used that headless Sandbox but
never connected a window to it, so the agent waited three minutes and
failed. The agent's own "no input desktop" after that wait now connects
one window, as it already does for a closed window. A window winapp
opened but could not identify still gets the full wait to sign in.

The docs and skill now say that closing the window ends a Sandbox
winapp started, and that one started with `wsb start` keeps running.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Measured live: a headless `wsb start` in the same moment as winapp's
launch wins the singleton, and winapp's window shows "Only one running
instance of Windows Sandbox is allowed". winapp then assumed a window
was attached, waited out the agent's three-minute deadline, and failed
after about six minutes. The fallback added in the previous commit
never fired, because the agent's dispatch failure on a headless guest
is not observed in time.

The window controller now reports when the window winapp launched shows
that error page, without waiting out its 30 s timeout. winapp then
treats the Sandbox like any other it adopts: the session probe finds
nobody signed in and winapp connects one window. The same race now
succeeds in about 20 s. The previous commit's fallback is reverted.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
If someone opens Windows Sandbox from Start at the same moment as
winapp's launch and wins, winapp's window shows the same "Only one
running instance" page. The winner has its own window, still signing
in, so probing the guest reported no login session and winapp connected
a second window.

winapp now treats the Sandbox as windowless only when its window shows
that page and no other Sandbox window is open. Measured live: racing
winapp with the Start entry, Start won and winapp used that Sandbox
without a second window (exit 0, 21 s).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@nmetulev Nikola Metulev (nmetulev) added ready-for-review Agent work and technical checks complete; awaiting review or re-review, not approval or merge and removed agent-preparing Agent is addressing feedback or completing required validation and CI labels Oct 9, 2026
@zateutsch
Zach Teutsch (zateutsch) merged commit 57f06b1 into main Oct 9, 2026
44 checks passed
@zateutsch
Zach Teutsch (zateutsch) deleted the nmetulev-sandbox-close-ends-session branch October 9, 2026 20:41
@nmetulev Nikola Metulev (nmetulev) removed the ready-for-review Agent work and technical checks complete; awaiting review or re-review, not approval or merge label Oct 9, 2026
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.

3 participants