Re-scoped 2026-07-06 (ratified — see docs/technical/ui-client-split-assessment.md)
The PWA is the new @openpalm/client static app (adapter-static + @vite-pwa/sveltekit), not the adapter-node host build. Host features are absent from the artifact, not capability-hidden. Revised design: docs/technical/ui-runtime-modes-plan.md §6.10, Phase 6.
Two primary install origins (simplicity guardrail: TLS is never a manual user task on default paths)
- Localhost (desktop, zero setup). The harness/CLI serves the built client on a stable loopback port (PWA identity = origin incl. port).
http://127.0.0.1 is a secure context → installable with no certificates. A loopback origin is exempt from mixed-content blocking and sits in the most-trusted Private Network Access tier, so it can talk to plain-HTTP LAN guardians. Entry points: Electron menu / host-app button ("Install OpenPalm app") and openpalm app.
- Official hosted URL (e.g.
https://app.openpalm.dev). CI publishes the same static build to a canonical TLS-terminated origin — one install for any phone/tablet, connecting to any of the user's instances.
Platform constraints this design is built around (why the original "same build" scope changed)
- Secure context: a PWA is only installable over HTTPS or from
localhost/127.0.0.1. A UI served over plain HTTP on a LAN IP is never installable — the original plan had no answer for mobile install.
- Mixed content: an HTTPS origin cannot
fetch() plain-HTTP guardians → the hosted path requires guardian TLS (tracked in the Phase 6.5 workstream issue; Tailscale ts.net certs recommended default). Any phone → guardian connection effectively requires TLS.
- Per-origin identity: one installed PWA = one origin; multi-instance switching must be in-app (the
/connections switcher + IndexedDB store), which also means one hosted origin can serve all of a user's instances.
Acceptance criteria
Dependencies
Original scope (2026-06-20) — superseded by the re-scope above
Summary
Make the OpenPalm UI installable as a PWA on mobile and desktop. The PWA is the same SvelteKit build (adapter-node + service worker) — no new UI, no duplicate pages. Capabilities hide host controls when there is no local stack.
Background
The PWA install path enables a phone or tablet to install OpenPalm as an app that connects to a remote assistant (either an assistant-container instance or a full stack behind Guardian). This is the completion of #486 (remote-only install) on mobile.
Design
Full design in docs/technical/ui-runtime-modes-plan.md §6.10 and Phase 6.
What makes it a PWA
Two additions to the existing build:
packages/ui/static/manifest.webmanifest — name, icons, display: standalone, start_url: /
packages/ui/src/service-worker.ts — SvelteKit auto-registers; precaches app shell + static assets
No new pages. No separate build. No duplicate UI code.
How features are hidden
When hostMode === 'pwa-static', resolveCapabilities() returns only:
connections:manage, connections:switch, chat, pwa:install
All components check hasCapability(cap). Host-only nav items are absent because hasCapability('host:stack:read') is false — not because of branching UI code or separate routes.
Effective capability matrix for PWA
| Active connection |
Available |
| None |
/connections/new (landing), pwa:install |
| Remote assistant |
chat, connections:switch, connections:manage |
Remote assistant-container (future, via grantedCapabilities) |
+ assistant-settings:read/write |
Offline support
IndexedDB connection store: connection records are readable offline (cached), writes queued and replayed when reconnected.
Auth
Remote connections use Guardian Basic auth, coordinated with #435 Bearer static token seam.
Acceptance criteria
Dependencies
Related
Re-scoped 2026-07-06 (ratified — see
docs/technical/ui-client-split-assessment.md)The PWA is the new
@openpalm/clientstatic app (adapter-static+@vite-pwa/sveltekit), not the adapter-node host build. Host features are absent from the artifact, not capability-hidden. Revised design:docs/technical/ui-runtime-modes-plan.md§6.10, Phase 6.Two primary install origins (simplicity guardrail: TLS is never a manual user task on default paths)
http://127.0.0.1is a secure context → installable with no certificates. A loopback origin is exempt from mixed-content blocking and sits in the most-trusted Private Network Access tier, so it can talk to plain-HTTP LAN guardians. Entry points: Electron menu / host-app button ("Install OpenPalm app") andopenpalm app.https://app.openpalm.dev). CI publishes the same static build to a canonical TLS-terminated origin — one install for any phone/tablet, connecting to any of the user's instances.Platform constraints this design is built around (why the original "same build" scope changed)
localhost/127.0.0.1. A UI served over plain HTTP on a LAN IP is never installable — the original plan had no answer for mobile install.fetch()plain-HTTP guardians → the hosted path requires guardian TLS (tracked in the Phase 6.5 workstream issue; Tailscalets.netcerts recommended default). Any phone → guardian connection effectively requires TLS./connectionsswitcher + IndexedDB store), which also means one hosted origin can serve all of a user's instances.Acceptance criteria
@vite-pwa/sveltekitinpackages/client: manifest, icons (192/512 + maskable), Workbox app-shell precachehttp://127.0.0.1:<stable port>with zero TLS setup/api/runtimecontract-version handshake: hosted client degrades gracefully against older instancesclientDisplayModeresolves tostandalone-pwaviamatchMediaDependencies
packages/client+packages/ui-kitextraction (tracked separately)Original scope (2026-06-20) — superseded by the re-scope above
Summary
Make the OpenPalm UI installable as a PWA on mobile and desktop. The PWA is the same SvelteKit build (adapter-node + service worker) — no new UI, no duplicate pages. Capabilities hide host controls when there is no local stack.
Background
The PWA install path enables a phone or tablet to install OpenPalm as an app that connects to a remote assistant (either an
assistant-containerinstance or a full stack behind Guardian). This is the completion of #486 (remote-only install) on mobile.Design
Full design in
docs/technical/ui-runtime-modes-plan.md§6.10 and Phase 6.What makes it a PWA
Two additions to the existing build:
packages/ui/static/manifest.webmanifest— name, icons,display: standalone,start_url: /packages/ui/src/service-worker.ts— SvelteKit auto-registers; precaches app shell + static assetsNo new pages. No separate build. No duplicate UI code.
How features are hidden
When
hostMode === 'pwa-static',resolveCapabilities()returns only:connections:manage,connections:switch,chat,pwa:installAll components check
hasCapability(cap). Host-only nav items are absent becausehasCapability('host:stack:read')is false — not because of branching UI code or separate routes.Effective capability matrix for PWA
/connections/new(landing),pwa:installchat,connections:switch,connections:managegrantedCapabilities)assistant-settings:read/writeOffline support
IndexedDB connection store: connection records are readable offline (cached), writes queued and replayed when reconnected.
Auth
Remote connections use Guardian Basic auth, coordinated with #435 Bearer static token seam.
Acceptance criteria
static/manifest.webmanifestpresent; browser shows install prompt on supported platformsclientDisplayModeresolves tostandalone-pwaviamatchMediahasCapability('host:stack:read')returns false in PWA mode — host tabs not visible and not reachable/api/host/*returns 403 even if a PWA client sends a direct request (server-enforced, not just hidden)/connections/new) and open chatDependencies
pwa-statichost mode) — Phase 1/connections— Phase 2/connections/newwhen no connection configuredRelated
docs/technical/ui-runtime-modes-plan.md— §6.10, Phase 6