wraith/docs/spikes/multi-window-results.md
Vantz Stockwell d42f000f8f spike: multi-window and RDP frame transport research results
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 06:35:00 -04:00

4.1 KiB

Spike: Multi-Window Support in Wails v3

Status: Research-based (not yet validated on Windows) Date: 2026-03-17 Target platform: Windows (developing on macOS) Wails version: v3.0.0-alpha.74


Context

Wraith needs to support detached sessions — users should be able to pop out an SSH or RDP session into its own window while the main connection manager remains open. This spike evaluates three approaches, ranked by preference.


Plan A: Wails v3 Native Multi-Window

Status: LIKELY WORKS based on API documentation.

How it works

  • app.Window.NewWithOptions() creates a new OS-level window at runtime.
  • Each window can load a different URL or frontend route (e.g., /session/rdp/3 in one window, / in the main window).
  • All windows share the same Go backend services — no IPC or inter-process marshalling required. Bindings registered on the application are callable from any window.
  • Window lifecycle events (OnClose, OnFocus, etc.) are available for cleanup.

Example (pseudocode)

win, err := app.Window.NewWithOptions(application.WindowOptions{
    Title:  "RDP — server-01",
    Width:  1280,
    Height: 720,
    URL:    "/session/rdp/3",
})

Risks

Risk Severity Mitigation
Alpha API — method signatures may change before v3 stable Medium Pin to a known-good alpha tag; wrap calls behind an internal interface so migration is a single-file change.
Platform-specific quirks on Windows (DPI, focus, taskbar grouping) Low Test on Windows during Phase 2. Wails uses webview2 on Windows which is mature.
Window count limits or resource leaks Low Cap concurrent detached windows (e.g., 8). Ensure OnClose releases resources.

Plan B: Floating Panels (CSS-based)

Status: FALLBACK — no external dependency, purely frontend.

How it works

  • Detached sessions render as draggable, resizable position: fixed panels within the main Wails window.
  • Each panel contains its own Vue component instance (terminal emulator or RDP canvas).
  • Panels can be minimised, maximised within the viewport, or snapped to edges.

Pros

  • Zero dependency on Wails multi-window API.
  • Works on any platform without additional testing.
  • Simpler state management — everything lives in one window context.

Cons

  • Sessions share the same viewport — limited screen real estate.
  • Cannot span multiple monitors.
  • Feels less native than real OS windows.

Implementation cost

Small. Requires a <FloatingPanel> wrapper component with drag/resize handlers. Libraries like vue3-draggable-resizable exist but a lightweight custom implementation (~150 LOC) is preferable to avoid dependency churn.


Plan C: Browser Mode

Status: EMERGENCY — last resort if both Plan A and Plan B are inadequate.

How it works

  • Wails v3 supports a server mode where the frontend is served over HTTP on localhost.
  • Detached sessions open in the user's default browser via open(url, '_blank') or runtime.BrowserOpenURL().
  • The browser tab communicates with Go services through the same HTTP endpoint.

Pros

  • Guaranteed to work — it is just a web page.
  • Users can arrange tabs freely across monitors.

Cons

  • Breaks the desktop-app experience.
  • Browser tabs lack access to Wails runtime bindings; all communication must go through HTTP/WebSocket, requiring a parallel transport layer.
  • Security surface increases — localhost HTTP server is accessible to other local processes.

Recommendation

Start with Plan A. The Wails v3 NewWithOptions API is documented and consistent with how other multi-window desktop frameworks (Electron, Tauri v2) work. The alpha stability risk is mitigated by wrapping calls behind an internal interface.

If Plan A fails during Windows validation, Plan B requires only frontend CSS changes — no backend work is wasted. Plan C is reserved for scenarios where neither A nor B is viable.

Next Step

Validate Plan A on Windows during Phase 2 when SSH sessions exist and there is a real payload to render in a second window.