Visitar URL original
feat: let agents apply plugin and personal themes by steipete · Pull Request #152460 · openclaw/openclaw · GitHub
Skip to content

feat: let agents apply plugin and personal themes - #152460

Merged
steipete merged 14 commits into
mainfrom
codex/plugin-theme-catalog
Sep 19, 2026
Merged

steipete merged 14 commits into
mainfrom
codex/plugin-theme-catalog

Conversation

@steipete

@steipete steipete commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Closes #152449
Related: #28300

What Problem This Solves

Agents could describe or generate an OpenClaw theme but could not discover, save, and apply it through the same appearance controls users have.

User Impact

Users can ask the agent to choose a built-in or plugin theme, or design and activate a personal theme in one call. Plugin theme additions and palette changes appear after plugin reload without restarting the Gateway or refreshing the page.

Changes apply to the trusted requesting profile; the agent cannot choose another person's profile. Existing browser-local tweakcn imports and appearance overrides remain supported. There is no database schema migration or required config conversion. New namespaced themes require an upgraded UI/Gateway pair, which OpenClaw ships together. The v2026.9.5 theme reader maps unknown IDs to Claw; it cannot render the new palettes.

Why This Change Was Made

One theme tool provides list, get, set, and import. Lists include descriptions, supported modes, sources, and current selection; import can save and activate atomically. Plugins contribute portable JSON definitions through an optional manifest field.

The Gateway owns the catalog and profile preferences, shared by Settings and agent tools. Writes validate current plugin definitions and concurrent preference changes at the transaction boundary. Disabling a selected plugin renders a built-in fallback while retaining the selection for restoration. Profile notifications trigger authenticated refetches.

The UI loads the catalog when Appearance needs it or a plugin/personal theme is selected. Shared strict mode normalization removes duplicated startup validation. Native protocol/tool-display artifacts and the wrapper dependency inventory are regenerated, and new RPCs preserve existing advertised method order.

Evidence

  • Final CI passed on 71143367669744d40100b5225e315f7501d406e8: all 176 jobs completed successfully, followed by successful security, dependency, and combined CI gates. Focused proof includes 69 theme/tool/method tests; the native maintainer workflow verified and merged that exact head as 68e23ccf848c25b678218521b6be5e1d94f92476.
  • Actual Control UI composer conversations with OpenAI gpt-5.6-luna: describe/select Xenovessel, recolor/reload its plugin, disable/fallback and re-enable/restore, discover a newly added Nebula Bloom theme, switch to Manuscript/light, then design/import/activate Event Horizon Garden. The final run passed all eight states with one Gateway PID/boot ID and one browser page lifetime, without page errors.
  • Gateway profile authority, concurrent writes and rollback, real plugin manifest discovery, queued/steered requester identity, legacy imports, Settings, and Retry coverage passed. Broader UI proof passed 865 tests and all 12 composer browser cases; focused mode/theme validation and core/UI typechecks also passed.
  • Full production build and SDK declarations/exports passed. Protocol generation, tool-display consistency, method-order and wrapper import-closure checks passed. CI's enforcing startup-size check passes without changing its budget; assertion allowances only shrink for removed casts.
  • A memory test fixture now fakes only Date for calendar-based assertions. Host hrtime deadlines and real worker clocks stay in the same domain; a controlled contention probe reproduced the original failure and passed with Date-only faking, and all 63 dreaming cases pass in original order. Production locking, retries, schemas, and deadlines are unchanged.
  • Integration uses the upstream auth freshness regression verbatim: cached data at 0 and 99 ms, then rotated credentials at 100 ms. The former immediate-read assertion reproduced the CI failure under a fixed clock; the integrated test file and existing cache-contract suite pass all 31 cases. No production freshness behavior or timeout changed.
  • Watcher investigation found that a rapid symlink-to-directory replacement can omit Chokidar's normalized directory event. Named and filename-less raw ancestor events now use the existing root reconciliation and symlink checks. The existing shared-root fixture proves real cached inventory refresh from both event shapes and fails before the repair. All 91 owner tests pass afterward, including real symlink replacement; the enlarged case moved unchanged into the existing subscription suite to respect the file-size guard.
  • Reuses the exact service-backup fixture repair: allocate the operator replacement while the original inode is still live and assert distinct file identities. All 73 receipt, ordering, and publication-mode tests pass; rejection and byte-preservation assertions remain intact, with no production service changes.
  • The next-day transcript ownership fixture now awaits actual capture startup before testing account isolation and always stops its service during cleanup. All 45 ownership and occupancy cases pass with the original ownership assertions and test deadlines.
  • Independent review completed with no unresolved actionable findings. An unrelated Android test setup race found by CI now uses its existing settled-handoff helper before exercising stale requests; every post-action assertion remains unchanged.

Local proof limits: the unchanged macOS cold/warm sparse-worktree stress case exceeded its 120-second deadline, including a solo attempt; an isolated main probe was blocked by the host's disk reserve. Other local provisioning cases and closure checks passed. This host has no Android SDK, so Android proof runs in CI. No timeout, disk guard, or performance budget was relaxed. Two existing UI scenarios (mobile Swarm details and cloud account selection) also failed intermittently in the first CI run after integrating main. Both full files and eight repetitions of each failing case passed locally with unchanged assertions and timeouts; no speculative test change was made. The original Windows intermediate-ancestor timeout did not reproduce in either native Windows attempt, and the complete hosted Windows job passed on bd18f4f22c29. Both extra native attempts hit a separate first-case deadline while cold worker generation took 179–187 seconds on a two-core machine; that limitation is retained, and the test machine has been released.

Final sanitized live capture, before:

Default theme before the final live agent requests

After the agent designed, saved, and activated Event Horizon Garden:

Event Horizon Garden created and applied through the agent

@clawsweeper

clawsweeper Bot commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation app: web-ui App: web-ui gateway Gateway runtime agents Agent runtime and tooling size: XL maintainer Maintainer-authored PR labels Sep 19, 2026
@clawsweeper

clawsweeper Bot commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Codex review: blocked before merge. Reviewed September 19, 2026, 7:30 AM ET / 11:30 UTC (Revision 14).

ClawSweeper review

What this changes

Adds a shared catalog for agents and Appearance settings to discover plugin themes and save or apply personal themes, alongside watcher and test-fixture repairs.

Merge readiness

⛔ Blocked before merge - 2 items remain

Keep open: the approved capability remains absent from fetched main. No blocking correctness or security defect was identified, and the documented compatibility contract addresses the previous review concern.

Priority: P3
Reviewed head: 71143367669744d40100b5225e315f7501d406e8

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) A coherent implementation with convincing visual proof and focused authority coverage; no actionable blocker was found in this read-only review.
Proof confidence 🦞 diamond lobster (5/6) ✨ media proof bonus Sufficient (screenshot): Inspected before/after captures show real composer requests applying a personal palette through the theme tool and browser appearance owner. The captured body records plugin reload and restoration in one Gateway/browser lifetime; source and storage-boundary tests separately support profile isolation and revoked-run rollback.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (screenshot): Inspected before/after captures show real composer requests applying a personal palette through the theme tool and browser appearance owner. The captured body records plugin reload and restoration in one Gateway/browser lifetime; source and storage-boundary tests separately support profile isolation and revoked-run rollback.
Evidence reviewed 10 items Pinned introduced change: The local checkout matches the pinned PR head. The complete local merge-base-to-head file list supplies the paths omitted from the prompt; git diff --check passed and the working tree remained clean.
Accepted feature boundary: #152449 explicitly approves declarative plugin themes, shared profile selection, personal imports, hot reload, and preservation of browser-local imports. The visual Theme Studio remains separate work.
Still necessary on main: Fetched main retains the closed built-in profile-theme list and excludes browser-local custom palettes. Its tree contains neither the new theme tool nor the theme RPC owner.
Findings None None.
Security None None.

How this fits together

The Gateway combines built-in themes, enabled-plugin palettes, and personal definitions into one appearance catalog. Agent requests and Settings use the same profile preference owner, which notifies connected browsers after changes.

flowchart LR
  A[Chat request] --> B[Agent theme tool]
  B --> C[Gateway appearance catalog]
  D[Enabled plugin metadata] --> C
  G[Appearance settings] --> C
  C --> E[Current profile authority]
  E --> F[Profile preference store]
  F --> G
Loading

Before merge

  • Review config compatibility - Confirm compatibility and upgrade impact for the changed config or default surface before merge.
  • Add data-model compatibility proof - Confirm migration or upgrade compatibility proof before merge.
Agent review details

Security

None.

PR surface

PR surface statistics unavailable: the file list is incomplete.

Review metrics

Metric Value Why it matters
Capability surface 1 agent tool, 4 Gateway methods, 1 optional plugin manifest field The accepted design exposes one shared catalog across agent and Settings callers.
Production versus test growth Production/tooling net +1,417 lines; tests/support net +1,755 lines; generated artifacts excluded Production growth implements the approved cross-layer catalog and authority contract, with substantial behavioral coverage.

Stored data model

Persistent data-model change detected: unknown-data-model-change: packages/gateway-protocol/src/schema/themes.ts, unknown-data-model-change: packages/gateway-protocol/src/schema/ui-appearance-preferences.ts, unknown-truncated-pull-files. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster

Relationship: fixed_by_candidate
Canonical: #152449
Summary: This PR implements the accepted plugin and agent appearance request; the broader visual Theme Studio remains distinct.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Technical review

Best possible solution:

Retain one Gateway-owned appearance catalog and profile writer, preserving browser-local imports and lifecycle-driven palette refresh.

Do we have a high-confidence way to reproduce the issue?

Not applicable: this implements an approved capability, rather than repairing a reported defect; current-main source confirms the missing plugin and personal-theme contract.

Is this the best way to solve the issue?

Yes: shared manifest metadata and the existing profile store avoid competing appearance owners, and the linked accepted scope resolves the product and persistence direction.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against acbeb3a07197.

Labels

Label justifications:

  • P3: This adds optional appearance ergonomics while existing themes and local imports remain usable.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (screenshot): Inspected before/after captures show real composer requests applying a personal palette through the theme tool and browser appearance owner. The captured body records plugin reload and restoration in one Gateway/browser lifetime; source and storage-boundary tests separately support profile isolation and revoked-run rollback.
  • proof: sufficient: Contributor real behavior proof is sufficient. Inspected before/after captures show real composer requests applying a personal palette through the theme tool and browser appearance owner. The captured body records plugin reload and restoration in one Gateway/browser lifetime; source and storage-boundary tests separately support profile isolation and revoked-run rollback.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. Inspected before/after captures show real composer requests applying a personal palette through the theme tool and browser appearance owner. The captured body records plugin reload and restoration in one Gateway/browser lifetime; source and storage-boundary tests separately support profile isolation and revoked-run rollback.

Evidence

What I checked:

  • Pinned introduced change: The local checkout matches the pinned PR head. The complete local merge-base-to-head file list supplies the paths omitted from the prompt; git diff --check passed and the working tree remained clean. (711433676697)
  • Accepted feature boundary: Plugin themes and agent-controlled appearance without Gateway restarts #152449 explicitly approves declarative plugin themes, shared profile selection, personal imports, hot reload, and preservation of browser-local imports. The visual Theme Studio remains separate work.
  • Still necessary on main: Fetched main retains the closed built-in profile-theme list and excludes browser-local custom palettes. Its tree contains neither the new theme tool nor the theme RPC owner. (packages/gateway-protocol/src/schema/ui-appearance-preferences.ts:12, acbeb3a07197)
  • Release and compatibility contract: The v2026.9.5 reader maps unknown theme IDs to Claw, matching the PR's documented downgrade behavior. The scoped UI policy explicitly ships UI and Gateway together; the patch preserves existing built-in IDs, local imports, and appearance overrides without a schema migration. (ui/src/app/theme.ts:78, ec9c1a13db89)
  • Requester and final-write authority: Theme requests derive their profile from trusted runtime or authenticated-client identity, reject caller-selected profile fields, and compose live authority checks into transaction and commit admission. Catalog replacement and concurrent selection changes are checked before persistence. (src/gateway/server-methods/themes.ts:45, 711433676697)
  • Forbidden-principal and rollback coverage: The focused tests exercise real preference storage, verify the other profile remains unchanged, reject forged targeting and missing requester identity, and assert import/selection rollback when run authority retires at commit. Tests were inspected, not executed during this read-only review. (src/gateway/server-methods/themes.test.ts:1, 711433676697)

Likely related people:

  • unknown: The claimed source-line change could not be verified from bounded local history. (role: source history unknown; confidence: low)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (13 earlier review cycles; latest 8 shown)
  • reviewed 2026-09-19T06:42:05.808Z sha f690d13 :: blocked before merge. :: none
  • reviewed 2026-09-19T07:52:57.681Z sha 6b0bc58 :: blocked before merge. :: none
  • reviewed 2026-09-19T08:29:07.855Z sha 1dd7b6e :: blocked before merge. :: none
  • reviewed 2026-09-19T08:41:38.194Z sha 1dd7b6e :: blocked before merge. :: none
  • reviewed 2026-09-19T09:34:54.318Z sha 2149239 :: blocked before merge. :: none
  • reviewed 2026-09-19T09:54:41.019Z sha cd37741 :: blocked before merge. :: none
  • reviewed 2026-09-19T10:14:53.824Z sha 5e1ad00 :: blocked before merge. :: none
  • reviewed 2026-09-19T10:51:15.117Z sha bd18f4f :: blocked before merge. :: none

@steipete
steipete force-pushed the codex/plugin-theme-catalog branch from 5fd1e7b to 254d7a3 Compare September 19, 2026 04:15
@steipete
steipete marked this pull request as ready for review September 19, 2026 04:17
@clawsweeper clawsweeper Bot added P3 Low-priority cleanup, docs, polish, ergonomics, or speculative work. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Sep 19, 2026
Add declarative plugin theme metadata, descriptive theme list/get/set/import operations, and shared profile appearance writes. Plugin additions and palette updates follow hot reload without a Gateway restart. Preserve legacy local imports, bound profile authority, and atomic concurrent preference updates.

Refs #152449.
@steipete
steipete force-pushed the codex/plugin-theme-catalog branch from 254d7a3 to 09123d9 Compare September 19, 2026 04:57
@openclaw-barnacle openclaw-barnacle Bot added app: android App: android scripts Repository scripts labels Sep 19, 2026
@github-actions

github-actions Bot commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ Security sensitive changes

This maintainer PR changes sensitive security components. This comment is informational because the PR author has repository Maintain or Admin access.

  • Current SHA: 71143367669744d40100b5225e315f7501d406e8
  • Maintainer: @steipete
  • Repository role: admin

These security sensitive changes were made:

  • src/gateway/methods/core-descriptors.ts: Controls Gateway authentication, pairing, or caller permissions. Check identity validation, scope checks, and revocation.
  • src/gateway/methods/core-profile-access.ts: Controls Gateway authentication, pairing, or caller permissions. Check identity validation, scope checks, and revocation.

Carefully review these changes before merging.

@clawsweeper clawsweeper Bot removed proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. labels Sep 19, 2026
@clawsweeper clawsweeper Bot removed the merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. label Sep 19, 2026
Integrate the tested main snapshot. Route named and filename-less raw ancestor events through the existing skills root reconciliation and symlink checks. Preserve shared-root discovery coverage in the subscription suite, and verify the documented external auth-write freshness window with a deterministic clock.
Use the main branch auth freshness regression verbatim after its independent fix landed in #152771. Theme and watcher implementations remain unchanged.
Observe the real startup promise before exercising next-day account ownership, and always stop the service during cleanup. This removes the provider-entry timing race while preserving the ownership assertions.
@steipete
steipete merged commit 68e23cc into main Sep 19, 2026
234 of 236 checks passed
@steipete
steipete deleted the codex/plugin-theme-catalog branch September 19, 2026 11:51
@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Sep 20, 2026
* feat: let agents apply plugin and personal themes

Add declarative plugin theme metadata, descriptive theme list/get/set/import operations, and shared profile appearance writes. Plugin additions and palette updates follow hot reload without a Gateway restart. Preserve legacy local imports, bound profile authority, and atomic concurrent preference updates.

Refs openclaw#152449.

* fix: complete theme integration and defer catalog loading

* refactor: share theme mode validation and trim startup work

* chore: shrink theme assertion allowances

* test: await the initial Android gateway handoff

* fix(gateway): settle chat waits after user cancellation

* fix(gateway): preserve upstream cancellation settlement

* test(memory): preserve real worker deadline clocks

* test(daemon): preserve distinct replacement fixture identity

* test(transcripts): await completed automatic capture startup

Observe the real startup promise before exercising next-day account ownership, and always stop the service during cleanup. This removes the provider-entry timing race while preserving the ownership assertions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling app: android App: android app: web-ui App: web-ui docs Improvements or additions to documentation extensions: memory-core Extension: memory-core gateway Gateway runtime maintainer Maintainer-authored PR P3 Low-priority cleanup, docs, polish, ergonomics, or speculative work. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. scripts Repository scripts security-sensitive-changed size: XL status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plugin themes and agent-controlled appearance without Gateway restarts

1 participant