Managed Desktop Runtime, Companion, and Demo Mode
This guide owns the packaged Electron desktop application (apps/desktop/):
bundled runtime payloads (managed Pi, PortableGit, fd/ripgrep), asar
packaging invariants, the Desktop Companion floating window, and isolated
Electron/browser Demo Mode. Project/home selection belongs to
alice-project; AI credential and model projection belong to
alice-harness.
1. Packaged Desktop Runtime Contract
A packaged OpenAlice desktop app opens a Workspace on a fresh macOS or Windows machine without requiring the user to pre-install Node, npm, Git, Bash, or an agent CLI:
- Bundled payloads (
scripts/vendor-managed-runtime.mjs): Checksum-verified and pinned invendor/manifest.json:vendor/pi/: isolatednpm ci --omit=devPi installation launched via[OPENALICE_MANAGED_PI_NODE_PATH, OPENALICE_MANAGED_PI_PATH, ...args]withELECTRON_RUN_AS_NODE=1(never exposed as a globalpibinary onPATH).vendor/tools/<platform>-<arch>/bin:fdandripgrepso Pi never downloads per-Workspace tools.vendor/git/<platform>-<arch>/(Windows): PortableGit (git,bash,sh, and POSIX utilities) injected onto Workspace childPATH. Windows shell preference lives in~/.openalice/state/workspace-shell.json(Autouses packaged PortableGit;Customrequires an explicit validbash.exeand never silently falls back).
- Windows shim safety: npm/pnpm
.cmdagent shims reduce to their JS entrypoint on Node or native.exe/.comwithshell: false; batch-only shims fail withunsupported_windows_batch_shim. Workspace CLIs (alice,traderhub,alice-uta) runopenalice-cli.cjsvia Electron's Node mode. - Pi trust & theme boundary: Before TUI/Web launch, the Pi adapter marks
undecided OpenAlice-managed Workspaces trusted in Pi's trust store without
overriding explicit user allow/deny choices. Packaged headless runs pass
--approve; interactive runs do not. Provider overrides stay Workspace-local (.pi/extensions/openalice-provider.ts+.pi/settings.json) and never write to the user's global~/.pi/directory.
Packaging invariants (pnpm electron:pack)
asaris enabled; JS entrypoints live insideapp.asarwhileextraResourcesplacesvendor/, CLI shims, templates, and UI assets under physicalResources/runtime(OPENALICE_APP_HOME). Never resolve backend JS entrypoints fromOPENALICE_APP_HOME.asarUnpackunpacksnode-ptyanddugite(macOS uses embedded dugite Git; Windows excludesnode_modules/dugite/git/**anchored by a positivepackage.jsonpattern and routes through PortableGit).openalice-update-attempt.jsonanddesktop.loglive in machine-local ElectronuserData, never insideOPENALICE_HOME.
2. AI Credential Setup UI Contract
Settings → AI Provider validates account → region/endpoint → compatible Workspace Agent runtimes → model ID via a live probe before saving:
- Google Gemini uses the native
google-generative-aiwire (x-goog-api-key), never Google's OpenAI-compatibility Bearer endpoint. - Anthropic-wire credentials distinguish first-party
x-api-keyfrom gatewayAuthorization: Bearer(never sending both). - Claude Code global onboarding/trust booleans are read-only advisories (never written by OpenAlice; unknown state fails open).
3. Desktop Companion (Floating Pet Window)
apps/desktop/src/app-window.ts starts one floating companion window sharing
the Electron main process (no extra Guardian/Alice/UTA process;
OPENALICE_DISABLE_COMPANION=1 disables it):
- Window & lifecycle: Closing the main window hides it while tray,
companion, and services stay running; only explicit Quit stops services and
destroys the companion. Position, size (in DIPs across monitor work areas),
and visibility persist in Electron
userData/companion.json; click audio settings (≤10s, ≤2 MB local WAV/MP3/OGG data URL) persist inuserData/companion-sound.json. - Security: Dedicated narrow preload, sender/frame-checked IPC, context
isolation,
connect-src 'none', and no renderer Node APIs. - Activity notifications (
userData/activity-notifications.json): One main-process controller polls the Product Activity Journal every 4s. Visible main windows use top-right Sonner toasts (up to 3); hidden/minimized windows route to an already-visible companion bubble (1 bubble, brief mode by default). Clicking a notification validates the active display token and opens only Office, Inbox, or News routes.
4. Demo Mode (Browser and Native Electron)
Demo mode previews populated frontend states (ui/src/demo/handlers/ and
ui/src/demo/fixtures/) without configuring AI credentials, brokers, or agent
CLIs:
pnpm -F open-alice-ui dev:demo # browser Demo Mode (MSW Service Worker)
pnpm electron:demo # native Electron Demo Mode (child IPC MSW)
pnpm electron:smoke:demo # automated native Electron demo smoke
- Process & credential isolation: Native
pnpm electron:demobuildsui/dist-demo/anddist/demo/, seeds an isolated temporaryopenalice-demo-*home for real file IPC reads, disables updates, analytics, and data-home switching, and exits cleanly when the window closes. It never starts production Guardian, Alice, UTA, Connector, or agent processes, never passes provider credentials to the fixture child, and fails unmocked/api/*requests explicitly with HTTP501. - Demo query parameters exercise recovery states without real mutations:
?workspaceSetup=failed|preparing|read-error,/settings/machines?machineScenario=probe-error|blocked|apply-error, and/settings?updates=ready.
5. Verification
pnpm vitest run src/core/runtime-profile.spec.ts \
src/workspaces/agent-detect.spec.ts src/workspaces/spawn-env.spec.ts \
scripts/vendor-managed-runtime.spec.mjs scripts/assert-desktop-package.spec.ts
pnpm electron:tsc
pnpm test:owner:desktop
pnpm electron:smoke:workspace # packaged PTY + scheduled Pi headless smoke
pnpm electron:smoke:demo # native demo smoke