Files
guru-connect/docs/specs/SPEC-019-private-backstage-session.md
Howard Enos f8f384f8d8 spec: add SPEC-019 private Backstage session (GUI private desktop for interactive uninstall)
Extends SPEC-013 backstage from terminal-only to a private GUI desktop so a tech
can drive a stubborn uninstaller's UI invisibly to the logged-on user. Builds on
SPEC-018 broker; deep-linked from GuruRMM SPEC-030 'needs remote removal' flag.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 16:05:43 -07:00

7.1 KiB

SPEC-019: Private Backstage Session (interactive uninstall / hidden desktop)

Status: Proposed Priority: P2 Requested By: Howard (2026-06-22) Estimated Effort: Large

Overview

A private session mode for GuruConnect: the tech gets an interactive remote view of a process's UI on the target machine that the logged-on user does not see. The motivating use case is GuruRMM's Tier-2 software removal — when a program has no silent uninstall (flagged needs_remote by the RMM removal engine), the tech opens a Backstage session, the stubborn uninstaller's GUI runs on a private desktop, and the tech clicks through it remotely while the end user's screen is undisturbed. This is GuruConnect's equivalent of ScreenConnect Backstage.

Success criteria:

  • A tech can launch a program (e.g. an uninstaller) on a target and drive its UI remotely.
  • The logged-on user does not see the window or the interaction (private-desktop mode).
  • Works with no interactive user logged in (system-spawned private desktop).
  • Deep-linkable from the GuruRMM "Needs remote removal" flag.

The Windows constraint (why this is non-trivial)

A GUI process needs an interactive window station + desktop. The agent runs as SYSTEM in Session 0, which is isolated and cannot present UI. So GuruConnect must either (a) run the target process on the active user's desktop and mirror it (visible to the user), or (b) create a separate private desktop (CreateDesktop) and stream only that desktop to the tech (invisible to the user). (b) is the Backstage model.

Scope

Included in v1

  • Private-desktop capture/input: capture a specific desktop's framebuffer and inject input into it (not just the active console desktop), via a dedicated window station/desktop the agent creates (CreateWindowStation/CreateDesktop + SetThreadDesktop on the capture/input threads).
  • Launch-process-in-session: start an arbitrary command (the uninstaller) bound to that private desktop, as SYSTEM or as a chosen user token.
  • Backstage viewer mode in the web/native viewer: a session flagged "private" with a clear "user cannot see this" indicator.
  • GuruRMM deep link: accept a launch target (program path/uninstall string) so the RMM needs_remote action opens straight into a Backstage session pointed at that program.

Explicitly out of scope

  • Mirroring the active user desktop — that is ordinary remote control (already covered); this spec is specifically the private/hidden desktop.
  • Logging in a brand-new interactive user session (secondary-logon) — heavier and fragile; considered in Future Considerations only.
  • The RMM-side removal engine + tracking (lives in GuruRMM SPEC-030; this is the GC counterpart).

Architecture

  • agent (Windows): new private-desktop subsystem — create a window station + desktop, run the capture loop with SetThreadDesktop bound to it (DXGI won't capture an off-screen desktop, so fall back to GDI BitBlt/PrintWindow for the private desktop), inject input with SendInput/PostMessage targeted at that desktop's windows. Process launch via CreateProcessAsUser/CreateProcess with STARTUPINFO.lpDesktop set to the private desktop.
  • relay-server (Axum): a new session kind private/backstage; same protobuf transport, flagged so the dashboard/viewer render the "hidden from user" state and audit it distinctly.
  • viewer: render the private-desktop stream; banner indicating the user can't see it.
  • dashboard: "Start Backstage session" entry; accept the deep-link launch target.
  • proto (proto/guruconnect.proto): add a session-mode enum (NORMAL/PRIVATE) and a LaunchProcess { command, desktop: PRIVATE, run_as } control message.

Implementation details

  • Capture: DXGI Desktop Duplication is tied to the active output/desktop; a private off-screen desktop is not duplicatable that way — use GDI capture of the private desktop's windows (PrintWindow per top-level window or BitBlt of the desktop DC after SetThreadDesktop). Lower FPS is acceptable for clicking through an installer.
  • Input: SendInput operates on the calling thread's desktop — bind the input thread with SetThreadDesktop(hPrivateDesktop) before injecting; for stubborn controls use PostMessage/SendMessage to the target HWND.
  • Lifecycle: tear down the private desktop + window station when the session ends; kill orphaned child processes bound to it.

Security considerations

  • A private/hidden session that the end user cannot see is powerful and must be audited loudly — record start/stop, operator, target, and the launched command. Consider an org/policy toggle to require consent or to disallow private mode per tenant.
  • Reuse GuruConnect's existing auth (JWT/support code/agent key). Launching arbitrary processes as SYSTEM on a private desktop is high privilege — gate behind tech-role auth.
  • Threat model: a hidden remote session is an attractive abuse target; treat parity with the existing remote-control trust boundary plus extra audit.

Testing strategy

  • Unit: desktop/window-station create+destroy; thread-desktop binding.
  • Manual: launch Notepad on a private desktop, confirm the logged-on user does NOT see it and the tech can type into it; then a real GUI uninstaller (e.g. an NVIDIA/Office leftover) driven to completion; then with no user logged in.
  • Integration: RMM needs_remote deep-link opens a Backstage session at the right program.

Relationship to existing specs (read first)

  • SPEC-018 (managed-agent SYSTEM service host + session broker) is the prerequisite — it provides the SYSTEM service + per-session worker spawning this builds on.
  • SPEC-013 (session selection + backstage) already defines backstage as a terminal/command interface (services management). SPEC-019 extends backstage from terminal-only to a private GUI desktop — the ability to see and click an arbitrary program's window (an uninstaller) that the logged-on user cannot see. Consider folding this into SPEC-013 as its "GUI backstage" phase if the team prefers one spec.

Effort estimate & dependencies

  • Large. Depends on SPEC-018 (broker) and the existing capture/input pipeline; complements SPEC-013 (backstage). The private-desktop GDI capture + input-desktop binding is the hard, novel part. Unblocks GuruRMM Tier-2 interactive removal and any "do something the user shouldn't see" support workflow.

Open questions

  • DXGI vs GDI for the private desktop — confirm DXGI truly can't target it; measure GDI FPS.
  • Run the uninstaller as SYSTEM or as the logged-on user's token on the private desktop? (Some per-user uninstallers need the user's profile/HKCU.)
  • Default posture: should private mode require explicit per-session consent or a tenant policy?

References

  • GuruRMM SPEC-030 (remote software inventory + bulk uninstall) — the needs_remote flag + the removal knowledge base that feeds this. Tier-2 is the last resort; the RMM vendor table shrinks the set over time.
  • ScreenConnect Backstage (prior art for a hidden support session).