feat(gui): Windows assistance GUI - named-pipe IPC, Session 0 launch, capture exclusion (VA-56) #91

Merged
nrupard merged 1 commit from feat/VA-56-windows-assistance-gui into main 2026-06-30 19:01:02 +02:00
Owner

What

Brings the assistance-mode GUI to Windows (VA-56), the follow-up to VA-24's Linux slice. The per-user egui process now cross-compiles for x86_64-pc-windows-gnu, and the Session 0 service launches and drives it.

Changes

vervain-agent-gui

  • Cargo.toml: split GUI deps. Cross-platform stack (eframe glow, egui, tray-icon, notify-rust, tokio) builds everywhere; the Linux-only backends (eframe wayland/x11, gtk) move into a cfg(target_os = "linux") table; Windows adds windows-sys + raw-window-handle.
  • IPC transport abstraction (ipc.rs): newline-JSON framing is shared; only the endpoint differs - unix socket on Linux, tokio named pipe on Windows. serve is generic over the stream; connect is per-platform (named-pipe client retries on ERROR_PIPE_BUSY).
  • Tray (tray.rs / app.rs): the Win32 backend must live on the winit main thread (vs Linux's gtk thread), so the app owns the TrayIcon, builds it on the first frame, polls MenuEvent, and refreshes on state change. Icon/menu helpers shared.
  • Capture exclusion (app.rs): SetWindowDisplayAffinity(hwnd, WDA_EXCLUDEFROMCAPTURE) on the winit HWND, retried until the handle exists.
  • Notification: Windows operator-attached toast (notify-rust's interactive actions are dbus/Linux-only).
  • proto: default_socket_path() returns the pipe name on Windows.

vervain-agent

  • gui_ipc.rs: named-pipe server (one-instance-at-a-time accept loop) alongside the unix listener; client generic over AsyncRead + AsyncWrite.
  • Session 0 -> active session launch (main.rs): the service launches vervain-agent assistance into the active console session via the VA-11 kvm::windows::session::spawn_in_active_session (CreateProcessAsUser) primitive; the GUI connects back over the pipe. Skipped when run interactively.
  • Ungate the gui_ipc module, the assistance subcommand + early routing, the server start, and the in-process consent preference for Windows.

CI (check.Dockerfile): re-include vervain-agent-gui in the windows-gnu cross-check (drop --exclude), and add a windows-gnu agent-gui check so the named-pipe server, Session 0 launch, and consent path keep compiling.

Acceptance criteria

  • vervain-agent-gui builds on Windows with app; vervain-agent --features agent-gui builds on Windows.
  • Daemon<->GUI IPC over a Windows named pipe; proto wire types shared with the unix path.
  • Session 0 service launches the GUI into the active session (CreateProcessAsUser) and the GUI connects back. (code; runtime per below)
  • System tray shows connection state + "disconnect now". (code; runtime per below)
  • In-process egui consent dialog serves host/consent.rs prompts over IPC.
  • Operator-connected notification fires. (Windows toast)
  • Assistance window opts out of screen capture via WDA_EXCLUDEFROMCAPTURE. (code; runtime per below)
  • Stripped Windows release binary size recorded: 16.9 MB (vervain-agent --features agent-gui, windows-gnu, release strip = "symbols"), under the 20 MB target.
  • vervain-agent-gui re-included in the windows-gnu CI cross-check.
  • Runtime-validated on a real Windows host. Not possible in this Linux/CI environment; deferred to a Windows host, consistent with how the repo already validates the Windows service ACs (sc query, reboot survival, uninstall idempotency) manually.

Verification

In the windows-gnu builder image:

  • cargo check --workspace --target x86_64-pc-windows-gnu --locked (whole workspace incl. the GUI).
  • cargo check -p vervain-agent -p vervain-agent-gui --features agent-gui --target x86_64-pc-windows-gnu --locked.
  • cargo clippy -p vervain-agent -p vervain-agent-gui --features agent-gui -- --deny warnings (Linux).
  • cargo fmt --all --check; cargo test -p vervain-agent-gui --lib (3 pass).
  • Stripped windows-gnu release binary: 16.9 MB.

Follow-ups (noted, not in scope)

  • Runtime validation on a Windows host (the open AC).
  • macOS window/capture backend (still deferred).
  • Tighter named-pipe SECURITY_ATTRIBUTES and the CreateEnvironmentBlock USERPROFILE/APPDATA fix the kvm primitive already flags.
  • Re-launch the GUI on console-session change (MVP launches once at service start).

#VA-56

## What Brings the assistance-mode GUI to Windows (VA-56), the follow-up to VA-24's Linux slice. The per-user egui process now cross-compiles for `x86_64-pc-windows-gnu`, and the Session 0 service launches and drives it. ## Changes **vervain-agent-gui** - **Cargo.toml**: split GUI deps. Cross-platform stack (eframe `glow`, egui, `tray-icon`, notify-rust, tokio) builds everywhere; the Linux-only backends (eframe `wayland`/`x11`, `gtk`) move into a `cfg(target_os = "linux")` table; Windows adds `windows-sys` + `raw-window-handle`. - **IPC transport abstraction** (ipc.rs): newline-JSON framing is shared; only the endpoint differs - unix socket on Linux, `tokio` named pipe on Windows. `serve` is generic over the stream; `connect` is per-platform (named-pipe client retries on `ERROR_PIPE_BUSY`). - **Tray** (tray.rs / app.rs): the Win32 backend must live on the winit main thread (vs Linux's gtk thread), so the app owns the `TrayIcon`, builds it on the first frame, polls `MenuEvent`, and refreshes on state change. Icon/menu helpers shared. - **Capture exclusion** (app.rs): `SetWindowDisplayAffinity(hwnd, WDA_EXCLUDEFROMCAPTURE)` on the winit HWND, retried until the handle exists. - **Notification**: Windows operator-attached toast (notify-rust's interactive actions are dbus/Linux-only). - **proto**: `default_socket_path()` returns the pipe name on Windows. **vervain-agent** - **gui_ipc.rs**: named-pipe server (one-instance-at-a-time accept loop) alongside the unix listener; `client` generic over `AsyncRead + AsyncWrite`. - **Session 0 -> active session launch** (main.rs): the service launches `vervain-agent assistance` into the active console session via the VA-11 `kvm::windows::session::spawn_in_active_session` (CreateProcessAsUser) primitive; the GUI connects back over the pipe. Skipped when run interactively. - Ungate the `gui_ipc` module, the `assistance` subcommand + early routing, the server start, and the in-process consent preference for Windows. **CI** (check.Dockerfile): re-include `vervain-agent-gui` in the windows-gnu cross-check (drop `--exclude`), and add a windows-gnu `agent-gui` check so the named-pipe server, Session 0 launch, and consent path keep compiling. ## Acceptance criteria - [x] `vervain-agent-gui` builds on Windows with `app`; `vervain-agent --features agent-gui` builds on Windows. - [x] Daemon<->GUI IPC over a Windows named pipe; `proto` wire types shared with the unix path. - [x] Session 0 service launches the GUI into the active session (`CreateProcessAsUser`) and the GUI connects back. (code; runtime per below) - [x] System tray shows connection state + "disconnect now". (code; runtime per below) - [x] In-process egui consent dialog serves `host/consent.rs` prompts over IPC. - [x] Operator-connected notification fires. (Windows toast) - [x] Assistance window opts out of screen capture via `WDA_EXCLUDEFROMCAPTURE`. (code; runtime per below) - [x] Stripped Windows release binary size recorded: **16.9 MB** (`vervain-agent --features agent-gui`, windows-gnu, release `strip = "symbols"`), under the 20 MB target. - [x] `vervain-agent-gui` re-included in the windows-gnu CI cross-check. - [ ] **Runtime-validated on a real Windows host.** Not possible in this Linux/CI environment; deferred to a Windows host, consistent with how the repo already validates the Windows service ACs (`sc query`, reboot survival, uninstall idempotency) manually. ## Verification In the windows-gnu builder image: - `cargo check --workspace --target x86_64-pc-windows-gnu --locked` (whole workspace incl. the GUI). - `cargo check -p vervain-agent -p vervain-agent-gui --features agent-gui --target x86_64-pc-windows-gnu --locked`. - `cargo clippy -p vervain-agent -p vervain-agent-gui --features agent-gui -- --deny warnings` (Linux). - `cargo fmt --all --check`; `cargo test -p vervain-agent-gui --lib` (3 pass). - Stripped windows-gnu release binary: 16.9 MB. ## Follow-ups (noted, not in scope) - Runtime validation on a Windows host (the open AC). - macOS window/capture backend (still deferred). - Tighter named-pipe `SECURITY_ATTRIBUTES` and the `CreateEnvironmentBlock` USERPROFILE/APPDATA fix the kvm primitive already flags. - Re-launch the GUI on console-session change (MVP launches once at service start). #VA-56
feat(gui): Windows assistance GUI - named-pipe IPC, Session 0 launch, capture exclusion (VA-56)
All checks were successful
Check / fmt + clippy + tests (pull_request) Successful in 4m2s
Create release / Create release from merged PR (pull_request) Has been skipped
d20e86cd2d
Brings the assistance-mode GUI (VA-24's Linux slice) to Windows: the per-user egui process now cross-compiles for x86_64-pc-windows-gnu and the daemon drives it from Session 0.

vervain-agent-gui:
- Cargo.toml: split the GUI deps so the cross-platform stack (eframe `glow`, egui, tray-icon, notify-rust, tokio) builds everywhere while the Linux-only backends (eframe `wayland`/`x11`, `gtk`) move into a `cfg(target_os = "linux")` table; add Windows-only `windows-sys` + `raw-window-handle` for capture exclusion.
- IPC (ipc.rs / gui_ipc.rs): abstract the transport. The newline-JSON framing is shared; only the endpoint differs - a unix socket on Linux, a `tokio` named pipe on Windows (`\\.\pipe\vervain-agent-assistance`). The daemon serves the pipe with the canonical one-instance-at-a-time accept loop; `client` is generic over `AsyncRead + AsyncWrite`.
- Tray: the Win32 backend must live on the winit main thread (unlike Linux's gtk thread), so the app owns the `TrayIcon`, builds it on the first frame, polls `MenuEvent`, and refreshes it on state change. Icon/tooltip helpers are shared.
- Capture exclusion: `SetWindowDisplayAffinity(hwnd, WDA_EXCLUDEFROMCAPTURE)` on the winit HWND (read via `raw-window-handle`), retried until the handle exists.
- Notification: an operator-attached toast on Windows (notify-rust's interactive dbus actions are Linux-only, so Windows gets a plain toast; disconnect stays reachable from the tray/window).
- proto: `default_socket_path()` returns the pipe name on Windows.

vervain-agent:
- The Session 0 service launches `vervain-agent assistance` into the active console session via the VA-11 `kvm::windows::session::spawn_in_active_session` (CreateProcessAsUser) primitive; the GUI connects back over the pipe. Skipped when run interactively.
- Ungate the `gui_ipc` module, the `assistance` subcommand + routing, the server start, and the in-process consent preference for Windows.

CI: re-include `vervain-agent-gui` in the windows-gnu cross-check (drop the `--exclude`) and add a windows-gnu `agent-gui` check so the named-pipe server, Session 0 launch, and consent path keep compiling.

Verified in the windows-gnu builder image: `cargo check --workspace --target x86_64-pc-windows-gnu --locked` (whole workspace incl. the GUI), `cargo check -p vervain-agent -p vervain-agent-gui --features agent-gui --target x86_64-pc-windows-gnu --locked`, `cargo clippy -p vervain-agent -p vervain-agent-gui --features agent-gui -- --deny warnings` (Linux), fmt, and the gui lib tests all pass. Stripped windows-gnu release binary (vervain-agent --features agent-gui) is 16.9 MB, under the 20 MB target.

Runtime ACs (tray render, capture exclusion, Session 0 -> active-session launch, consent dialog) need a real Windows host and are validated there, like the existing Windows service ACs; this change is the compile/link-verified port.

#VA-56

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
nrupard scheduled this pull request to auto merge when all checks succeed 2026-06-30 19:00:28 +02:00
nrupard deleted branch feat/VA-56-windows-assistance-gui 2026-06-30 19:01:02 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/vervain-agent!91
No description provided.