Code Organisation
Keep your root component thin.src/ui/index.tsx should delegate immediately to a router or page component — it should not contain business logic.
As your plugin grows, use this structure:
src/ui/index.tsx must have a single export default. Named exports are ignored by the shell loader.
Performance
Always use select with useSimData()
Simulator data updates at ~60fps. Without select, your component re-renders on every frame:
Split components by data needs
If one part of your UI needs high-frequency sim data and another only needs the flight phase, make them separate components:Don’t poll when you have Socket.io
The SDK hooks (useSimData, useFlightPhase, useFlightEvents, useLandingAnalysis, useTrackingSession) all use Socket.io for real-time push updates. They hydrate once via REST on mount, then stay current via WebSocket. Don’t set up your own polling intervals for data the shell already pushes.
Data Fetching
Use TanStack Query for your own API calls. TanStack Query is provided by the shell at runtime:Settings Design
Airline-scoped for VA-controlled content. Welcome messages, links, branding, event rules, route configurations — anything the VA admin should control centrally. These can be updated from the Skyvex platform without rebuilding the plugin. User-scoped for personal preferences. Unit systems, display toggles, notification preferences, refresh intervals. Each pilot can customise these independently. Always provide sensible defaults. Your plugin should work out of the box without any settings configured:Logging and Error Handling
Use the SDK logger
Never useconsole.log directly. Use the SDK loggers — they write to Stratos’ log files with timestamps and your plugin ID prefix, which is essential for troubleshooting production issues.
Handle async errors gracefully
For API calls and async operations, show meaningful error states:Use toast for transient errors
Styling
Use Tailwind utility classes. Your plugin inherits the shell’s full Tailwind config including the theme system. Dark mode works automatically when you use semantic tokens. Use SDK UI components for consistency.Button, Card, Badge, Dialog, Input, etc. are all themed and support light/dark mode. Using a third-party component library will look out of place.
Respect the layout. Your plugin renders in the main content area next to the sidebar. Fill the container and handle overflow:
Versioning
Follow semver. Bump the version inplugin.json for each release:
- Patch (
1.0.1): Bug fixes, minor text changes - Minor (
1.1.0): New features, new settings - Major (
2.0.0): Breaking changes, major redesigns
plugin.json and package.json versions in sync.
Common Pitfalls
Bundling shared dependencies
If your bundle is unexpectedly large, you might be accidentally bundling React, TanStack, or the SDK. ThecreatePluginConfig() Vite factory externalises these automatically — only if you’re using it. Check that your vite.config.ts uses createPluginConfig and not a custom Vite config.
Forgetting the default export
The UI module must have adefault export that is a React component. Named exports are ignored:
Using console.log
console.log output goes to Electron DevTools but not to log files. Use the SDK logger so that logs are captured in production for troubleshooting.
Mutating sim data
The data returned fromuseSimData() is shared across all consumers via the TanStack Query cache. Never mutate it directly — treat it as read-only.
Not handling the “no flight active” state
Many hooks return null or empty data when no flight is being tracked. Always handle this case:Background module not loading
If your background module isn’t running, check:- Your
vite.config.tshasbackground: { entry: "src/background/index.ts" } - Your build script runs both builds:
"build": "vite build && BUILD_TARGET=background vite build" dist/background/index.jsexists after building- Your module exports
onStartandonStop(or usescreatePlugin)
Stale plugin after changes
In dev mode, UI changes hot reload automatically. For other change types:plugin.json— restart the app- Background module — rebuild (
pnpm build) and restart Stratos - New npm dependencies — run
pnpm installthen restart
Plugin not appearing in sidebar
Check that:- Your
plugin.jsonis valid (use the$schemafor editor validation) - The
idfield uses only lowercase alphanumeric characters and hyphens - Your plugin is installed in the Stratos plugins directory, or your dev server is running and connected
- No other plugin uses the same
id
Debugging
UI: Open Chrome DevTools (Cmd+Option+I on macOS, Ctrl+Shift+I on Windows). Your plugin components appear in the React DevTools tree under the PluginHost wrapper.
Background: Background module logs go to the Stratos log files:
- macOS:
~/Library/Application Support/stratos/logs/stratos-YYYY-MM-DD.log - Windows:
%APPDATA%\stratos\logs\stratos-YYYY-MM-DD.log
http://127.0.0.1:2066/api/.... Test them directly with curl or a browser during development.