ctx.flight (PluginFlightAccessor) lets you read live flight state, subscribe to flight-lifecycle events, write to the flight log, gate flight starts, and attach your own data to the PIREP.
ctx.flight.log — PluginFlightLogWriter
Add, remove, and update flight-log events. Events added here are authoritative flight-log telemetry — they appear in the Flight Log and are submitted to the VA like any other event.
ctx.flight.registerStartGuard(guard) — gate flight starts
A guard runs inside startFlight before the flight is created or persisted, covering both manual and auto-start. Returning { allow: false, reason } vetoes the start: it appears in the pre-flight check dialog as a check titled with your plugin’s name and described by the reason, shown alongside the built-in checks (and any other plugins’ guards). The pilot can still Start Anyway, which bypasses every check, guards included. Guards are fail-open: a throw or a >5s hang allows the start with a loud warning.
When to use it: to react to the flight lifecycle from the background — logging milestones, mirroring flight data somewhere, or blocking a start until your plugin is ready. For the same data in a UI component, the renderer hooks (useFlightPhase, useSimData, useTrackingSession) are usually simpler.
ctx.flight.attachToPirepSubmission(handler) — put your data on the PIREP
A handler runs while the airline PIREP is being assembled, after every milestone capture and immediately before the body is posted. Whatever it returns is attached to the submission under plugin_data["<your-plugin-id>"]. Return null to attach nothing for that flight.
The airline receives:
Keying by plugin ID means two plugins can both send a score without colliding.
plugin_data is a reserved top-level key on the submission body: it is added after the airline’s own custom submission fields are spread in, so an airline that names a submission field plugin_data has it silently overwritten. Avoid that name when configuring submission fields.
The handler receives flightId (local flight id), stratosFlightId, vaTrackingId, status (completed, diverted or crashed), plan and snapshot.
It is fail-open. A throw, a rejection, a hang past 3s, a non-object return, or data over the size limit below omits your plugin’s key and logs a warning. The PIREP is submitted either way. A broken plugin can never cost a pilot their PIREP.
The data you return is capped at 256 KB per plugin, and 512 KB across all plugins. This is measured on the JSON your handler returns, and keeps the PIREP body small enough for an airline’s server to accept. If one plugin’s data would push the total past 512 KB, that plugin’s data is dropped and the rest are still included if they fit. Files you attach with attachFile() do not count towards either limit: in the JSON, an attached file is only a short reference, and the file itself is sent separately (see Attaching files).
Handlers must be idempotent. If the airline rejects a PIREP the pilot can retry, and a retry runs every handler again. Do not write records, send requests, or mutate state from a handler; read what you already captured and return it.
When it does not run: cancelled flights (nothing is filed) and flights with no airline bound. Registering more than one handler is allowed; their results are shallow-merged under your single plugin key, later fields winning.
plugin_data reaches the airline only. It is not sent to Skyvex, so it does
not appear in Skyvex flight records or analytics.
Attaching files
Wrap a path in attachFile() anywhere inside the object you return, and the shell delivers the file to your airline with the PIREP.
The airline receives the submission as multipart/form-data: your JSON with each attachment replaced by { "$file": "<part name>" }, and each file as its own part under that name.
attachFile() only records the file’s path; it doesn’t open or read the file. Stratos reads it later, when the PIREP is sent, streaming it from disk rather than loading it into memory. So calling attachFile() never throws and never slows your handler, even for a large file or one that has since been deleted. If the file can’t be read when the PIREP is sent, it is skipped, its reference becomes { "$file": null, "error": "..." }, and the flight still files.
Attached files have no size or count limit. Stratos passes them straight through; your plugin and the airline’s backend own their own limits. This is separate from the 256 KB limit on the JSON data you return, which files don’t count towards.
Attaching a file changes how the PIREP is encoded for that submission, which
your airline’s backend must be built to accept. See PIREP file
attachments before shipping a plugin that uses
this, and declare "attachesFilesToPirep": true in your plugin.json so
airlines can see it before installing.