Stratos is built on a shell + plugin model. The shell owns the infrastructure — auth, routing, simulator connections, IPC bridge, theming, and the sidebar. Plugins are independently deployable modules that extend the shell with custom UI pages and/or background services.Documentation Index
Fetch the complete documentation index at: https://docs.skyvexsoftware.com/llms.txt
Use this file to discover all available pages before exploring further.
Shell-Plugin Contract
The shell and plugins communicate through a strict, versioned contract. Plugins never import from the shell directly — all access goes through the SDK’s context objects and hooks, which the shell injects at runtime. Each plugin runs in its own host — errors in one plugin don’t crash others. IPC channels are automatically namespaced toplugin:{pluginId}:* to prevent collisions.
Plugin Lifecycle
Plugins go through four stages from discovery to teardown:1. Discovery
On startup, the shell scans the plugins directory and reads each plugin’splugin.json manifest. The sidebar order is determined by the VA owner’s configuration on the Skyvex platform.
2. Load
The shell loads the background module (ifbackground/index.js exists in the plugin’s install directory) for each discovered plugin. This happens after auth is initialised, so the background module receives a fully populated PluginContext.
If onStart() throws, the plugin is marked as errored. Other plugins continue loading normally.
3. Mount
When a pilot navigates to a plugin’s sidebar entry, the shell lazy-loads the UI module and mounts it inside aPluginShellProvider. This provider supplies PluginUIContext to all child components via React context.
The UI module is unmounted when the pilot navigates away, but the background module keeps running.
4. Unmount / Stop
On shell shutdown,onStop() is called for each running background module. Use this to close connections, flush data, or cancel timers.
UI Module vs Background Module
| UI Module | Background Module | |
|---|---|---|
| Where it runs | Electron renderer process (React) | Electron main process (Node.js) |
| Entry point | src/ui/index.tsx | src/background/index.ts |
| Lifecycle | Mounted/unmounted on navigation | Runs from startup to shutdown |
| Context | PluginUIContext via usePluginContext() | PluginContext passed to onStart() |
| Use for | Display, interaction, flight data visualisation | Express routes, IPC handlers, background tasks |
PluginContext
Passed to your background module’s onStart(ctx) function. Provides scoped access to shell infrastructure:
plugin:{pluginId}:* — you can’t accidentally handle another plugin’s messages.
PluginUIContext
Available in renderer components via usePluginContext(). Provides synchronous access to the same capabilities as PluginContext, plus navigation and UI utilities:
config.get() is synchronous in the UI context (values are pre-loaded when the plugin mounts), while ctx.config.get() in the background context returns a Promise.
IPC Communication Model
The shell’s IPC bridge auto-prefixes all channel names to prevent cross-plugin pollution. When your background module registers a handler:plugin:my-plugin:get-status. This means two plugins can both register a "get-status" handler without conflict.
To communicate between your UI and background modules, register Express routes in the background module via ctx.server.registerRouter() and fetch them in the UI with TanStack Query. This keeps data flowing through standard HTTP rather than requiring a custom IPC abstraction.