Release/0.11.0#424
Open
itlackey wants to merge 269 commits into
Open
Conversation
Verified across OpenCode 1.2.24, 1.3.3 (current pin), and 1.14.50 (latest): - Hardcoded baseURL http://127.0.0.1:1234/v1 still present in models.dev catalog - OpenCode supports `provider` (singular) config key to override but no env var - Writing to opencode.json from entrypoint would violate "never overwrite user files" Comment now records: - Versions verified + date - Pointer to upstream provider.ts mergeProvider for the override path - Why env-var override is the missing piece - Link to related upstream issue anomalyco/opencode#1555 - TODO to file a fresh issue requesting env-var override When OpenCode adds env-var override, this whole function + the socat apt-get dependency in the Dockerfile can be deleted. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…tdin pattern (closes #406) (#421) * feat(vault): complete Phase 2 of #388 + migrate to akm secret-store stdin pattern (closes #406) WIP — agent ran out of time before updating 5 tests to match the new architecture. Tests failing on this branch: - cli main > backs up the current OP_HOME (likely hang regression similar to PR #404) - secrets.env generation > user.env as placeholder (Phase 2 deletes user.env) - buildComposeOptions/buildComposeCliArgs (env file list changed) - Fresh install > ensureSecrets user.env placeholder A follow-up fix is needed to update those tests to match the Phase 2 reality. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: align 5 stale assertions with Phase 2 (#388 / closes #406) vault layout Phase 2 retired vault/user/user.env from the compose env_file set and no longer seeds the file on fresh install (akm vault:user is the canonical source). Five tests still encoded the pre-Phase-2 contract and were failing on the WIP branch: * install flow tier 1 (3 tests): - "seed + performSetup..." — drop user.env from regular-files check; assert it is now ABSENT after a fresh setup. - "compose config validates..." — drop --env-file user.env from the compose invocation (it would error with "couldn't find env file"). - "performSetup with no addons..." — same compose-arg fix. * cli main "backs up the current OP_HOME before install --force": bootstrapInstall now uses vault/stack/stack.env as the "already installed" marker (commit f9e0451). Seed both stack.env AND a legacy user.env so the backup path triggers and we can still prove user.env content is preserved in the backup snapshot. * secrets.env generation "...empty placeholder...": Fresh installs no longer create user.env. Assert it is absent and rename the test to reflect the new contract. * Fresh Install "ensureSecrets creates user.env as placeholder...": Same change in the lib edge-case suite — assert user.env is absent while stack.env still gets the seeded keys. No production behavior change beyond what landed in f9e0451; this commit only updates test assertions to match. All 877 tests pass and admin svelte-check reports 0 errors / 0 warnings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(vault): align 10 admin vitest specs with Phase 2 akm-only contract - buildEnvFiles tests: drop user.env from expected outputs (Phase 2 removes user.env from compose env_file list to prevent shadowing akm-sourced values). - ensureSecrets / secrets directory tests: assert vault/user/ directory exists for operational non-env files but user.env is no longer seeded. - user-vault route tests: rewrite to mock @openpalm/lib akm helpers (ensureAkmUserVault / readAkmUserVaultFile / writeAkmVaultKey / deleteAkmVaultKey). Real akm calls go through Bun.spawn which is unavailable inside vitest's Node worker pool; end-to-end coverage of the real akm binary lives in akm-vault.test.ts under bun test. - Add explicit GET/POST/DELETE 503 coverage when akm is unavailable so the akm_unavailable path is exercised in CI. Closes test gap from f9e0451 (Phase 2 of #388 / closes #406). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(lib): add @types/bun for Bun.spawn typing The new akm-vault.ts uses Bun.spawn (in-memory stdin pipe). Lib's tsconfig only declared "node" types, so admin's svelte-check failed with "Cannot find name 'Bun'" when type-checking lib via the workspace. Add @types/bun to lib's devDeps and declare it in tsconfig types. Tests still pass (Bun runtime provides this globally regardless), and downstream consumers (admin, cli) inherit correct types via workspace symlinks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Final 3-reviewer audit on release/0.11.0 surfaced 3 medium and 4 low findings against the akm vault migration (PR #421) and adjacent surfaces. Medium: - secret-backend: stop reading the deleted legacy vault/user/user.env. Phase 2 of #388 deletes that file post-upgrade, so plaintext list/exists/ currentValueForTarget were returning empty for user-scope secrets after the migration. Add akmUserVaultPathSync + readUserVaultSync helpers to akm-vault.ts that prefer the akm vault:user store and fall back to the legacy file for fresh installs that have not yet seeded akm. Add a regression test that simulates the post-migration state and asserts user-scope list/exists still resolve. - entrypoint.sh maybe_proxy_lmstudio: validate target_host and target_port before handing them to socat. Restrict host to a hostname/IP character class and port to digits to block socat option-injection via crafted LMSTUDIO_BASE_URL values. - akm-vault.test.ts argv-leak guard: make the security invariant test unconditional. Stub Bun.spawn (which Bun's child_process.execFile shim also delegates through) to synthesize akm responses end-to-end without needing the real binary on PATH. Capture stdin writes + argv calls and assert the secret value never appears on argv. Keep the live-akm test as a sanity check gated on AKM_AVAILABLE. Low: - system.md: drop the stale "falls back to /etc/vault/user.env" claim for load_vault. Post-#421 the only resolver is `akm vault path vault:user`. - packages/lib barrel: re-export type SecretBackend so consumers can type-annotate detectSecretBackend's return. Also re-export the new akmUserVaultPathSync + readUserVaultSync helpers. - voice addon: remove dead CHANNEL_VOICE_SECRET from .env.schema (voice serves static assets and never round-trips through the guardian). Document the new design inline in the schema and the channel README. Promote STT_BASE_URL to @required so the registry-components contract test (which requires at least one @required var per full addon) keeps passing. - ci.yml: enforce AKM_CLI_VERSION lockstep between core/base/Dockerfile and core/guardian/Dockerfile so a future bump to the base image cannot silently leave guardian on an older akm-cli version. Update the comment in core/base/Dockerfile to point at the new CI gate. Verified: bun run test (889 pass, 0 fail), bun run admin:test:unit (505 pass, 0 fail), bun run admin:check (0 errors), validate-registry.sh (8 addons, 0 errors). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- index: remove dead barrel exports (buildAkmEnv, MirrorResult, UpgradeResult, AccessScope, ActionType, AutomationAction, akmUserVaultPathSync) — none consumed outside lib; verified via grep across admin/cli/scheduler/core. Symbols stay defined in their source modules where lib internals (and the akm-vault.test.ts file) still reference them via relative imports. - secret-backend: drop the readUserEnv 1-line alias; both call sites now invoke readUserVaultSync directly. - akm-vault: extract raceWithTimeout helper used by both execAkm and akmVaultSetViaStdin (was ~20 lines of duplicated setTimeout/unref/race logic). Make ensureAkmUserVault accept a pre-built akm env so writeAkmVaultKey / deleteAkmVaultKey / mirrorUserVaultToAkm / migrateAndCleanupLegacyUserEnv stop building it twice per call. - lifecycle: drop the redundant compose preflight at the top of performUpgrade — applyUpgrade -> reconcileCore already runs it. One fewer docker subprocess per upgrade and one fewer place that can drift out of sync with the canonical preflight call. - secret-backend: keep the PassContext struct (with a clarifying comment on why) — inlining would duplicate the default-resolution logic across five helpers. bun run test: 882 pass / 7 skip / 0 fail. bun run admin:check: 0 errors / 0 warnings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Scripts: - release-e2e-test.sh: read OP_ADMIN_TOKEN from vault/stack/stack.env and OP_CAP_LLM_PROVIDER/MODEL instead of nonexistent ADMIN_TOKEN/SYSTEM_LLM_* in user.env; renumber step comments to be contiguous (11–14). - dev-setup.sh: drop retired openviking data directory from mkdir list. - dev-e2e-test.sh: renumber Step 13/14 → 12/13 to close the numbering gap. - upgrade-test.sh: seed and verify OP_ADMIN_TOKEN in vault/stack/stack.env (where it actually lives) instead of vault/user/user.env. - run-all-tiers.sh: rewrite to delegate to scripts/test-tier.sh so tier definitions live in a single place. - load-test-env.sh: add a must-be-sourced guard so direct execution fails loudly instead of silently doing nothing. Docs: - .github/CONTRIBUTING.md: drop references to nonexistent bun run channel:chat:dev (the chat addon is served by channel-api with CHANNEL_ID=chat). - docs/technical/environment-and-mounts.md: remove the entire Memory service section (memory was retired in #405) and replace with a note pointing at the akm stash mounts; drop residual MEMORY_*/OP_MEMORY_* refs from the assistant, scheduler, admin, and stack.env tables. Versions: - Bump platform manifests (root, lib, admin, guardian, cli, channels-sdk) and setup.sh/setup.ps1 SCRIPT_VERSION to 0.11.0; bump CLI's @openpalm/lib semver range to >=0.11.0 <1.0.0; regenerate bun.lock. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Channels SDK + adapters + guardian: - Drop the constantTimeEqual re-export shim in channels-sdk/src/utils.ts; re-export from crypto.ts directly via the barrel (no external consumer imports utils.ts directly). [HI9] - Delete the splitMessage test blocks duplicated across channel-discord and channel-slack — splitMessage is fully covered in channels-sdk/src/utils.test.ts. Removed channel-slack's splitMessage re-export that only existed for those tests. [HI10] - Hoist guardian's clientOpts() factory to a module-level CLIENT_OPTS const (env vars are stable). [MEDIUM] - Simplify findExistingSessionId: drop the redundant inner condition that mirrored the early-return guard. [MEDIUM] Containers + scheduler: - Voice addon: align CHANNEL_PACKAGE with start.sh by introducing a CHANNEL_ENTRYPOINT override in start.sh. Voice runs its own Bun.serve (not BaseChannel), so it now installs CHANNEL_PACKAGE as usual and execs the package's index instead of the SDK channel-entrypoint. [M5] - Admin addon: pass through the full provider key set (LMSTUDIO_*, TOGETHER, DEEPSEEK, XAI, HF_TOKEN, MCP_API_KEY, EMBEDDING_API_KEY, OP_CAP_LLM_PROVIDER) so admin's OpenCode sees the same providers as the assistant. [M6] - Drop azure-cli, huggingface-hub[cli], mgc, dbus/gnome-keyring/ libsecret-1-0 from the assistant Dockerfile and the matching MGC_CONFIG_DIR env from compose — no caller. Keep gcloud + gws (used by the gws-setup skill) and apprise (used by notify). [H1, H2] - Refactor entrypoint.sh start_opencode from 4 near-duplicated branches to a single command-array build (with optional gosu prefix). [M3] - Refactor maybe_enable_ssh to check id -u once at the top. [M4] CI: - Add CI sync checks asserting OPENCODE_VERSION is declared only in core/base/Dockerfile (admin/assistant inherit) and that BUN_VERSION major.minor in core/base matches the oven/bun image tag in core/guardian + core/channel. [M2]
- HI3: drop spurious `await` from 11 sync `ensureValidState()` call sites.
- HI4: remove dead `bootstrapInstall` re-export from `main.ts`.
- HI5: move volume-mount-target pre-creation into
`@openpalm/lib`'s `ensureComposeVolumeTargets()` (called from
`applyInstall`), eliminating 65 lines of duplicated compose parsing
in `install.ts`. Tighten the file/dir heuristic so leading-dot files
(e.g. `.env`) are correctly treated as files instead of directories.
- Move env helpers (`upsertEnvValue`, `resolveRequestedImageTag`,
`reconcileStackEnvImageTag`, `RELEASE_TAG_REGEX`) from CLI into
`@openpalm/lib`'s `control-plane/env.ts` and import from lib in CLI.
- Drop unused `unwrapQuotedEnvValue` (had no callers).
- Split misnamed `cli/lib/docker.ts` (249 lines) into focused modules:
* `docker.ts` keeps only `runDockerCompose` / `runDockerComposeCapture`
* new `io.ts` owns directory-tree, asset fetch, copy-tree, dir-exists,
seedOpenPalmDir
* new `browser.ts` owns `openBrowser`
- Replace BSD/GNU-incompatible `find` subprocess in `copyTree` with
`node:fs` recursive `readdirSync` — portable, no subprocess.
- Update `install-flow.test.ts` to call the lib helper directly instead
of replicating the volume-mount logic via a `cast as any` access of
the (now-removed) private CLI function.
Net CLI reduction: ~131 lines. All existing tests (889) pass; admin
svelte-check is clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Audit #2 cleanup for the admin package: - HI6: collapse three diverging asString/asRecord definitions to a single source in `lib/server/coercion.ts`. Provider routes now use `asStringOrEmpty` for the trimmed/empty-string semantics they need; `provider-models.ts` imports `asRecord` directly instead of redefining a null-returning copy. - HI7: delete `lib/server/scheduler.ts`. The remaining caller now imports `loadAutomations` from `@openpalm/lib` directly. - Inline `lib/server/capabilities.ts` (10-line wrapper around 4 lib calls) at its two call sites and delete the file. - Inline `lib/opencode/client.server.ts`. Helpers exposes a lazy `getOpenCodeClient()` singleton bound to the configured base URL; routes call it directly instead of importing 7 named re-exports. Vitest mocks now stub `getOpenCodeClient` from helpers. - OverviewTab.svelte: drop the dead `services` and `adminStatus` props (and the now-orphan `services` derived block in the parent page). - packages/admin-tools/AGENTS.md: trim runtime persona content; the assistant guidance lives in `core/assistant/opencode/` and this file is a contributor pointer only (mirrors the assistant-tools AGENTS.md pattern from #410). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Docs cleanup (3 files outside WS1's scope): - docs/channels/community-channels.md: removed channel-chat reference (channel-api serves chat addon via CHANNEL_ID=chat) - docs/technical/bunjs-rules.md: replaced channel-chat example with channel-discord/channel-slack - docs/technical/opencode-configuration.md: replaced MEMORY_API_URL/MEMORY_AUTH_TOKEN/MEMORY_USER_ID rows with AKM_STASH_DIR/AKM_CACHE_DIR (memory served via akm stash) Route helper: - Added withAdminBody() to packages/admin/src/lib/server/helpers.ts to wrap the 4-line auth+JSON-body preamble that was copy-pasted across 30+ admin POST routes - Migrated 5 provider routes as proof-of-pattern: providers/save, providers/toggle, providers/model, providers/oauth/start, providers/oauth/finish Each migrated route loses 5 lines of boilerplate. Future routes can opt in. Misc: - Add .claude/ to .gitignore (per-session worktree directories should never be tracked) Verified: bun run admin:check 0 errors, bun run admin:test:unit 499/499 pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The "one-shot" framing in the docstring implied no leftover state on the assistant, but the function was leaking sessions on every call. Schedulers running daily prompts via askAssistant would accumulate sessions indefinitely. Behavior change: - Default: try/finally now calls deleteSession after sendMessage - Cleanup is best-effort (.catch swallows failures so the answer takes priority) - Pass `keepSession: true` to opt out (for follow-up message flows) Tests: - Updated existing happy-path test to expect 3 calls (create + send + delete) - Updated message-timeout test mock to handle DELETE (otherwise the cleanup fetch hangs against the never-resolving mock) - Added new test asserting keepSession: true skips the cleanup This is a breaking change for external SDK consumers relying on session persistence, but no internal OpenPalm code uses askAssistant for that pattern (verified via grep). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CHANGELOG.md: add [0.11.0] section (Added/Changed/Fixed/Removed/Security) - capability-injection.md: remove stale memory service row + Memory capability slot - api-spec.md: remove all /admin/memory/* routes and memory from service lists - installation.md, system-requirements.md: replace MEMORY_* vars with OP_CAP_* - managing-openpalm.md: replace data/memory with data/stash, add port 3881 - password-management.md: replace MEMORY_* and SYSTEM_LLM_* with OP_CAP_* vars - how-it-works.md: replace memory service bullet with akm stash - backup-restore.md, troubleshooting.md: remove data/memory and port 3898 - setup-walkthrough.md: remove memory from core services + step 5 options - setup-guide.md: replace .env.schema troubleshooting hint with compose.yml - manual-compose-runbook.md: remove memory from core services description - testing-workflow.md: remove OpenMemory Tier 5/6 test items - README.md, docs/README.md: remove memory service references Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…th akm - entrypoint.sh: add maybe_configure_akm() — calls `akm setup --config` with OP_CAP_* vars on container start so akm always uses the configured provider. SLM preferred over LLM for akm (lightweight operations). Includes embedding config when OP_CAP_EMBEDDINGS_* are set. - entrypoint.sh: fix maybe_unset_unused_provider_keys() — now considers both LLM and SLM providers before unsetting any key. Prevents the scheduler's akm improve/distill calls (which use SLM) from losing their API key when LLM and SLM use different providers. - lib: add buildAkmSetupJson(spec, stackEnv) to spec-to-env.ts — builds the akm setup config JSON from a StackSpec. SLM preferred; falls back to LLM. Exported from lib index. 19 tests cover all paths. - assignments route: call buildAkmSetupJson after writeCapabilityVars and write to data/stash/.config/config.json — so akm is configured immediately on capability save without waiting for container restart. - CapabilitiesTab: rename "Capabilities" sub-tab to "AI Models"; add contextual descriptions explaining akm uses SLM for stash improvement/ memory consolidation and embeddings for semantic search. Voice tab gets a note that TTS/STT are for voice channel and web audio, not akm. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…all save paths Dead code removed (all introduced before akm alignment): - fetchCapabilities() and CapabilitiesResponseDto/CapabilitiesSummary types — masked secrets were fetched on capabilities tab switch but never rendered in the UI - capabilitiesData, capabilitiesLoading, loadCapabilities() from +page.svelte - loading and onRefresh props from CapabilitiesTab (parent had no meaningful value to pass; component manages its own load state) - api.vitest.ts deleted — all 3 tests were for the removed fetchCapabilities akm config now written on all capability save paths: - Old /admin/capabilities POST (setup wizard path) now also calls buildAkmSetupJson and writes data/stash/.config/config.json, matching the assignments route Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…emory capability
Directory layout (v0.11.0):
data/stash/ — akm STASH: asset content only (skills, vaults, knowledge)
data/akm/ — NEW: akm operational data (config / data / state)
config/ → AKM_CONFIG_DIR (was: data/stash/.config)
data/ → AKM_DATA_DIR (was: data/stash/.data)
state/ → AKM_STATE_DIR (was: data/stash/.state)
data/akm-cache/ — cache (unchanged)
data/guardian-stash/ — guardian-only stash (unchanged)
data/guardian-akm/ — NEW: guardian akm operational data
Changes:
- core.compose.yml: init mkdir creates data/akm/* and data/guardian-akm/*
instead of stash hidden dirs; assistant + guardian get /akm-data and
/akm-guardian-data bind mounts; AKM_CONFIG/DATA/STATE_DIR updated
- admin compose: same AKM env and /akm-data mount
- akm-vault.ts: buildAkmEnv() uses data/akm/{config,data,state} instead
of nested stash paths; updated layout comment
- home.ts: ensureHomeDirs() creates new akm and guardian-akm trees;
removes stale stash/.{config,data,state} entries
- capabilities routes: akm config write target updated to data/akm/config
Memory capability cleanup:
- setup-config.schema.json: remove deleted memory service fields
(memoryUserId, memory subsystem descriptions)
- spec-validator.ts: remove capabilities.memory required validation
- setup.test.ts: remove stale memory capability from test fixture
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ory taxonomy
New ~/.openpalm/ layout:
config/ — user-editable config (unchanged)
stash/ — akm knowledge: skills, vaults, knowledge, agents
workspace/ — shared work area
services/ — container bind mounts
assistant/ — assistant HOME (/home/opencode)
admin/ — admin home
guardian/ — guardian + guardian/stash + guardian/akm
state/ — system-managed state (replaces vault/ + data/ + logs/)
stack.env — was vault/stack/stack.env
guardian.env — was vault/stack/guardian.env
auth.json — was vault/stack/auth.json
akm/config/ — akm operational config (was data/akm/)
scheduler/ — trigger sentinels (was data/scheduler/)
logs/ — was logs/
backups/ — was backups/
registry/ — was registry/
cache/akm,guardian,rollback — all regenerable data
stack/ — compose runtime files (unchanged)
Also: paths.ts — central path-resolution module
All path strings centralized in packages/lib/src/control-plane/paths.ts
(stackEnvPath, guardianEnvPath, authJsonPath, akmConfigPath, logsDir,
registryDir, rollbackDir, akmUserVaultPath, assistantServiceDir, etc.)
Consumers import typed functions instead of concatenating strings inline.
Files changed: 74 files, 947 insertions, 1394 deletions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Final ~/.openpalm/ structure:
config/ — user config + system config (stack.env, guardian.env, auth.json, akm/)
cache/ — regenerable/semi-persistent (akm, guardian, rollback)
state/ — persistent service data (assistant, admin, guardian, logs, backups, registry)
stash/ — akm knowledge (unchanged)
workspace/ — shared work area (unchanged)
stack/ — compose runtime (unchanged)
Key moves from previous iteration:
services/ eliminated — service bind mounts now live under state/
state/assistant/ (was services/assistant/)
state/admin/ (was services/admin/)
state/guardian/ (was services/guardian/)
state/cache/ eliminated — cache promoted to top-level cache/
cache/akm/ (was state/cache/akm/)
cache/guardian/ (was state/cache/guardian/)
cache/rollback/ (was state/cache/rollback/)
stack.env, guardian.env, auth.json moved to config/
config/stack.env (was state/stack.env)
config/guardian.env (was state/guardian.env)
config/auth.json (was state/auth.json)
akm config moved to config/
config/akm/ (AKM_CONFIG_DIR — was state/akm/config/)
ControlPlaneState: servicesDir removed, cacheDir added
paths.ts: all path functions updated to match new layout
home.ts: ensureHomeDirs() creates new tree; resolveCacheDir() added
akm-vault.ts: buildAkmEnv() uses configDir/akm and cacheDir/akm
Compose: AKM_CONFIG_DIR=/etc/openpalm/akm (assistant, via existing config mount)
AKM_CONFIG_DIR=/openpalm/config/akm (admin, via full OP_HOME mount)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
….env, stack.yml now live at config/stack/ Completes the v0.11.0 directory restructuring. All top-level dirs under OP_HOME are now: config/ cache/ state/ stash/ workspace/. Stack.env, guardian.env, and stack.yml move from config/ into config/stack/ alongside the compose overlays and addons. - Central paths.ts module resolves all paths through ControlPlaneState - secrets.ts, lifecycle.ts, config-persistence.ts, spec-to-env.ts all updated to use state.stackDir for stack.env and guardian.env - registry.ts, channels.ts, core-assets.ts updated to config/stack/addons - rollback.ts SNAPSHOT_FILES updated to new relative paths - CLI io.ts ensureDirectoryTree rewritten to match v0.11.0 layout - All 873 bun tests, 496 admin unit tests, 67 CLI tests pass - svelte-check: 0 errors Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…state/assistant/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Update 38 documentation files to reflect the migration of stack directory into config/stack/. Key changes: - Stack configuration (core.compose.yml, addons/) moved from OP_HOME/stack/ to OP_HOME/config/stack/ - System-managed env files moved from vault/stack/ to config/stack/: - stack.env (system-managed env vars and secrets) - guardian.env (channel HMAC secrets with hot-reload) - Vault now contains only user-managed secrets (vault/user/) - Updated all path references across operational docs, technical docs, setup guides, channel documentation, and README files - Created new .openpalm/config/stack/README.md with updated structure - Marked old .openpalm/stack/README.md as deprecated with migration note Files updated: - Operational docs: manual-compose-runbook, troubleshooting, setup guides - Technical docs: core-principles, api-spec, registry, environment-and-mounts - Channel docs: all channel-specific READMEs - Supporting docs: AGENTS, CONTRIBUTING, installation, backup-restore All 38 files verified with no remaining old path references. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Critical fixes for directory structure migration: CLI Installation Flow: - Fix install.ts: check "already installed" marker at config/stack/stack.env - Fix install.ts: create guardian.env at config/stack/ instead of state/ - Fix install.ts: pass configDir to ensureStackEnv (not stateDir) - Fix env.ts: write stack.env to config/stack/ instead of state/ - Fix io.ts: seed core.compose.yml from correct repo location E2E Test Harness: - Fix e2e/global-setup.ts: point to .dev/config/stack/stack.env - Fix e2e/global-teardown.ts: point to .dev/config/stack/stack.env - Fix e2e/channel-guardian-pipeline.pw.ts: point to .dev/config/stack/guardian.env Test Updates: - Fix main.test.ts: seed and verify stack.env at new config/stack/ location - Update core-assets.vitest.ts: clarify old paths are not resurrected - Update auth server test name: reference config/stack/stack.env - Update lifecycle-validate comment: reference config/stack/stack.env - Update staging comment: reference config/stack paths - Update route handler comment: reference config/stack paths All 67 CLI tests passing, all 496 admin tests passing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deletes the `packages/scheduler/` co-process entirely and delegates all scheduling, execution, and history to the AKM task system. The assistant container now starts crond at boot via entrypoint.sh and calls `akm tasks sync` to register task files with OS cron; a 60 s background loop re-syncs to pick up files written by the admin container. Breaking changes: - `config/automations/*.yml` files are no longer read; automation task files are now AKM markdown in `stash/tasks/*.md` - Per-task `timezone:` is dropped; set container-wide TZ in stack.env - Sentinel-file triggers removed; use `POST /admin/automations/:name/run` - Execution latency increases from ~10 ms (inline) to ~80 ms (CLI spawn) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implements the first two phases of the host-admin migration proposal
(docs/technical/proposals/host-admin-migration.md).
Phase 1a — Server proof-of-concept:
- `openpalm admin serve` command: Bun.serve gateway on 127.0.0.1:3880
extracts SvelteKit build tarball to ~/.openpalm/cache/admin/{version}/
and serves it from disk (adapter-node output, no path patch needed)
- Host OpenCode subprocess with SIGTERM/SIGINT wiring and crash recovery
- Proxy routes /proxy/assistant and /proxy/admin to respective backends
- OPENPALM_ADMIN_MODE=host|container feature flag (default: container)
- Cookie auth foundation: /admin/auth/session issues httpOnly cookie
- Host header allowlist (closes DNS rebinding) + Origin check on mutations
- Admin skills allowlist with 4-invariant argument validation
- admin-token.ts: ensureAdminToken / rotateAdminToken at mode 0600
- Windows: symlinkSync → copyFileSync guard in opencode-subprocess.ts
Phase 1b — Chat UI (primary user surface):
- /chat route: default landing after setup, Svelte 5 runes, full state
- Assistant/Admin toggle with visual thread segmentation on switch
- ChatMessage + ChatInput components; 150s timeout on all chat requests
- /proxy/assistant and /proxy/admin catch-all SvelteKit routes
- Existing admin dashboard moved to /admin; root / redirects to /chat
- Voice TTS wired to chat responses via voice-state.svelte.ts
- OP_ADMIN_OPENCODE_INTERNAL_URL added to compose.dev.yml
Test results:
- cli:test: 92 pass / 0 fail
- admin:check: 0 errors / 0 warnings (676 files)
- admin:test:unit: 459 pass / 0 fail
- guardian:test: 31 pass / 0 fail
- sdk:test: 39 pass / 0 fail
Phase 2 gate: requires Phase 1a/1b to soak for ≥ 1 release.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Workstream A — Push appendAudit into lib: - Add AuditContext type to @openpalm/lib types - applyInstall/applyUpdate/applyUninstall now call appendAudit internally with optional ctx parameter; direct appendAudit calls removed from routes Workstream B — Auth migration (x-admin-token → cookie): - Add /admin/auth/login + /admin/auth/logout routes (httpOnly cookie) - requireAdmin/requireAuth accept cookie OR x-admin-token (both work) - Delete packages/admin/src/lib/auth.ts (localStorage token) - Remove token: string param from all 23 api.ts functions - Update 21 vitest files to use session cookie instead of x-admin-token header Workstream C — 52 routes to Bun.serve handlers: - Add packages/admin/src/server/router.ts (path-matching router) - Add packages/admin/src/server/entry.ts (Bun.serve entrypoint) - Add packages/admin/src/server/shim.ts (Request → RequestEvent adapter) - Add 55 handler files in packages/admin/src/server/routes/ - Add "start:bun" script to packages/admin/package.json Workstream D — Default mode cutover: - resolveAdminMode() now defaults to 'host' - CLI install --admin-mode defaults to 'host' - state.ts audited: no container-mode hardcoded paths Workstream E — Docker lib consolidation: - Move inspectContainerStatus into @openpalm/lib docker module - Move runPreflight into lib docker module (injected into compose* fns) - Export inspectContainerStatus from lib barrel - Admin routes import from @openpalm/lib directly Workstream F — Automations check command: - Add openpalm automations check command - Detects type:api tasks needing host-cron migration - automations/catalog/refresh flags deprecated api-type tasks Test results: - admin:check: 0 errors / 0 warnings (679 files) - admin:test:unit: 463 pass / 0 fail (+4 new cookie-path tests) - cli:test: 92 pass / 0 fail - guardian:test: 31 pass / 0 fail - sdk:test: 39 pass / 0 fail Net: 367 insertions, 473 deletions — codebase is smaller after migration. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…cket-proxy Tier 1 (parallel deletions): - Delete core/admin/ — Dockerfile, entrypoint.sh, opencode config - Delete .openpalm/registry/addons/admin/ — compose.yml + .env.schema - Delete packages/admin-tools/ — 35 HTTP-wrapper tools + skills - Remove OP_ADMIN_API_URL from core.compose.yml assistant env - Remove admin/docker-socket-proxy from CI health check scripts Tier 2 (code cleanup): - Remove selfRecreateAdmin from lib/docker.ts, index.ts, admin wrapper, vitest, and upgrade route (--profile admin no longer exists) - Simplify OptionalServiceName → never, OPTIONAL_SERVICES → [] in lib types - Remove OPENPALM_ADMIN_MODE feature flag from all sources (host is always the mode now; no conditional branches remain) - Clean SSRF blocklist: remove "admin" and "docker-socket-proxy" entries - Delete docs/technical/docker-dependency-resolution.md + all references Tier 3 (docs): - core-principles.md: rewrite invariant #1 (admin is host process), add invariant #6 (admin is host-only, enforced by OS loopback) - foundations.md: remove admin_docker_net network, replace Admin Addon section with "Admin (host process)" + "UI-first principle" - Update environment-and-mounts.md, opencode-configuration.md, system-requirements.md, package-management.md, cli README, stack READMEs, AGENTS.md, CLAUDE.md — remove all container-era admin refs Also removed: - .github/workflows/publish-admin-tools.yml (package gone) - .github/release-package-groups.json admin-tools entry - .github/workflows/ci.yml admin Dockerfile audit entry - compose.dev.yml admin service block - packages/admin/e2e/opencode-ui.pw.ts admin-tools test block Final state: - 0 container images for admin (−1 from before) - 0 Docker services for admin + docker-socket-proxy (−2) - 0 networks: admin_docker_net gone (−1) - 0 packages: admin-tools gone (−1) - admin:check: 0 errors / 0 warnings - admin:test:unit: 459 pass / 0 fail - cli:test: 92 pass / 0 fail - guardian:test: 31 pass / 0 fail - sdk:test: 39 pass / 0 fail Net: 101 insertions, 2786 deletions — codebase is substantially smaller. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Source code:
- stop.ts, uninstall.ts: remove stale comments about admin.yml/socket-proxy
- host-admin-server.ts: fix proxy comment ("container admin" → "host admin OpenCode subprocess")
- admin.ts: remove dead --container-admin flag and containerAdminBaseUrl arg
- config-persistence.ts, spec-to-env.ts: remove OP_DOCKER_SOCK (no consumer since docker-socket-proxy deleted)
Test fixtures:
- CapabilitiesTab.svelte.vitest.ts: remove stale localStorage.setItem for adminToken
- SecretsTab.svelte.vitest.ts: remove 3x stale localStorage.setItem for adminToken
Docs:
- assistant-tools/README.md: replace deleted @openpalm/admin-tools reference
- how-it-works.md: remove docker-socket-proxy references (×2)
- environment-and-mounts.md: remove OP_DOCKER_SOCK row
Tests: admin:check 0 errors, admin:test:unit 459/0, cli:test 92/0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dead code removed: - host-admin-server.ts: delete /proxy/admin Bun gateway handler (always returned 503; SvelteKit route handles /proxy/admin correctly) - host-admin-server.ts: remove containerAdminBaseUrl from options type - cli/src/lib/env.ts: remove OP_DOCKER_SOCK from stack.env generation (docker-socket-proxy deleted in Phase 3; no container reads this var) Comment and doc fixes: - core/assistant/opencode/system.md: "admin container" → "admin process" - core/assistant/entrypoint.sh: fix cron sync comment (admin is host process) - docs/technical/api-spec.md ×2: remove "admin container" from upgrade and network/check endpoint descriptions - docs/troubleshooting.md: replace docker compose exec admin instructions with host process equivalents (lsof, openpalm admin) - docs/operations/diagnostic-playbook.md: replace docker exec env inspect with host process equivalent (ps + stack.env grep) - packages/admin/e2e/scheduler.pw.ts: fix comment + port 8100→3880, use ADMIN_URL env var with default Tests: admin:check 0 errors, admin:test:unit 459/0, cli:test 92/0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Registry automations: - health-check.md, update-containers.md, validate-config.md: replace http://admin:8100 curl commands (dead — admin is no longer a container reachable from inside the assistant) with openpalm CLI equivalents CLI: - admin.ts: remove enable/disable/status subcommands for the admin addon (addon deleted in Phase 3; commands would always fail with "not found") - admin.ts: remove unused listEnabledAddonIds + runAddonEnable/DisableAction imports - main.test.ts: remove test assertions for deleted admin enable/disable/status Docs: - how-it-works.md: remove http://admin:8100 from architecture example - managing-openpalm.md: replace http://admin:8100 automation example - scheduler.vitest.ts: replace http://admin:8100 test fixture command - .gitignore: remove packages/admin-tools/dist/index.js (package deleted) - opencode-configuration.md: remove registry/addons/admin + core/admin/entrypoint.sh refs - testing-workflow.md: remove admin-tools from test suite description - release-publish-remediation-plan.md: remove admin-tools workflow references (×2) - .github/SECURITY.md: replace docker-socket-proxy bullet with host-admin model Tests: admin:check 0 errors, admin:test:unit 459/0, cli:test 92/0, guardian 31/0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… docs Svelte components: - ContainersTab.svelte: remove docker-socket-proxy from container overlay comment - OverviewTab.svelte: same Docs: - troubleshooting.md: remove port 3881 (admin OpenCode, container-era) - managing-openpalm.md: remove http://localhost:3881 row from ports table Tests: admin:check 0 errors, admin:test:unit 459/0, cli:test 92/0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dev scripts: - package.json dev:stack + dev:build: remove --enable-addon admin and -f .dev/stack/addons/admin/compose.yml (admin addon deleted) - scripts/dev-e2e-test.sh: same — remove admin addon from dev_compose() - scripts/test-tier.sh: same Docs: - core-principles.md: remove Admin OpenCode port 3881 from port assignments table Tests: admin:check 0 errors, admin:test:unit 459/0, cli:test 92/0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…books .dockerignore: remove core/admin/ entries (directory deleted in Phase 3) Docs: - installation.md: remove admin addon cp command + admin row from addon table - .openpalm/README.md: remove admin addon from example compose command + cp - docs/operations/manual-compose-runbook.md: remove admin addon compose -f flags (×2) - docs/troubleshooting.md: remove admin addon compose -f flags (×2) - docs/technical/opencode-configuration.md: replace admin addon compose ref with host subprocess description Tests: admin:check 0 errors, admin:test:unit 459/0, cli:test 92/0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The system-check endpoint tries to bind a fresh TCP server on the admin port to test availability. When the UI server itself is already listening on that port (PORT env var set by Electron / cli serve), the bind always fails and the wizard blocks with "port 3880 is in conflict" even on a clean machine. Fix: skip the bind test for the port the current server process is already holding. The port is available from the stack's perspective — the UI server will continue holding it both before and after install. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixes before public npm publish: - add files whitelist to packages/cli (prevented full src/ publish) - wrap lifecycle endpoints in try-catch for structured error responses - add types field to @openpalm/lib package.json - update SECURITY.md supported versions (0.9.x → 0.11.x) and remove Caddy reference Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
requireAdmin was updated to validate op_session cookies against an
in-memory session store (validateSession) rather than comparing
the cookie value directly to OP_UI_LOGIN_PASSWORD.
All 18 failing test files still presented the password as the cookie
value, which validateSession always rejected (the password was never
seeded into the session map).
Fix:
- Add _seedSession / _clearSessions helpers to session-store.ts for
test use
- Update resetState() in test-helpers.ts to seed the password value as
a valid session so every test that calls resetState('token') can
continue using that value as the op_session cookie
- Fix proxy/assistant streaming test which set the env var manually
without seeding a session (stale comment referenced old direct-compare
behavior)
Result: 530 passed, 0 failed (was 406 passed, 124 failed)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CLI error handling: all 10 command run() handlers now wrap in try-catch and call process.exit(1) on failure for reliable CI/script exit codes - stack.yml seed stripped to version:2 only (stale capabilities block removed) - CHANGELOG stale OP_CAP_* references corrected to akm config.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove dead code from capabilities → akm config migration: - dead readStackSpec import in lifecycle.ts - unused stackSpecFilePath export in paths.ts - stackSpecPath helper (production-dead, inline the concat) - unused spec: StackSpec param in deriveSystemEnvFromSpec - stale wizard comment referencing stack.yml capabilities.tts.provider Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Implemented smoke tests for the setup wizard browser using Playwright. - Created unit tests for AuthGate, ChatInput, ChatMessage, FriendlyError, LogsTab, ProvidersPanel, SecretsTab, SessionPicker components using Vitest. - Added server route tests for GET /admin/health and GET /admin/providers to ensure proper authentication and response structure. - Ensured coverage for various states including loading, error handling, and user interactions.
- Implemented tools for managing Docker Compose lifecycle: compose.up, compose.down, and compose.ps. - Added health-check tool to monitor OpenPalm services. - Introduced endpoints-list tool to retrieve configured OpenCode endpoints. - Created secrets-list-keys tool to list secret names without exposing values. - Established a plugin structure to expose these tools for use in the Electron environment. - Included comprehensive tests for all tools to ensure functionality and security. - Configured TypeScript settings for the project.
writeSystemEnv was writing OP_SETUP_COMPLETE=false when the key was absent, overriding the OP_UI_LOGIN_PASSWORD fallback in isSetupComplete. Users whose initial deploy health-check timed out never had the explicit flag written, so upgrading to beta11 caused every request to redirect to /setup. Fix mirrors isSetupComplete semantics: promote legacy installs that have OP_UI_LOGIN_PASSWORD to OP_SETUP_COMPLETE=true on startup. Voice profile section was hiding CUDA/ROCm options behind a collapsed <details> "Advanced" element and always defaulting to CPU even when NVIDIA hardware is available. Replace with a plain visible select and update resolveDefaultProfile to prefer the first available GPU profile. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
isSetupComplete was short-circuiting on any explicit OP_SETUP_COMPLETE value, so OP_SETUP_COMPLETE=false (written by old code) blocked the OP_UI_LOGIN_PASSWORD fallback even for users who completed setup. Fix: treat OP_UI_LOGIN_PASSWORD present as sufficient, same as absent flag. getAddonProfiles was reading the enabled-addon copy first — which for existing users is a stale copy from an earlier beta that only had the cpu profile. Reverse priority: registry is always current; enabled copy is only the fallback when the registry entry is missing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…build resolution compareVersionTags split on '.' and mapped to Number, turning "0.11.0-beta.4" into [0, 11, NaN] — NaN !== NaN is always true in JS, making every beta-vs-beta comparison non-deterministic. Replace with proper semver pre-release parsing: - numeric version segments compared numerically - pre-release part split on '.' with each identifier compared numerically when both are digits (so "beta.4" < "beta.11"), or lexicographically otherwise - stable release > pre-release per semver spec Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Added functionality to fetch releases from GitHub API, including release tags and UI build availability. - Updated admin page to manage selected image and UI tags, integrating release data. - Refactored AKM configuration handling to align with the new schema, removing deprecated fields and improving validation. - Adjusted automation endpoints to support YAML file formats instead of Markdown. - Cleaned up unused imports and improved error handling in various server routes.
- Added support for selecting hardware profiles for the bundled OpenPalm Voice addon. - Introduced a new VoiceProfileSelector component for profile selection. - Updated the setup wizard to include options for enabling voice and including Ollama. - Enhanced the SystemCheckStep to detect GPU availability and update the UI accordingly. - Modified the ReviewStep to display selected voice profiles and their statuses. - Implemented API endpoint to fetch available voice profiles and selected profile. - Improved model selection logic to apply imported model preferences.
- Updated `setAddonEnabled` and `setAddonProfileSelection` functions to accept state for writing run scripts upon changes. - Introduced `resolveActiveProfiles` to deduplicate and retrieve active Docker Compose profiles from the stack environment. - Enhanced `buildComposeOptions` to include profiles in the Docker Compose CLI arguments. - Modified `writeRunScript` to generate a script that includes profile information for Docker Compose. - Updated various commands and lifecycle functions to utilize the new profile handling, ensuring that profiles are set and persisted correctly. - Added Ollama profile management to the setup process, allowing for default profile selection based on GPU detection. - Created a new API endpoint to fetch available Ollama profiles and the selected profile. - Updated UI components to support Ollama profile selection and display. - Refactored setup scripts and development environment setup to accommodate new state management and directory structure.
- Removed unused imports and functions related to provider API key management in PATCH handler. - Updated import-host route to streamline service restart logic, focusing on the assistant service. - Enhanced test coverage for provider registration and import functionality, ensuring API keys are not stored in environment variables. - Adjusted file paths for secrets storage from `config/stack/secrets` to `stash/vaults/secrets` for better organization. - Modified setup scripts to reflect new secrets storage structure and ensure proper permissions. - Improved error handling and logging in various service interactions.
- Removed addon compose file snapshotting and restoration in rollback.ts. - Updated setup-config.schema.json to reflect new secrets path. - Adjusted setup.test.ts comments for clarity on automation locations. - Modified setup.ts to clarify addon enabling process. - Updated skeleton-guardrail.test.ts to reflect changes in directory structure. - Enhanced stack-spec tests to include addon round-trip validation. - Implemented validation for addon names in stack-spec.ts. - Removed registry references from ui-assets.ts and adjusted seeding logic. - Updated core-assets.vitest.ts to ensure fallback behavior for missing files. - Revised lifecycle.vitest.ts to include fixed custom compose file instead of addons. - Changed addon handling in admin routes to utilize stack.env for profiles. - Updated dev-setup.sh to modify how addons are enabled, focusing on COMPOSE_PROFILES.
- Removed the guardian service from core.compose.yml as it is no longer needed. - Updated backup-restore documentation to reflect changes in stack.env and added descriptions for new compose files. - Revised community channels documentation to clarify the process for adding channels and services. - Adjusted how OpenPalm manages addon activation, moving from enabled-addons.json to stack.yml for first-party addons. - Updated installation and setup guides to reflect the new stack configuration structure. - Modified managing OpenPalm documentation to clarify the purpose of various stack files. - Enhanced manual compose runbook to provide clearer instructions on managing profiles and services. - Updated technical documentation to reflect changes in addon management and stack structure. - Adjusted CLI tests to validate changes in stack.yml instead of stack.env. - Updated control-plane logic to read from stack.yml for addon activation. - Refactored dev setup script to write enabled addons directly to stack.yml.
- Moved operational data and logs from `state/` to `cache/` for better organization. - Updated documentation to reflect new directory structure. - Adjusted backup processes to store UI builds and other artifacts in `cache/backups/`. - Modified tests and code references to align with the new paths. - Ensured that all relevant directories are created during setup and installation.
…to akm state directory
… across the codebase - Updated references in test files and server routes to use 'data' instead of 'cache' and 'state'. - Adjusted log reading and writing functions to align with new directory structure. - Modified helper functions and state management to reflect the new 'data' directory. - Added new README files for assistant tools and instructions. - Created necessary directory structure with .gitkeep files to ensure persistence.
Rename the host-side OP_HOME/stash directory to OP_HOME/knowledge across the codebase: path resolver, source path builders, compose mount default, secret/channel file paths, scripts, docs, tests, and ignore/CI files. The repo skeleton dir .openpalm/stash is moved to .openpalm/knowledge. Scope is the host path only (clean break, no migration). The container mount target /stash, AKM_STASH_DIR, OP_AKM_STASH override name, and the stashDir/resolveStashDir identifiers are intentionally retained — /stash is the akm CLI's own convention and renaming it would break akm. Tests: cli 46, lib 310, sdk 33, guardian 35, ui:check 0 errors, ui vitest 608. Both edited compose files validate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ship two example convenience wrappers in the .openpalm/ skeleton (they copy to OP_HOME/ root on install) that drive the stack with the same docker compose invocation the CLI and admin UI use: up / down / restart / upgrade / status / logs, plus a compose passthrough. They replicate the control plane's exact invocation — project name, overlay order (core → services → channels → custom, only those present), --env-file stack.env, and COMPOSE_PROFILES from stack.env. OP_HOME defaults to the script's own directory. `upgrade` only pulls images and recreates containers; the help text is explicit that it does not refresh assets or the UI build the way `openpalm update` does, and that the CLI and admin UI remain the canonical orchestrators. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Relocate OpenCode's auth.json from config/auth.json to config/stack/auth.json
so a single file backs every OpenCode-based container. authJsonPath() now
resolves to ${stackDir}/auth.json; secrets writers, both import-host
endpoints, the CLI wizard symlink, the rollback snapshot list, install/
dev-setup seeds, and the host-import mkdir target all follow.
The assistant mount is repointed to config/stack/auth.json, and the guardian
now mounts the same file read-only at its OpenCode auth path
(/opt/openpalm/guardian/.local/share/opencode/auth.json), so provider
credentials are shared between assistant and guardian.
Tests and docs (mount tables, comments) updated to the new location.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Install the OpenCode binary in the guardian image (mirroring the assistant: HOME=/usr/local install, pinned OPENCODE_VERSION=1.3.3, plus unzip/bash for the installer). Guardian-side OpenCode instances now read their global config from /etc/opencode, bind-mounted from OP_HOME/config/guardian (OPENCODE_CONFIG_DIR), and share provider credentials with the assistant via the auth.json mount. - channels.compose.yml: OPENCODE_CONFIG_DIR=/etc/opencode + config/guardian mount - .openpalm/config/guardian/opencode.jsonc seeded (akm-opencode plugin, deny-read on auth.json) - guardianConfigDir path helper; skeleton guardrail asserts the config ships - docs (guardian README, mount tables) and the assistant Dockerfile comment updated Verified by building the image: opencode --version → 1.3.3, resolves on PATH, OPENCODE_CONFIG_DIR baked in, and config/guardian mounts at /etc/opencode. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Insert a semantic moderation stage between structural validation and the assistant forward, so the guardian can inspect what an inbound message is trying to do — not just that it is well-formed and signed. Layered cheap → expensive (balances security and efficiency): - channels-sdk/content-screen: pure in-process heuristics scoring prompt injection / jailbreak / exfiltration / obfuscation. Most traffic scores 0 and never touches a model. - guardian/moderation: messages over GUARDIAN_MODERATION_THRESHOLD escalate to the guardian's local OpenCode moderator (loopback :4097, started by the new entrypoint, small model pinned in config/guardian/opencode.jsonc, shared provider creds). Stateless ephemeral session per call; strict JSON verdict (allow / flag / block). Fail-closed: an escalated message the moderator cannot classify (down, timeout, unparseable) is blocked (403 content_blocked). Because that trades availability for security, the whole stage is OFF by default (GUARDIAN_CONTENT_VALIDATION). - config/guardian/instructions/moderation.md: taxonomy + output contract - server.ts wiring + content_blocked error code + audit - guardian entrypoint starts the loopback moderator when enabled - compose env knobs; guardian README + skeleton guardrails Tests: content-screen 16, moderation 15, server integration 2 (clean→200, malicious→fail-closed 403). Full non-UI suite 705/705. Guardian image builds; opencode 1.3.3 on PATH. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request introduces several important updates to documentation, CI/CD workflows, and the filesystem contract, primarily to improve clarity, enforce version consistency, and reflect recent architectural changes (such as the deprecation of OpenViking and the migration of stack secrets/configs). The changes also streamline the Docker build process and update the development and security documentation to match the current system design.
Key changes include:
CI/CD Workflow Improvements
AKM_CLI_VERSIONandBUN_VERSIONbetween the base, guardian, and channel Dockerfiles, and to ensureOPENCODE_VERSIONis only declared in the base Dockerfile. This prevents silent version mismatches and ensures single sources of truth.openpalm-base) and updated dependent images to pull from GHCR, improving build reproducibility and reliability. [1] [2] [3]Filesystem Contract and Secrets Migration
.openpalm/README.mdto move stack secrets (stack.env,guardian.env) from.dev/vault/stack/to.dev/config/stack/, aligning with the new filesystem contract and clarifying the separation between user-managed secrets and system-managed config. [1] [2] [3] [4]Deprecation and Roadmap Updates
Documentation and Security Model Updates
.github/CONTRIBUTING.mdto clarify dev server scripts, Docker build patterns, and to remove outdated references to the admin Docker image (which is now host-only). [1] [2] [3] [4] [5].github/SECURITY.mdto reflect the new admin security model (host-only, direct Docker access, no socket proxy).Cleanup and Package Publishing
admin-toolspackage from the release group and deleted its publish workflow, reflecting its deprecation or removal from active development. [1] [2]Other minor changes:
.dockerignoreto stop ignoringcore/admin/node_modulesand related build artifacts, matching the new admin build process.These changes together ensure the project documentation, build system, and security posture are up-to-date, reduce the risk of version drift, and clarify the direction for future development.