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 asprovadyne-hostbyci/build.sh. - Host id:
com.provadyne.host(the extension callschrome.runtime.connectNative/sendNativeMessagewith this name). - Requires the
nativeMessagingpermission (already declared inextension/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":"…"} |
statusonly checksGET /api/v1/health; it never spawns.ensure_daemonchecks health, and if the daemon is down it locates and launches the daemon binary, then polls health for up to ~10 s.startedreports whether this call launched it.- An optional
idon a request is echoed back for correlation.
How the host finds & starts the daemon
- Port: resolved with the daemon's own precedence —
DAEMON_PORTenv >~/.provadyne/config.json>9400(sharedinternal/config). - Binary:
$PROVADYNE_DAEMON_BIN> next toprovadyne-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. IfENGINE_PATHis unset (Chrome gives the host a minimal env), it defaults to~/.provadyne/enginewhen 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 thereg add HKCU\…\NativeMessagingHosts\com.provadyne.hostcommand 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.