aerocontext
Pluggable aeronautical-context system: fetch weather/briefing products from
provider adapters behind capability traits, then compare them across sources
with per-source attribution. Serves a pilot as a briefing and an agent as
grounded context.
Crates
aerocontext-core— domain model, provider identity/capability traits, cycle-aware navdata snapshots, andcompare(cross-source reconciliation). No transport deps.aerocontext-awc— aviationweather.gov Data API adapter (REST/JSON).aerocontext-leidos— Leidos Flight Service Pilot Web Service adapter (REST + JSON, no SOAP: area & route briefings and NOTAMs). Targets the Leidos test server only for now.aerocontext-navdata— NASR→snapshot packer: cycle math, versioned blob format, manifest, fetch/ingest pipeline, CLI. The pure slice (cycle/manifest/blob-decode) is wasm-clean;ingest/fetch/clifeatures are native-only.aerocontext— facade:gatherone request across providers, thencompare; ships theaerocontextCLI (aerocontext brief KSFO --navdata "$(aerocontext-navdata current)").aerocontext-mcp— MCP stdio server exposing the system to AI agents.v99n62— experimental install-and-go entry point; the binary serves MCP over stdio.
Use
let provider: = new;
let briefing = provider.area_briefing.await?; // request: AreaBriefingRequest
let report = compare; // who said what, where they disagree
AI agents (MCP)
setup prints the exact MCP configuration for this machine — with the
binary's absolute path, because MCP clients spawn servers outside your
shell and a bare v99n62 often fails with ENOENT — and downloads the
current navigation-data snapshot so the first resolve answers
immediately. Copy the printed line, e.g.:
Tools: resolve, airspace, area_brief, notams, tfrs, route_alerts, route_brief,
navdata_sync, navdata_status. The notams tool reconciles FAA NMS and Leidos NOTAMs;
tfrs and route_alerts are Leidos. Set the upstream credentials to enable them — see
Credentials. ownship_status and
submit_command are designed and documented but not yet callable; command
escalation is gated by the safety boundary in ARCHITECTURE.md,
not by trait availability alone. Stdout belongs
to the MCP transport; diagnostics go to stderr via RUST_LOG (default
info). All data is advisory — never a sole source for real-world navigation
or flight decisions.
Credentials
Upstream credentials come only from environment variables — never a file the
program reads, never command-line args. They are held in a redacting Secret type
([redacted] in every log, Debug, and error message), URLs are scrubbed of any
userinfo before printing, and the OAuth bearer token NMS mints lives in memory only.
Nothing secret is written to disk. Each tool degrades gracefully: with no credentials
it returns an empty result and a note, never an error.
| Source | Environment variables | Enables |
|---|---|---|
| FAA NMS | FAA_NMS_CLIENT_ID, FAA_NMS_CLIENT_SECRET |
notams (FAA side) |
| Leidos Flight Service(test server only) | LEIDOS_VENDOR_ID, LEIDOS_VENDOR_PASSWORD |
notams (Leidos side), tfrs, route_alerts, and Leidos weather in area_brief/route_brief |
Local development — keep a gitignored .env at the repo root (it is in
.gitignore and is never committed) and source it into your shell:
# .env
FAA_NMS_CLIENT_ID=...
FAA_NMS_CLIENT_SECRET=...
LEIDOS_VENDOR_ID=...
LEIDOS_VENDOR_PASSWORD=...
; ;
Deployment — put the same variables in the MCP client's env block, injected
from your OS keychain (1Password op run, security find-generic-password, a
secrets manager) rather than pasted into a world-readable config file:
{ "mcpServers": { "aerocontext": {
"command": "/Users/you/.cargo/bin/v99n62",
"env": {
"FAA_NMS_CLIENT_ID": "op://vault/faa-nms/client-id",
"FAA_NMS_CLIENT_SECRET": "op://vault/faa-nms/client-secret",
"LEIDOS_VENDOR_ID": "op://vault/leidos/vendor-id",
"LEIDOS_VENDOR_PASSWORD":"op://vault/leidos/vendor-password"
}
} } }
On iOS there is no shell environment. The host app drives MCP through the
Swift SDK and calls the Rust
provider crates over FFI, reading the same credentials from the iOS Keychain
and handing them to the config constructors. The library sources credentials only
as data passed in — env vars are the desktop convenience — so the redaction and
never-on-disk guarantees hold identically on both targets. (The provider crates
are kept aarch64-apple-ios-clean by the ios-guard CI job.)
Leidos is pinned to its test server (ffspelabs); there is no production Leidos endpoint anywhere in the tree.
Navigation Data
Identifier-based areas use NavDataSnapshot: a serializable list of airports,
waypoints, and navaids tagged with NavDataCycle. NavDataCycle::faa_nasr
models the FAA 28 Day NASR Subscription cadence and records the source used to
produce the snapshot. Core does not download or cache FAA files; web, WASM,
iOS, and CLI shells fetch/cache data through their platform layer and pass the
same snapshot into Rust.
aerocontext-navdata produces those snapshots: .acnav blobs built from the
NASR CSV subscriber files (current + preview cycle), published per cycle to
GitHub Releases by .github/workflows/navdata-publish.yml. Shells bake in one
URL — the rolling manifest at
releases/download/navdata-manifest/manifest.json — and pick blobs by
effective date with Manifest::entry_for (derive "today" in UTC; cycle
boundaries are UTC-anchored).
On a user device the same crate is the consumer — zero configuration
(cargo install it; the library compiles for wasm32 and iOS with
--no-default-features for the pure slice, full features for on-device sync):
sync follows a subscription list: built-in defaults out of the box (the
official manifest, its IPNS mirror as fallback, and an IPFS gateway for blob
fallback by cid), or ~/.aerocontext/subs.json managed with
aerocontext-navdata subscriptions init|add|remove|show — never hand-written
JSON. It downloads current + prefetch blobs per authority into
~/.aerocontext/navdata and sha256-verifies every byte. Future pay-gated
sources fit the same file: a subscription may carry an auth reference naming
a header and an environment variable — the credential itself never lives in
the file. Build a cycle from FAA sources yourself:
Each release also carries a CARv1 archive of the same content for IPFS
mirroring; manifest entries record its root cid (IPIP-499 unixfs-v1-2025
profile, pinned ipfs-car under .github/navdata-tools, drift-gated by
scripts/cid-guard.sh). HTTPS stays the primary fetch path; the cid is a
content address anyone can pin:
&&
A pinning node runs scripts/pin-navdata.sh on a timer: it imports each
cycle's CAR, verifies the root CID against the manifest, and republishes one
IPNS name pointing at a directory of {manifest.json, blobs}. The IPNS key
lives only in that node's kubo keystore — never in CI secrets (the name is
the key hash and IPNS has no revocation, so a leaked CI secret would be a
permanent hijack; back the key up once with ipfs key export). The default
subscription already includes the IPNS manifest as fallback, so devices sync
entirely over IPFS whenever the primary URL is unreachable — no flags needed.
AWC accepts only coordinate/bbox requests, so attach a snapshot when it needs to
serve Area::LocationRadius:
let awc = new?.with_nav_data;
Design documents
ARCHITECTURE.md — layering, safety boundary, paid-data and secrets policy, extension seams, deliberate debt register. CERTIFIABILITY.md — what CI enforces, the data-chain assessment, and the gap-closing order. PREFLIGHT.md — the 14 CFR 91.103 coverage map: element by element, primary/backup/foreign sources and gaps.
Develop
The same script runs on every PR via .github/workflows/ci.yml. Binaries log
to stderr through tracing (RUST_LOG; CLIs default warn, servers info);
stdout carries results or the MCP transport only.
Tests hit mock servers only — no live endpoint. One #[ignore]d live AWC check:
cargo test -p aerocontext --test awc_live -- --ignored. Provider wire contracts
are pinned by wiremock tests and vendored in reference/.
License
Copyright (C) 2026 sokoly systems.
Licensed under the GNU Affero General Public License v3.0 only
(AGPL-3.0-only). This program is distributed in the hope that
it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.