@openuidev/openclaw-os-plugin
v0.1.3
Published
OpenClaw plugin that turns agent responses into Generative UI and serves the claw-client at /plugins/openclawos.
Readme
@openuidev/openclaw-os-plugin
The OpenClaw plugin behind OpenClaw OS. Bundles the workspace UI (
@openuidev/claw-client) and serves it from the gateway athttp://<gateway>/plugins/openclawos— no separate Next.js process, no tunnel, no settings dialog on first load.
Requires openclaw >= 2026.4.12.
What it does
The plugin is a single OpenClaw extension that performs four roles:
Serves the workspace UI. Registers an HTTP route at
/plugins/openclawos(viaapi.registerHttpRoute). The route serves the prebuilt static export of the workspace (Next.jsoutput: "export") bundled into the plugin'sstatic/directory. Browser tabs load the UI from the gateway origin and connect back over the same-origin WebSocket — no CORS, no allowed-origins config, no tunnel.Augments agent prompts for OpenClaw OS sessions. A
before_prompt_buildhook prepends the full inline-UI OpenUI Lang spec plus surface-routing guidance; abefore_tool_callhook blocksapp_create/app_updateuntil the agent hasreadskills/openui-app/SKILL.mdthat session. Both are scoped by the session-key suffix:openclaw-os, so other clients (CLI, scripts, third-party apps) are unaffected. See "Two UI surfaces" below.Provides persistent UI primitives. Lightweight stores for apps, artifacts, notifications, and uploads give agents addressable, persistent surfaces the workspace renders and updates across turns. See
app-store.ts,artifact-store.ts,notification-store.ts,upload-store.ts.Registers the
openclaw osCLI command group. Viaapi.registerCli. Theos urlsubcommand prints a token-authenticated workspace URL built from the gateway-validated config — same auth pattern asopenclaw dashboard. Clipboard and browser-open are left to the calling shell so the plugin stays free ofchild_process(which would trip openclaw's install security scan).
Two UI surfaces: one inlined, one loaded on demand (and gated)
The plugin teaches OpenUI Lang in two pieces, split by how often a turn needs each:
- Inline UI — one-shot UI in a chat reply (charts, tables, forms, follow-ups; static, no
$state/Query/Mutation). Used by almost every visual answer, so the full spec (prompts/openui-inline-ui.md, agenerate-prompt.tsartifact — not a skill) is prepended verbatim to every OpenClaw OS system prompt. - Durable apps — reopenable dashboards/trackers/command centers with the full reactive surface (
$state,Query,Mutation, scheduled refresh, SQLite). Larger and needed by a minority of turns, so it stays a load-on-demand skill (skills/openui-app/SKILL.md). The model tends to callapp_createwithout reading it, so abefore_tool_callhook blocksapp_create/app_updateuntil the agent hasreadit that session (per-session set persisted to<state-dir>/plugins/openclaw-os/app-skill-read-sessions.json, so restarts don't force a re-read).
Install
For end users, install OpenClaw OS via the installer script from the root README:
macOS or Linux:
curl -fsSL https://openui.com/openclaw-os/install.sh | bashWindows:
powershell -c "irm https://openui.com/openclaw-os/install.ps1 | iex"Opening the workspace
The workspace is served from your gateway — most likely http://localhost:18789/plugins/openclawos. For the pre-authenticated URL, run openclaw os url.
From a local clone
# Build the workspace static export and copy it into ./static/
pnpm bundle-ui
# Build the plugin's own dist/ (esbuild bundle)
pnpm build
# Clear local node_modules before installing. pnpm's escaping symlinks trip
# openclaw's install scanner, and the bundled dist/ has no runtime deps.
# macOS or Linux: rm -rf node_modules
# Windows PowerShell: Remove-Item -Recurse -Force node_modules
# Install + reload, then open it
openclaw plugins install ./packages/claw-plugin --force
openclaw gateway restart
openclaw os urlIf ~/.openclaw/openclaw.json has a non-empty plugins.allow list, add openclaw-os-plugin to it. With an empty plugins.allow (allow-all) no action is needed; without pinning when an allow list is set, the gateway lazy-reloads the plugin on every tool lookup and app_create fails intermittently.
Scripts
pnpm bundle-ui # build claw-client and copy out/ → ./static/
pnpm build # esbuild bundle src/index.ts → dist/index.js
pnpm lint:check # ESLint
pnpm lint:fix # ESLint --fix
pnpm format:check # Prettier --check
pnpm format:fix # Prettier --write
pnpm typecheck # tsc --noEmit
pnpm test # vitest run
pnpm ci # lint + format + typecheckProject layout
packages/claw-plugin/
├── src/
│ ├── index.ts # entrypoint: hooks (prompt + app-skill gate) + tools + RPC + HTTP route + CLI
│ ├── app-store.ts # app primitive store
│ ├── artifact-store.ts # artifact primitive store (SQLite-backed)
│ ├── lint-openui.ts # validation for emitted OpenUI Lang
│ ├── notification-store.ts # notification store
│ ├── upload-store.ts # upload store
│ └── generated/ # generated assets — openui-schema.json (do not edit by hand)
├── prompts/
│ └── openui-inline-ui.md # inline-UI OpenUI Lang spec — inlined into the system prompt (not a skill)
├── skills/
│ └── openui-app/SKILL.md # durable-apps skill — loaded on demand, gated by app_create/app_update
├── generate-prompt.ts # regenerates prompts/, skills/openui-app/, and src/generated/ from the OpenUI library
├── static/ # workspace static export (gitignored, populated by `pnpm bundle-ui`)
├── dist/ # esbuild output (generated by `pnpm build`)
├── openclaw.plugin.json # plugin manifest
└── package.jsonNotes for plugin developers
openclawis inpeerDependenciesanddevDependencies, neverdependencies. The runtime gateway provides the module.- Types come from subpath exports:
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"andfrom "openclaw/plugin-sdk/core". SeeAGENTS.mdfor the full guidance. - The plugin ships compiled JS at
dist/index.js, bundled by esbuild.package.jsonmainandopenclaw.extensionsboth point there. Older "jiti loads.tsdirectly" behavior was removed in openclaw 2026.5.x. - Plugin RPCs and tools that share names with gateway-core surfaces (
artifacts.*,tools.invoke) are namespaced underopenclawos.*to avoid collision. app_create/app_updateare gated by abefore_tool_callhook (mustreadskills/openui-app/SKILL.mdfirst; state in<state-dir>/plugins/openclaw-os/app-skill-read-sessions.json). The inline-UI spec (prompts/openui-inline-ui.md) is read at startup bysrc/index.tsand prepended viabefore_prompt_build. Both:openclaw-os-only. See "Two UI surfaces" above.- The
static/directory is treated as opaque content. The HTTP handler serves whatever is in there with sensible MIME types and a path-traversal guard.pnpm bundle-uiis the only thing that should write to it. - For end-user setup story, architecture rationale, and what's still TODO, see
docs/openclaw-os-bundling.md.
