This is the minimal working OWOX plugin in the v2 (capability-broker) shape. Copy it, edit three
files, and install by pasting owner/repo into Install from URL — the host bundles backend.ts
for you (no CI, no release tarball, no Docker).
plugin.json # v2 manifest: ui + backend + declared credentials[] + credential-free settings[]
ui/ # React + Tailwind frontend (static build) — runs in a sandboxed iframe
App.tsx # reads settings, calls a capability (ai.chat) directly, toasts
backend.ts # OPTIONAL, experimental — runs in dev:broker only (prod pending the WASM sandbox)
This plugin depends on no OWOX npm package. @owox/plugin-sdk isn't on npm yet, so it's not a
dependency at all: the host serves it to the iframe at runtime, dev/test alias it to the local mock
(ui/sdk-mock.ts), and tsconfig paths types it. So npm install pulls only public packages and
never blocks. (Once the SDK is published, add it back as a devDependency and drop the tsconfig alias.)
npm install # types-only SDK; never fails on an unpublished package
npm run dev # Vite → browser, hot reload, MOCK SDK, LOCAL creds (no host)
npm run dev:broker # Vite → real SDK talking to a broker fed from owox.dev.json (no host chrome)
npm test # vitest, against a local SDK mock (ui/sdk-mock.ts)
npm run typecheckTwo ways to run without deploying the full host:
npm run dev— swaps@owox/plugin-sdkfor the local mock (ui/sdk-mock.ts) so the UI runs with no host. Set local creds/settings by editingDEV_DEFAULTSin that file, or from the console:localStorage.setItem('owox.dev.settings', JSON.stringify({ 'github-repo': 'me/repo' })).settings/storageare real (localStorage);backend.call+ brokered capabilities are stubbed and logged. Fastest loop for pure UI work.npm run dev:broker— serves only the iframe plus a real capability broker fed fromowox.dev.json(cp owox.dev.example.json owox.dev.jsonfirst). That file mirrors the prod vault + SettingsStore shapes (owox,credentials[],settings.{global,byProject}), so your plugin talks to it through the unchanged SDK and behaves identically to production — only the source differs.owox.apiKeysecures OWOX entity access;credentials[]feed ai/git/sheets;settingsfeedsettings.getwith real JSON types.backend.call()also runs here (experimental — your own code in an in-process engine; production backend is pending the host sandbox). Runs from the owox monorepo.
You never run npm run build yourself: the host builds ui/ on install (see the root AGENTS.md §7).
plugin.json— name, menu, declaredcredentials[], credential-freesettings[].ui/App.tsx— your screen. Import{ owox, ai, storage, git, sheets, credentials, settings, ui, backend }from@owox/plugin-sdk. The iframe holds no tokens.backend.ts— named async fns.ctxis the capability surface (minusui) plusctx.log/ctx.settings. Nofetch/fs/process— capability access is only throughctx.
The host is a capability broker; the plugin has zero ambient authority. It never holds a token
or credential — it declares what it needs, the user consents at install, and the broker injects the
credential at the boundary. See the root AGENTS.md for the full author contract.