Skip to content

Native Messaging Host (daemon launcher)

The Chrome extension talks to the local daemon over HTTP (localhost:9400). That works only while the daemon is running — and a browser cannot start a local process on its own. The native messaging host (provadyne-host) is the control channel that closes this gap: Chrome launches it on demand, and it can start the daemon for the user without them opening a terminal.

Heavy work (analysis, PDF export) still goes over HTTP — native messaging caps a host→extension message at 1 MiB, so it is used only for "is the daemon up / start it", never to proxy results.

Architecture

Chrome extension ──HTTP──▶  daemon (localhost:9400)   ◀── analysis, reports
       │                          ▲
       └──native messaging──▶ provadyne-host ──spawns──┘
          (com.provadyne.host)    (control channel only)
  • Binary: daemon/cmd/nativehost → built as provadyne-host by ci/build.sh.
  • Host id: com.provadyne.host (the extension calls chrome.runtime.connectNative / sendNativeMessage with this name).
  • Requires the nativeMessaging permission (already declared in extension/manifest.json).

Protocol

Length-prefixed JSON over stdin/stdout (Chrome's native messaging framing: a 32-bit length in native byte order, then the UTF-8 JSON message).

Request Response
{"type":"ping"} {"type":"pong","host_version":"…"}
{"type":"status"} {"type":"daemon_status","running":bool,"port":N,"version":"…"}
{"type":"ensure_daemon"} {"type":"daemon_status","running":bool,"started":bool,"port":N,"version":"…","error":"…"}
  • status only checks GET /api/v1/health; it never spawns.
  • ensure_daemon checks health, and if the daemon is down it locates and launches the daemon binary, then polls health for up to ~10 s. started reports whether this call launched it.
  • An optional id on a request is echoed back for correlation.

How the host finds & starts the daemon

  • Port: resolved with the daemon's own precedence — DAEMON_PORT env > ~/.provadyne/config.json > 9400 (shared internal/config).
  • Binary: $PROVADYNE_DAEMON_BIN > next to provadyne-host (the install layout co-locates them in /usr/local/bin) > on $PATH.
  • Spawn: detached into its own session (Unix setsid / Windows new process group) so it outlives the host, with stdout/stderr → ~/.provadyne/daemon.log. If ENGINE_PATH is unset (Chrome gives the host a minimal env), it defaults to ~/.provadyne/engine when that exists.

On macOS the installer also sets up a LaunchAgent (KeepAlive), so the daemon is normally already running; the host is the fallback for when it isn't (and the primary mechanism on platforms without the LaunchAgent).

Extension integration

CHECK_DAEMON now self-heals: if the HTTP health check fails, the service worker asks the host to ensure_daemon and re-checks. START_DAEMON is the explicit, user-triggered version (e.g. a "Start daemon" button). If the host isn't installed, both degrade gracefully to the previous "daemon not reachable" state (hostAvailable: false).

Registering the host manifest

Chrome only launches a host whose manifest lists the calling extension id in allowed_origins. The binary registers itself:

# write the manifest to every installed Chromium-family browser
provadyne-host --install <chrome-extension-id>

# inspect what would be written
provadyne-host --manifest <chrome-extension-id>

# remove it
provadyne-host --uninstall

Manifest locations (user-level):

  • macOS: ~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.provadyne.host.json (also Chromium / Edge / Brave when present)
  • Linux: ~/.config/google-chrome/NativeMessagingHosts/com.provadyne.host.json
  • Windows: manifest written under %APPDATA%\Provadyne; the binary prints the reg add HKCU\…\NativeMessagingHosts\com.provadyne.host command to run.

ci/macos/install.sh installs provadyne-host next to the daemon and, when PROVADYNE_EXTENSION_ID is set, auto-registers the manifest. Until the extension is published (its id is fixed only once on the Web Store), registration is a one-line manual step after loading the extension.