Skip to content

Extract packages/client (@openpalm/client) + packages/ui-kit — thin static client app (Phase 5) #555

Description

@fwdslsh-dev

Summary

Extract the end-user surface (chat, connection switching, assistant-settings views) into a new packages/client (@openpalm/client) — a static, PWA-ready SvelteKit app — plus packages/ui-kit, a raw-source workspace package for shared components/icons/theme. packages/ui remains the host control plane and is not renamed or split further.

Ratified 2026-07-06: docs/technical/ui-client-split-assessment.md (options considered, evidence). Design: docs/technical/ui-runtime-modes-plan.md §6.11, Phase 5.

Why (short version)

  • The transport forks anyway. Host modes chat through the same-origin server proxy with cookies; PWA/container modes need direct cross-origin guardian calls with Basic/Bearer and client-held connections. Two apps = one transport each; one app = mode branches in the data layer.
  • A hosted install origin requires a static client. The adapter-node control plane is machine-bound; https://app.openpalm.dev can only ever serve static files.
  • Structural exclusion beats runtime 403s. Container and PWA artifacts contain no host-admin code and no @openpalm/lib.
  • SvelteKit has no per-build route exclusion (kit#6031 removed config.kit.routes) — two thin apps sharing a workspace package is the grain-of-the-tool pattern.
  • By LOC the client is the small slice: chat ≈ 6.6k vs admin/setup ≈ 22.5k of ~44k total. This is "move one-fifth", not "move four-fifths".

Design

packages/client/            # @openpalm/client — published, exact-pin delivery
  svelte.config.js          # adapter-static, SPA fallback
  vite.config.ts            # @vite-pwa/sveltekit (Phase 6)
  src/routes/{chat,connections,assistant/settings}
  src/lib/transport/        # ONE transport: guardian/OpenCode base URL + credentials
                            # connections in IndexedDB

packages/ui-kit/            # raw-source workspace package — NOT published
  src/lib/components/       # common/, icons/, chrome primitives
  src/lib/theme/            # tokens, design vocabulary (coordinates with #506)

Rules (plan §8):

  • client never bundles @openpalm/lib, has no src/lib/server/, never holds host credentials.
  • ui-kit is presentational only — no stores with server assumptions.
  • Simplicity guardrail: two UI packages max (client, ui-kit). No further splits.

Prerequisites (untangling, already scheduled in Phases 2–3)

After those land, this extraction is file relocation, not surgery.

Acceptance criteria

  • packages/client builds a self-contained static bundle; bun run check clean in both apps
  • Chat in Electron runs from the client build (harness serves it on a stable loopback port alongside the host app); packages/ui chat is deleted once parity is confirmed
  • Client transport works against: local OpenCode (loopback), LAN guardian (plain HTTP from a loopback origin), remote guardian (HTTPS + Basic/Bearer)
  • Connections persist in IndexedDB, readable offline
  • @openpalm/client added to the publish DAG + exact-pin artifact table (OP_CLIENT_VERSIONPLATFORM_VERSION → error)
  • CI build assertion: client artifact contains no host-admin code and no @openpalm/lib

Unblocks

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions