Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
dd0c557
docs: ratify UI client split (Option C) — revise runtime-modes plan
claude Jul 6, 2026
763eb11
docs: link new issues #555-#557 into the runtime-modes plan phases
claude Jul 6, 2026
483b4bf
test(phase-1): red tests for #509
claude Jul 6, 2026
71f1686
feat(ui): RuntimeContext v2 — server context, capabilities, /api/runt…
claude Jul 6, 2026
538393b
test(phase-1.5): red tests for #556
claude Jul 6, 2026
fc4c254
feat(cli): add `openpalm admin` — host-ui admin serve mode (#556)
claude Jul 6, 2026
e777688
docs: document the three ways to reach the admin surface (#556)
claude Jul 6, 2026
5e0f2d5
test(phase-2): red tests for #486
claude Jul 6, 2026
4632135
feat(ui): add ConnectionKind + connection-language model to the endpo…
claude Jul 6, 2026
efaffaa
feat(ui): add capability-guarded /api/connections routes (#486)
claude Jul 6, 2026
f67585f
refactor(ui): untangle endpoints-state from chat-state via connection…
claude Jul 6, 2026
b7b8fb3
feat(ui): move connection management to /connections; alias /admin/en…
claude Jul 6, 2026
23fd94c
fix(ui): point EndpointList manage-connections link at /connections (…
claude Jul 6, 2026
e039fae
test(phase-3): red tests for plan Phase 3
claude Jul 6, 2026
d4cd80f
feat(ui): capability-driven landing via resolveLanding(); split /spla…
claude Jul 6, 2026
90b7513
refactor(ui): capability-driven navigation; untangle admin chrome fro…
claude Jul 6, 2026
0f9c2fa
docs: add ui-route-map.md — routes, surfaces, guards after Phase 3 (#…
claude Jul 6, 2026
89a6417
test(phase-4): red tests for plan Phase 4
claude Jul 6, 2026
98567c0
feat(ui): move session lifecycle endpoints to /api/auth/* (#555)
claude Jul 6, 2026
2ba5304
feat(ui): split host and assistant control planes — /host + /api/host…
claude Jul 6, 2026
a25cf7c
docs: update route map + API spec for the Phase 4 control-plane split…
claude Jul 6, 2026
5a4f115
test(ui): update browser-project tests for the /admin -> /host split …
claude Jul 6, 2026
1bd98f3
docs: mark Phases 1-4 (+1.5) DONE in ui-runtime-modes-plan (#509, #55…
claude Jul 6, 2026
514f0a2
test(p5a): red tests for #555
claude Jul 6, 2026
93fadfd
feat(ui-kit): extract shared components, icons, and theme tokens into…
claude Jul 6, 2026
c7d53ab
fix(ui-kit): decouple Toast from voice-state; add svelte-check type g…
claude Jul 6, 2026
424d091
test(p5b): WIP client test scaffold (interrupted by spend limit; resu…
claude Jul 6, 2026
e8e67b1
test(p5b): red tests for #555
claude Jul 6, 2026
a049f06
feat(client): transport, connection store, and landing resolver (#555)
claude Jul 6, 2026
93cebe8
feat(client): SvelteKit static app, views, serve script, workspace wi…
claude Jul 6, 2026
c6f38a4
test(p5b): red test — serve.mjs must survive malformed percent-escape…
claude Jul 6, 2026
c036bba
fix(client): serve.mjs returns 400 on malformed percent-escapes inste…
claude Jul 6, 2026
9f79b1c
docs: Phase 5 completion guide — P5a/P5b as-built, P5c-P5e handoff (#…
claude Jul 6, 2026
90edbd3
test(p5c): red tests for #555
claude Jul 6, 2026
002f019
feat(lib): client-assets — resolve/seed/update @openpalm/client (#555)
claude Jul 6, 2026
d9102bb
feat(cli): serve @openpalm/client on stable loopback port 3890 (#555)
claude Jul 6, 2026
05086ed
feat(electron): client server child + window prefers the client chat …
claude Jul 6, 2026
034da91
test(p5d): red tests for #510
claude Jul 6, 2026
f2106d1
feat(assistant): container serves @openpalm/client on a published por…
claude Jul 6, 2026
d33f650
test(p5e): red tests for #555
claude Jul 6, 2026
5f4c532
feat(release): @openpalm/client joins the publish DAG + platform stam…
claude Jul 7, 2026
90a1494
ci(test): run the client suite + bundle purity gate in CI and the roo…
claude Jul 7, 2026
3421395
docs(release): record @openpalm/client in release architecture, plan,…
claude Jul 7, 2026
1748915
docs(plan): mark Phase 5 DONE with as-built notes (#555, #510)
claude Jul 7, 2026
49bab70
Merge remote-tracking branch 'origin/main' into claude/ui-runtime-mod…
claude Jul 7, 2026
ac1c5ea
fix(ui): route main's new chat/voice icon imports through @openpalm/u…
claude Jul 7, 2026
a3e1fdf
docs(plan): §12 remaining-work handoff — verified statuses, chat pari…
claude Jul 7, 2026
bb237d2
fix(runtime): address client app review fixes
itlackey Jul 7, 2026
3bd0a37
fix(ci): isolate admin tests and allow client bootstrap
itlackey Jul 7, 2026
76b1d6f
fix(ci): prevent lib mock leakage in admin tests
itlackey Jul 7, 2026
4e1d647
fix(ci): reset cli-state in admin tests
itlackey Jul 7, 2026
f9f0158
fix(ci): avoid toxic status test lib mock
itlackey Jul 7, 2026
bcc8d88
fix(runtime): cover client artifact upgrade paths
itlackey Jul 7, 2026
ed02f79
fix(ci): allow electron client bootstrap import
itlackey Jul 7, 2026
0526661
fix(runtime): address PR #559 follow-ups
itlackey Jul 8, 2026
28c294b
fix(stack): pass skeleton version to assistant
itlackey Jul 8, 2026
c3cecf3
docs(release): add unit=all rc checklist
itlackey Jul 8, 2026
efe9697
fix(release): support guardian dry-run and smoke builds
itlackey Jul 8, 2026
210d3dd
docs(release): add rc runbook
itlackey Jul 8, 2026
f1e4850
fix(cli): normalize install file setup UX
itlackey Jul 8, 2026
8813d9b
fix(ui): read persisted assistant port for default endpoint
itlackey Jul 8, 2026
b629dc5
fix(ui): stabilize release candidate test gates
itlackey Jul 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .github/release-package-groups.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"packages/lib/package.json",
"packages/cli/package.json",
"packages/ui/package.json",
"packages/client/package.json",
"packages/electron/package.json",
"packages/electron/admin-tools/package.json"
],
Expand Down
15 changes: 14 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,23 @@ jobs:
- name: Type check admin UI
run: cd packages/ui && bun run check

- name: Type check UI kit
run: cd packages/ui-kit && bun run check

- name: Type check client app
run: cd packages/client && bun run check

- name: Type check CLI
run: cd packages/cli && bun run typecheck

- name: Test (sdk + guardian + portals)
# Client-bundle purity gate (plan §8.5/§8.10): packages/client/tests/
# purity.test.ts greps the BUILT bundle for '@openpalm/lib' and
# '/api/host' and deliberately FAILS when build/ is absent — so the
# client must be built before `bun run test` runs packages/client.
- name: Build client app (input to the client purity gate)
run: bun run client:build

- name: Test (sdk + guardian + portals + client purity gate)
run: bun run test

- name: Validate Docker Compose manifests
Expand Down
58 changes: 50 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ name: Release
# its own slice. A partial unit will silently leave the other units behind (e.g.
# `platform` does NOT touch the portal image or the discord/slack npm adapters).
# For a complete, coordinated release of the whole platform, use `all`.
# platform — @openpalm/lib + openpalm (CLI) + @openpalm/ui (npm) + admin-tools +
# CLI native binaries + optional Electron + git tag + GitHub release
# platform — @openpalm/lib + openpalm (CLI) + @openpalm/ui + @openpalm/client (npm) +
# admin-tools + CLI native binaries + optional Electron + git tag + GitHub release
# (add include_images=true to also rebuild guardian + assistant images).
# PARTIAL: no portal image, no portal npm, no voice.
# portals — @openpalm/discord-portal + @openpalm/slack-portal npm packages
Expand All @@ -26,7 +26,7 @@ name: Release
# Always pass version explicitly (the version the existing npm packages are at). PARTIAL.
# all — COMPLETE coordinated release. Publishes EVERY unit at one version,
# flag-free (no include_images / include_electron needed):
# npm: @openpalm/{lib,ui,guardian,skeleton} + openpalm (CLI)
# npm: @openpalm/{lib,ui,client,guardian,skeleton} + openpalm (CLI)
# + @openpalm/{discord,slack}-portal
# images: openpalm/{assistant,guardian,portal} (+ :latest when stable)
# electron installers (mac/linux/win) + CLI native binaries
Expand Down Expand Up @@ -172,8 +172,8 @@ jobs:
// platform release can never compute a next version at or below an
// already-published skeleton/guardian, which npm rejects.
const npmPackages = {
platform: ['@openpalm/lib', 'openpalm', '@openpalm/ui', '@openpalm/skeleton', '@openpalm/guardian'],
all: ['@openpalm/lib', 'openpalm', '@openpalm/ui', '@openpalm/skeleton', '@openpalm/guardian'],
platform: ['@openpalm/lib', 'openpalm', '@openpalm/ui', '@openpalm/client', '@openpalm/skeleton', '@openpalm/guardian'],
all: ['@openpalm/lib', 'openpalm', '@openpalm/ui', '@openpalm/client', '@openpalm/skeleton', '@openpalm/guardian'],
guardian: ['@openpalm/guardian', '@openpalm/skeleton'],
};
const packages = npmPackages[unit] || [];
Expand Down Expand Up @@ -253,8 +253,13 @@ jobs:
if: inputs.unit == 'platform' || inputs.unit == 'all'
run: |
bun install --frozen-lockfile
# The client purity gate greps the BUILT bundle (packages/client/tests/
# purity.test.ts fails when build/ is absent), so build before bun run test.
bun run client:build
bun run test
bun run ui:check
bun run ui-kit:check
bun run client:check
bun run --cwd packages/ui test:browsers
bun run ui:test:unit
bun run electron:test
Expand Down Expand Up @@ -304,7 +309,8 @@ jobs:
platform)
for f in package.json packages/lib/package.json packages/skeleton/package.json \
packages/guardian/package.json packages/cli/package.json \
packages/ui/package.json packages/electron/package.json \
packages/ui/package.json packages/client/package.json \
packages/electron/package.json \
packages/electron/admin-tools/package.json; do
node scripts/set-version.mjs "$f" "$V"
done
Expand All @@ -314,7 +320,8 @@ jobs:
all)
for f in package.json packages/lib/package.json packages/skeleton/package.json \
packages/guardian/package.json packages/cli/package.json \
packages/ui/package.json packages/electron/package.json \
packages/ui/package.json packages/client/package.json \
packages/electron/package.json \
packages/electron/admin-tools/package.json; do
node scripts/set-version.mjs "$f" "$V"
done
Expand Down Expand Up @@ -382,7 +389,7 @@ jobs:
# ── npm layer ─────────────────────────────────────────────────────────────────
# skeleton + guardian: published for unit=guardian (thin-host needs both at runtime)
# and unit=platform + unit=all (full coordinated release)
# lib + cli + ui: platform + all only (guardian npm pkg has no lib dep)
# lib + cli + ui + client: platform + all only (guardian npm pkg has no lib dep)
# NOTE: guardian and skeleton are published independently of lib to avoid
# blocking the platform regression guard. lib is platform-managed.
npm-skeleton:
Expand Down Expand Up @@ -463,6 +470,28 @@ jobs:
exact-version: true
dry-run: ${{ inputs.dry_run }}

# Client app (@openpalm/client): exact-pin delivered like @openpalm/ui — the
# assistant container installs @openpalm/client@<platform version> at startup
# (ui-runtime-modes-plan.md §1 exact-pin table, Phase 5 item 5). needs-build
# compiles the adapter-static bundle; @openpalm/ui-kit is inlined from the
# workspace at build time (raw-source, NEVER published). Unlike npm-ui there
# is no npm-lib ordering dependency: the client never bundles @openpalm/lib
# (§8.10 purity rule, enforced by packages/client/tests/purity.test.ts in CI).
npm-client:
name: npm @openpalm/client
needs: [compute-version, bump]
if: always() && needs.bump.result == 'success' && (inputs.unit == 'platform' || inputs.unit == 'all')
uses: ./.github/workflows/publish-npm-package.yml
secrets: inherit
with:
package-dir: packages/client
package-name: '@openpalm/client'
needs-build: true
version: ${{ needs.compute-version.outputs.new_version }}
ref: ${{ github.ref_name }}
exact-version: true
dry-run: ${{ inputs.dry_run }}

# Portal adapters: the portal image bun-installs these from npm at runtime
# (data/portal/tools/package.json + bun update), so a published patch reaches
# running portals without an image rebuild. Published as `src` only (no build).
Expand Down Expand Up @@ -508,6 +537,11 @@ jobs:
- uses: actions/checkout@v6
with:
ref: ${{ github.ref_name }}
- name: Stamp local guardian/skeleton sources for dry-run image build
if: ${{ inputs.dry_run }}
run: |
node scripts/set-version.mjs packages/guardian/package.json "${{ needs.compute-version.outputs.new_version }}"
node scripts/set-version.mjs packages/skeleton/package.json "${{ needs.compute-version.outputs.new_version }}"
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
Expand Down Expand Up @@ -563,6 +597,11 @@ jobs:
- uses: actions/checkout@v6
with:
ref: ${{ github.ref_name }}
- name: Stamp local guardian/skeleton sources for dry-run image build
if: ${{ inputs.dry_run }}
run: |
node scripts/set-version.mjs packages/guardian/package.json "${{ needs.compute-version.outputs.new_version }}"
node scripts/set-version.mjs packages/skeleton/package.json "${{ needs.compute-version.outputs.new_version }}"
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
Expand Down Expand Up @@ -593,6 +632,8 @@ jobs:
file: containers/guardian/Dockerfile
build-args: |
GUARDIAN_VERSION=${{ needs.compute-version.outputs.new_version }}
GUARDIAN_USE_LOCAL_SOURCE=${{ inputs.dry_run && 'true' || 'false' }}
SKELETON_USE_LOCAL_SOURCE=${{ inputs.dry_run && 'true' || 'false' }}
platforms: ${{ inputs.dry_run && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
push: ${{ !inputs.dry_run }}
# Provenance/SBOM attestations add extra manifests + blobs that make
Expand Down Expand Up @@ -781,6 +822,7 @@ jobs:
- npm-guardian
- npm-cli
- npm-ui
- npm-client
- npm-discord-portal
- npm-slack-portal
- docker-portal
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ CLAUDE.md
packages/ui/.svelte-kit/
packages/ui/build/
packages/ui/dist/
packages/client/build/
packages/ui/undefined/
packages/ui/.env
packages/ui/.env.local
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Added

- **New `@openpalm/client` npm package** — the unprivileged chat/connections
static app extracted from the admin UI (host/client split, #555). It joins the
platform release exactly like `@openpalm/ui`: published by `platform`/`all`
releases, always exact-pinned to the platform version. The assistant container
installs it at startup as a co-process next to OpenCode (#510), pinned via
**`OP_CLIENT_VERSION`** in `stack.env` (empty = the image's `PLATFORM_VERSION`;
never `latest` — the same contract as `OP_UI_VERSION` for the host UI), and
serves it on **`OP_CLIENT_PORT`** (default host bind `127.0.0.1:3810`, behind
the existing `OP_CLIENT_BIND_ADDRESS`/`OP_BIND_ADDRESS` loopback policy).
`docker restart` with a new `OP_CLIENT_VERSION` picks up the new client. CI now
enforces a client-bundle purity gate: the built artifact must contain no
`@openpalm/lib` and no host control-plane (`/api/host`) code. The shared
`@openpalm/ui-kit` workspace package is inlined at build time and is never
published.
- The guardian thin-host entrypoint can now install and boot a configurable
guardian composition package via `OP_GUARDIAN_PACKAGE` (default
`@openpalm/guardian`) with an overridable boot entry `OP_GUARDIAN_ENTRY`
Expand Down
Loading