The richest, most powerful way to run Mission Control on the desktop: a native
Electron shell wrapping the self-contained mission_control_v2 SPA. No
Streamlit, no Python runtime required for the core app — the SPA talks to
Socrata, OpenAI, and Gemini directly. This produces a true standalone installer
(.exe / .dmg / AppImage) with native menus, system tray, persisted window
state, and auto-update.
┌─────────────────────────────────────────────┐
│ Electron main process (main.js) │
│ • secure BrowserWindow (contextIsolation) │
│ • native menu + system tray │
│ • auto-updater (GitHub releases) │
│ • optional Python FastAPI sidecar │
│ └─ renderer/index.html ← the SPA │
└─────────────────────────────────────────────┘
| Streamlit + pywebview | This (Electron) | |
|---|---|---|
| Python required to run | ✅ yes | ❌ no (SPA is client-side) |
| Native menus / tray / notifications | limited | ✅ full |
| Auto-update | none | ✅ electron-updater |
| Signed cross-platform installers | basic | ✅ electron-builder |
Self-contained .exe |
hard (heavy deps) | ✅ clean |
- Node.js 18+ and npm — nodejs.org
- (Optional) icons in
build/— seebuild/README.md
cd desktop
npm install
npm start # copies the SPA, launches Electron in devIn dev the app loads the canonical SPA directly from
../app/static/mission_control_v2.html, so edits there show up on reload
(View → Reload).
npm run dist # current OS
npm run dist:win # Windows NSIS installer (.exe)
npm run dist:mac # macOS .dmg
npm run dist:linux # Linux AppImageOutput lands in desktop/dist/. The predist hook copies the SPA into
renderer/index.html (single source of truth — never edit that file directly).
electron-updater is wired to GitHub releases (ryudkiss-hue/nyc_data).
Publish a release with the built artifacts and installed clients will update
automatically on next launch. To publish from CI:
GH_TOKEN=… npm run dist -- --publish alwaysThe SPA is fully client-side, but if you want the heavy Python analytics
(PyMC Bayesian, Prophet) exposed to a future SPA panel, the main process can
spawn the FastAPI backend (socrata_toolkit.api:app) as a sidecar:
MMC_SIDECAR=1 MMC_PYTHON=python npm startThis requires the Python deps installed (pip install -e ".[mission]") and is
off by default — the desktop app runs fully without it.
contextIsolation: true,nodeIntegration: false,sandbox: true- The renderer reaches the OS only through the audited
window.missionControlbridge inpreload.js - All external links open in the system browser, never in-app