Symptom
Launching the dashboard in app mode (--app) does not give cldctrl its own taskbar button or icon. cldctrl, another local app-mode tool (PhysioMetrics), and the user's ordinary Chrome browsing window all collapse into a single Chrome taskbar button with the Chrome icon — so you can't click between them as distinct apps.
Measured evidence (not a guess)
Enumerated top-level windows of the running chromium processes and read PKEY_AppUserModel_ID (fmtid 9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3, pid 5) via SHGetPropertyStoreForWindow:
chrome "(5 live) App Analytics · Usage Map" -> AUMID unset (inherits process/exe default)
chrome "PhysioMetrics" -> AUMID unset (inherits process/exe default)
chrome "⌃ CLD CTRL" -> AUMID unset (inherits process/exe default)
Every window falls back to chrome.exe's identity → Windows groups them. Correct behaviour, wrong identity.
Root cause
packages/cli/src/…/app-launch:
const args = [`--app=${target}`, '--new-window'];
if (isolated) args.push(`--user-data-dir=${dir}`);
--app=URL + --user-data-dir is not enough. --app only removes browser chrome; --user-data-dir only isolates the profile/process tree. Neither creates a Windows app identity. Chromium mints a per-app AUMID only for installed web apps — not ad-hoc --app=URL windows. There is no Chromium switch that sets an arbitrary AUMID (--app-id selects an already installed app; it is not an AUMID setter).
This is presumably why the CLI already carries --shared-profile and a "chrome (default; better taskbar icon)" note — same wall, worked around rather than fixed.
Options (reviewed with a second agent)
-
Installed PWA + --app-id — Chromium assigns a real AUMID/icon/taskbar button. --app-id=<id> is a real, current Chromium switch; the ID derives from the manifest ID (double SHA-256 + extension-style a–p encoding). Don't reproduce that algorithm — read the ID from the shortcut Chromium generates at install, or chrome://web-app-internals. Caveats: there is no supported way to install a PWA silently into a consumer profile (WebAppInstallForceList is enterprise policy — mandatory, un-uninstallable, registry-based; inappropriate here), and a Chrome-installed app is not visible to Edge, so "Chrome preferred, Edge fallback" becomes install state you must persist (browser + user-data-dir + profile-directory + app id).
Relevant to cldctrl specifically: the dashboard serves on a fixed port (2533 default) → stable origin, which makes this path far more viable for cldctrl than for an app on a dynamic port (a changing port changes the origin and therefore the PWA identity; an explicit manifest id cannot rescue that). Note the bootstrap caveat still applies: a pinned PWA shortcut relaunches the browser, it does not start the cldctrl server.
-
Set the AUMID on the window yourself — SHGetPropertyStoreForWindow + IPropertyStore::SetValue(PKEY_AppUserModel_ID). Two corrections worth recording: per-window AUMIDs are officially supported (the "must set before the window is shown" rule applies to the process-level SetCurrentProcessExplicitAppUserModelID, and a window-level ID overrides the process one), and Commit() is not needed for this property store — SetValue applies immediately. Practical notes: don't match the HWND by title — hook window create/show (SetWinEventHook), filter by PID/process tree + the Chrome_WidgetWin_1 frame class; also set RelaunchCommand/RelaunchIconResource and put the same AUMID on the shortcut. Still fragile: you're mutating a window Chrome owns, across browser updates.
-
Native shell (Tauri / WebView2) — owns its own top-level HWND and can set its process AUMID before any UI. The durable answer, but a much bigger change.
Suggested
For cldctrl the fixed port makes (1) genuinely attractive; (2) is a reasonable bridge behind a flag. Filed so it's tracked — the same root cause is tracked on the PhysioMetrics side too.
Reported from a PhysioMetrics session at the operator's request.
Symptom
Launching the dashboard in app mode (
--app) does not give cldctrl its own taskbar button or icon. cldctrl, another local app-mode tool (PhysioMetrics), and the user's ordinary Chrome browsing window all collapse into a single Chrome taskbar button with the Chrome icon — so you can't click between them as distinct apps.Measured evidence (not a guess)
Enumerated top-level windows of the running chromium processes and read
PKEY_AppUserModel_ID(fmtid9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3, pid 5) viaSHGetPropertyStoreForWindow:Every window falls back to
chrome.exe's identity → Windows groups them. Correct behaviour, wrong identity.Root cause
packages/cli/src/…/app-launch:--app=URL+--user-data-diris not enough.--apponly removes browser chrome;--user-data-dironly isolates the profile/process tree. Neither creates a Windows app identity. Chromium mints a per-app AUMID only for installed web apps — not ad-hoc--app=URLwindows. There is no Chromium switch that sets an arbitrary AUMID (--app-idselects an already installed app; it is not an AUMID setter).This is presumably why the CLI already carries
--shared-profileand a "chrome (default; better taskbar icon)" note — same wall, worked around rather than fixed.Options (reviewed with a second agent)
Installed PWA +
--app-id— Chromium assigns a real AUMID/icon/taskbar button.--app-id=<id>is a real, current Chromium switch; the ID derives from the manifest ID (double SHA-256 + extension-style a–p encoding). Don't reproduce that algorithm — read the ID from the shortcut Chromium generates at install, orchrome://web-app-internals. Caveats: there is no supported way to install a PWA silently into a consumer profile (WebAppInstallForceListis enterprise policy — mandatory, un-uninstallable, registry-based; inappropriate here), and a Chrome-installed app is not visible to Edge, so "Chrome preferred, Edge fallback" becomes install state you must persist (browser + user-data-dir + profile-directory + app id).Relevant to cldctrl specifically: the dashboard serves on a fixed port (2533 default) → stable origin, which makes this path far more viable for cldctrl than for an app on a dynamic port (a changing port changes the origin and therefore the PWA identity; an explicit manifest
idcannot rescue that). Note the bootstrap caveat still applies: a pinned PWA shortcut relaunches the browser, it does not start the cldctrl server.Set the AUMID on the window yourself —
SHGetPropertyStoreForWindow+IPropertyStore::SetValue(PKEY_AppUserModel_ID). Two corrections worth recording: per-window AUMIDs are officially supported (the "must set before the window is shown" rule applies to the process-levelSetCurrentProcessExplicitAppUserModelID, and a window-level ID overrides the process one), andCommit()is not needed for this property store —SetValueapplies immediately. Practical notes: don't match the HWND by title — hook window create/show (SetWinEventHook), filter by PID/process tree + theChrome_WidgetWin_1frame class; also setRelaunchCommand/RelaunchIconResourceand put the same AUMID on the shortcut. Still fragile: you're mutating a window Chrome owns, across browser updates.Native shell (Tauri / WebView2) — owns its own top-level HWND and can set its process AUMID before any UI. The durable answer, but a much bigger change.
Suggested
For cldctrl the fixed port makes (1) genuinely attractive; (2) is a reasonable bridge behind a flag. Filed so it's tracked — the same root cause is tracked on the PhysioMetrics side too.
Reported from a PhysioMetrics session at the operator's request.