Skip to content
github-actions[bot] edited this page Sep 11, 2026 · 19 revisions

WP OpenStation — Developer Documentation

This folder is the contract between WP OpenStation and the plugins that extend it.

If you are building a plugin that interacts with the desktop shell — opens windows, adds dock items, listens to window events, drops icons on the wallpaper — start here.

Index

  1. Getting Started — your first hook, in five minutes.
  2. Event-Driven FrameworkStable. The mental model: framework as transport, apps own UX policy. Read once before building anything non-trivial.
  3. Agents Security ModelExperimental. The trust model for the one part of the framework that acts with capability: why agents can never authenticate, why a run is ceilinged at the invoker's capabilities, why tool output is untrusted input, and why granting an agent a role is granting capability. Read before registering an ability agents can call or adding a trigger intake.
  4. Architecture — what renders where, and why. 4a. Data model — where every piece of data is persisted: the eight plugin-owned tables, the two custom post types, every user / post / comment meta key, every option and transient, the upload directories and the cron hooks — with entity–relationship diagrams. Read before adding a store or touching a stored name (the desktop_mode_* values are frozen).
  5. Station Home — the native Dashboard replacement: an App Framework app painted on the server, the plugin-card contract, the responsive design contract, and the Imagegen record.
  6. Hooks Reference — every PHP action and filter, with signatures, defaults, and minimal examples.
  7. JavaScript Reference — CustomEvents on document, the window.wp.os API, and the iframe postMessage bridge.
  8. API Index — single-page table of every wp.os.* method, CustomEvent, and postMessage type with its current status. Use this when you need to grep the surface, then jump to the per-API reference for details.
  9. Examples — recipes you can copy into a plugin.
  10. Bridge Protocol Overviewinternals doc. End-to-end wiring of wp.os.connect() / wp.os.iframe.* / the synthesised iframe inside native windows. Read when debugging a stuck handshake or building unusual integrations.
  11. Native Windows & Framework InteropStable. Public API for openstation_register_window() / openstation_register_window_tab(), Web Components as first-class, and how React / Vue / Svelte plug in without the shell taking a framework dependency. See also examples/native-windows.md and examples/native-window-with-tabs.md.
  12. Dock CustomizationStable. Three orthogonal registries — decoration hooks, submenu renderer, dock rail renderer — that let a plugin author go from "tweak a className" to "replace the entire rail with a circular ring." Start here if you want to customize the dock visual.
  13. WorkspacesStable. A virtual desktop plus the answer to what it is FOR: which apps show on it, which widgets sit on it, what it looks like, which windows it opens with, how they are arranged. Three templates ship — Commerce, Learning and Publishing, named for the job and built around the products that do it — offered as cards by the wizard behind the overview bar's + (whose first step is a blank desk one Enter away), and a plugin adds its own from one PHP filter. Covers the token-matching that makes a template degrade instead of break, the one rule the whole feature rests on — rails, widget column and appearance are all views, never written back to the user's settings — and the columns / focus arrangements. See also examples/workspace-preset.md.
  14. Plugin Compatibility Layerinternals doc. How OpenStation adapts third-party plugins (WooCommerce, Yoast, etc.) whose CSS or menu-registration assumes classic admin chrome. The three-tier mental model — CSS variables → runtime offset scanner → targeted overrides — and the decision tree for adding a new fix. Read before touching chromeless.css or the dock builder for plugin-specific work.
  15. Files on the DesktopExperimental. OpenStation_File base class, openstation_register_file_type(), and wp.os.files.*. The registry, folders, opener associations with per-user overrides, folder sharing, real file storage, and the Trash pin-to-desktop flow are all live.
  16. Desktop ThemesExperimental. Whole-OS reskins uploaded as a ZIP of theme.json plus images and fonts: every design token, the typeface, a texture on any of 24 surfaces (chrome, dock, desk, menus, dialogs, tables, buttons) plus a documented way to add your own, and a complete iconset down to the window control glyphs. No author CSS or JS ever executes — PHP validates the manifest and compiles the stylesheet, @font-face rules included. Read before authoring a theme, or before touching the texture and typography tokens in variables.css. See also examples/register-desktop-theme.md.
  17. Folder SharingExperimental. Per-principal read / write grants on desktop folders with first-sight opt-in, polymorphic target_type schema, If-Match conflict detection, and a <os-modal>-based Share Settings UI.
  18. MioExperimental. The desk companion: a PixiJS soft-body blob with a chroma neon outline that floats over the wallpaper, feels the gravity of nearby windows and settles onto them, watches your cursor (including across window iframes), and can be dragged anywhere. Covers the simulation, the four soft-body failure modes worth knowing before touching it, the openstation_mio_config filter, and wp.os.mio.
  19. Icons: Stable. The thirty-icon set and the one rule behind it: Core owns the verbs, OpenStation owns the nouns. Covers osIcon() / osIconSvg() / osIconDataUri(), the sizing floor below which a Core glyph goes faint, the three groups that stay hand-drawn and why, and how the same eleven reach WordPress's own icon registry as outlines. Read before drawing any glyph.
  20. Native Desktop HostExperimental. The optional Electron layer, shipped as an extension so core never mentions Electron: any window can be set free into a real OS window ("Send to your Mac"). Covers the two generic core capabilities it stands on (wp.os.registerWindowAction() and ?openstation_solo=), the capability-probe detection model, and the deliberately cheap liveness pulse. Read before touching the ⋯ menu or solo mode.
  21. Progressive Web App (PWA)Stable. Web app manifest, service worker (root-scope, narrow fetch handler), install affordance, and wp.os.notify() for local notifications. Phase-4 Web Push wiring lands later without breaking the v1 call surface.
  22. Layered layout — the structural refactor that split the historical god-modules: the @core / @api / @protocol / @layout / @ui path aliases, the registry / server-sync / api-client primitives, the public-API facade home, and the PHP slicing of helpers.php / components.php / render.php. Read once before adopting any of the new modules in your plugin.
  23. Migration — activity channels move to os/ (1.0.0) — the eleven framework-published activity channels drop the pre-rebrand desktop-mode/ prefix. No alias ships: a subscriber left on an old slug stops firing silently. Read if you subscribe to or filter any built-in channel.
  24. Migration — native window tabs move to the chrome — a multi-tab native window no longer renders an <os-tabs> strip into its body; the shell builds one strip in the window chrome from the same metadata. openstation_register_window_tab() is unchanged. Read if you listened for os-tab-change, or styled or queried that strip.
  25. Migration — window, wallpaper and widget bundles load on demand — a window's script loads on first open, a canvas wallpaper's when it's applied or previewed, a widget's when it mounts — instead of all of them on every admin page. Nothing to do for a bundle that only publishes its render/mount callback; read if yours also has a boot-time job, extends another plugin's window, or calls an API one publishes.
  26. Migration — the navigation model — one model decides where every menu, app and control shows up; itemVisibility / dockOrder become navPlacement / navOrder, native windows take nav_kind, and rails paint three zones. Read if you register a native window with a dock tile, read or write OpenStation Preferences state, or ship a dock rail renderer.
  27. Migration — WordPress package globals are no longer ambient — deferring Core's ⌘K runtime took wp.apiFetch, wp.element, wp.data and wp.components off every admin page. Declare the packages your script uses as dependencies. Read if anything you ship touches a wp.* global.
  28. Migration — the shell boots from its own screen — the desktop is served by admin.php?page=openstation instead of being painted over the Dashboard (or whichever screen the portal forwarded to), so another screen's scripts, render and hidden HTML never reach the shell document. desktop_mode_portal URLs become alias redirects. Read if you keyed anything on the shell being the Dashboard, or built desktop URLs by hand.
  29. Register a widget — polling, storage, canvas charts
  30. The App Framework — a window in one PHP fileExperimental. .os.php apps: declare a whole window (title, size, title-bar buttons, ⋯ rows, tabs, state, actions, view) in PHP, with <os-*> components and a small attribute vocabulary (os-action, os-bind, os-poll, os-prop-*, …), and ship no JavaScript — or add an .os.ts client view (defineApp()) for the interactions that must be instant. Covers the state cycle, the $os data-access layer that keeps the core WordPress-free, the standalone host, and the client runtime. Code Blue (apps/code-blue/) is built on it. See also examples/os-app.md.
  31. Migration — Code Blue becomes an App Framework app — the desktop-mode/v1/code-blue/* REST routes and the openstation_code_blue_{window_args,icon_args,template_html} filters are gone; the window, its id, its gate and its other hooks are unchanged. Read if you called those routes or filters.
  32. Migration — WP Explorer becomes the my-wordpress app — the legacy desktop-mode-my-wordpress native window, its bundle and the wp.os.myWordpress API are gone; the app carries the name, the launcher and every surface (footprint included). Read if you opened, configured or extended the legacy window.
  33. Migration — the Recycle Bin becomes an App Framework app — the openstation_recycle_bin_{window_args,template_html} filters, the legacy bundle and its config global are gone; the frozen window id, the store/capture/realtime hooks, the REST routes and the JS columns filter are unchanged. Read if you filtered the bin's registration or template.
  34. Migration — Station Home becomes an App Framework app — the desktop-mode/v1/station-home REST routes, the openstation_station_home_{register_window,build_snapshot,…} functions and the bundle are gone; the window id, the URL remap, the opt-in and the whole plugin-card API are unchanged. Read if you fetched the snapshot or posted a card preference.
  35. Migration — OpenStation Preferences becomes an App Framework app — the lazy os-settings-panel bundle, its config key and the os-settings stylesheet handle are gone; the window id, openOsSettings(), registerSettingsTab() and every settings key are unchanged, updateOsSettings() now accepts every key, and resetOsSettings() is new. Read if you touched the panel bundle or its sheet. 35a. Migration — Posts, Pages, Users, User Edit, Plugins and Comments become App Framework apps — the openstation_{posts,pages,users,user_edit,plugins,comments}_window_{args,template_html} filters, the os-posts-window / os-plugins-window / os-comments-window bundles and stylesheets, and the shared-store deep-link hand-offs are gone; the frozen window ids, the gates, the query-args and REST-field hooks, the REST routes and the JS hook-bus filters are unchanged, and deep links ride open-time params (userId, post, tab). Read if you filtered a registration or template, imported a window bundle, or set a target store before opening one of these windows.
  36. The Living Tree — algorithm definitionExperimental. The full normative spec for the wp-living-tree canvas wallpaper: WordPress emits hormones, the biology (Space Colonization) decides geometry inside age-bounded morphological constraints. Read before touching any part of the wallpaper.
  37. MultisiteExperimental. What the shell does on a network: the network admin, the Network Admin dock tile, and per-site session scoping. Read before touching anything cross-site — it opens with the constraint that decides the rest, which is that WordPress refuses to be framed cross-origin, so nothing leaving the current site can be a window.
  38. Mobile — the phone layerExperimental. wp.os.mode (desktop | tablet | mobile) and what the shell does when it says mobile: a home screen of the same navigation items, one full-screen window at a time under a slim top bar, a swipeable app switcher, a five-slot tab bar, an edge-swipe Back — and a session that a phone visit never rearranges. Covers the data-os-mode CSS hook, the head stamp that makes the first paint right, the os.session.snapshot filter, and what a phone does and does not pay for. See also examples/mobile-tab-bar.md.
  39. OpenStation NetworkExperimental. Separate installs, each with OpenStation, showing one site switcher: a hub keeps the list, every install publishes an Ed25519 key that its peers pin when pairing, members fetch the list with signed requests, a switch to another install logs the user in there through a signed hop token, and the Network app is the one-time admin task behind it. Read for the trust model before touching anything cross-install.

Conventions used in this docs folder

  • Status labels — every hook, event, or API surface carries one of:
    • Stable — shipping today, backwards-compatible inside the current major version.
    • Experimental — shipping but signature may change.
    • Planned — reserved name, not yet fired. Do not rely on it.
  • Code examples are complete, drop-in, and use my_plugin_ / my-plugin prefixes as they would in a real plugin.
  • PHP examples assume a plugin file with defined( 'ABSPATH' ) || exit; at the top.
  • No version tags — these docs describe what the current release does, not when a given surface was added. Breaking changes get a migration-*.md note instead of inline version annotations.

Reporting breakage

If a documented hook behaves differently than what's written here, that is a bug in either the code or the docs. Open an issue or PR. Do not work around it silently — the docs are source of truth for plugin authors.

Home

Guides

Migration notes

More

Examples

All examples

Clone this wiki locally