Build a module
A module translates between an external system and Mainframe’s capabilities. Start by deciding what entities the integration provides, which channels they publish, and which commands the integration can actually perform.
bun run new:serviceThe generator describes its arguments when invoked without them. Existing modules are useful examples: weather for a periodic feed, radar-net for a stream, TAK for a provider that also consumes Mainframe, and world-sim for flight and media capabilities.
Connect and report
Section titled “Connect and report”Use @workspace/provider/index for registration and publishing. Read the API key with the shared environment helpers, which support secret files. Keep external IDs stable. Publish unavailable fields as the capability contract specifies; avoid invented measurements.
Use provider.health("degraded", "reason") when an upstream fails. A process responding to HTTP can still have a failed device or feed. Add numeric workload statistics to heartbeats, such as active sessions, stale sites, or messages received.
Expose /api/health on the module’s private HTTP port. Expose /metrics with metricsResponse from @workspace/provider/metrics; the provider SDK already tracks connections, queued and dropped samples, protocol errors, and command outcomes. Add module-specific metrics when they explain useful work or a failure mode. Do not use tokens, URLs, free-form errors, or unbounded detection IDs as metric labels.
Handle commands carefully
Section titled “Handle commands carefully”Only advertise commands that have handlers. Declare unsupported operations and lease requirements in command policies. Observe mode should still allow the lifecycle operations required by the integration, but it must not imply permission to fly an aircraft.
Use cancellation signals for pending work. On reconnect, reconstruct the current registration and device state. Never assume that an old socket’s acknowledgement belongs to a new command session.
Add deployment support
Section titled “Add deployment support”- Add the module’s policy and credential configuration to Mainframe.
- Give the service its own Dockerfile, health check, environment fields, and Compose profile.
- Add it to
deploy/modules.tsso the launcher selects it and Prometheus discovers its metrics. - Document required upstream access and credentials.
- Test its provider contract, failure and reconnect behavior, then run it against an isolated Mainframe.
Keep vendor SDKs and protocol logic in the module. Terminal should consume the resulting capabilities through the client SDK.