# Ubuntu Dashboard Space — Design Status: design. Goal: a macOS-Dashboard-style **dedicated rightmost workspace** on GNOME/Ubuntu that hosts user-defined widgets. Widgets are written against a TypeScript SDK and rendered as web components inside an embedded WebKit view; the GNOME Shell extension is the workspace warden and the IPC bridge, nothing heavier. Codename: **Dashward** (decided 2026-05-22; see §19). --- ## 1. Goals & non-goals ### Goals - A workspace that is **created by the extension** at enable time, lives at the rightmost position, and is **destroyed** at disable time. It is not one of the user's existing workspaces, even temporarily. - **Regular windows cannot enter it** — neither by overview drag, by `super+shift+arrow`, by `wmctrl`/`xdotool`, nor by being newly mapped there. Attempts get bounced to the prior workspace immediately. - Widgets are **web components in TS**. A buggy widget cannot take down GNOME Shell. - Hot-reload during widget development. - Light/dark theme follows the system. - Zero hand-edits to user dotfiles outside `~/.local/share/dashward/` and the extension install dir. ### Non-goals (v1) - Cross-distro support beyond Ubuntu 25.04 / GNOME 48. KDE, XFCE, Cinnamon are out of scope until v1 lands and stabilizes. - A widget marketplace, signing, or sandboxing beyond what WebKit's process model already provides. Widgets are trusted code at v1. - macOS-style "ripple in" widget add animation. Edit mode is utilitarian. - Multi-monitor span: dashboard appears on the **primary** monitor only; other monitors get the regular last-workspace view. - Replacing the regular workspace switcher UX. The dashboard is reached by a dedicated gesture/shortcut, not by being workspace N+1 in the existing switcher. --- ## 2. Hard constraints (carried from chat) | C# | Constraint | Resolution | |---|---|---| | C1 | Dashboard does **not** reuse any existing workspace | §5: append a new workspace at enable, mark it, remove at disable | | C2 | Dashboard is **always rightmost** | §5: position invariant maintained on every workspace mutation | | C3 | Regular windows cannot be **dragged into** dashboard | §6: layered defense on `window-added`, overview drop target, gesture handlers | | C4 | Widgets in **TypeScript** | §9: SDK is a TS package; widgets are TS modules bundled to ESM | | C5 | Avoid the GridSpaces lockout failure mode | §17: VM-only iteration loop; extension never touches `gnome-extensions enable` on host until VM-green | --- ## 3. Reality check (probed 2026-05-22 on ubuntu2504-test) | Component | Version | Note | |---|---|---| | Ubuntu | 25.04 (Plucky) | | | GNOME Shell | 48.0-1ubuntu1 | ESM extension format | | Mutter | 48.1 (`libmutter-16-0`) | API gen 16, `Meta.WorkspaceManager` stable | | gjs | 1.82.1 | SpiderMonkey 128 era — ESM, top-level await OK | | WebKit2GTK 4.1 (GTK3) | 2.50.4 + `gir1.2-webkit2-4.1` pre-installed | **Chosen** for the container — zero new GIR deps | | WebKitGTK 6.0 (GTK4) | 2.50.4 lib present, GIR not installed | Migration target post-v1 | | Session | Wayland (gdm `Ubuntu on Wayland` default) | | | Pre-existing ext | `ding`, `tiling-assistant`, `ubuntu-appindicators`, `ubuntu-dock` | tiling-assistant is the relevant precedent for window manipulation | Implication: we can build v1 with only what's already on disk — no new apt packages required. (Build chain is in dev only; not shipped onto the VM at runtime.) --- ## 4. Architecture Three processes, two IPC channels: ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ gnome-shell (GJS, in-process) │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ Dashward extension │ │ │ │ • WorkspaceWarden (create/destroy + position invariant) │ │ │ │ • WindowGuard (block window-added on dashboard ws) │ │ │ │ • EntryUX (gesture, shortcut, panel indicator) │ │ │ │ • ContainerSupervisor (spawn/respawn web container, pin window) │ │ │ │ • DBusService "top.hangmanlab.Dashward.Shell" │ │ │ └─────────┬────────────────────────────────────────────────────────┘ │ └────────────┼────────────────────────────────────────────────────────────┘ │ DBus session bus ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ dashward-container (GJS + WebKit2 4.1, separate process) │ │ • One GtkWindow, fullscreen, undecorated, app_id = container │ │ • WebKitWebView loads file://…/dashboard.html │ │ • DBus client: pushes shell events into the page via │ │ UserContentManager.evaluate_javascript() │ │ • UserContentManager script-message handlers receive page→shell calls │ └─────────────────────────────────────────────────────────────────────────┘ │ WebKit user-content-manager bridge ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ dashboard.html (WebKit content process, sandboxed by WebKit) │ │ • Runtime: dashboard-runtime.js (host shell, layout grid, edit mode) │ │ • SDK: @dashward/widget-sdk (TS, bundled in) │ │ • Widgets: each loaded into its own