# packaging/nativehost — the Firefox native-messaging manifest Owner: lane DAEMON (`packaging/nativehost/**` is explicitly DAEMON's per `CLAUDE.md`'s lane table, unlike the rest of `packaging/`, which is PKG/QA's). This directory holds the manifest `velox-nmhost` (built from `nmhost/`) is registered under, and this file is the one place that says exactly which on-disk locations need it and why — the "install manifests to all four locations" line in `docs/agents/AGENT-DAEMON.md`'s build order predates `docs/adr/0003-native-messaging-under-snap.md`, which cut that down to three *real* ones. Read the ADR before touching this list; it is the empirical spike, not a guess. ## The manifest `com.velox.host.json` in this directory is the template: ```json { "name": "com.velox.host", "description": "Velox download manager — native messaging bridge to veloxd", "path": "/usr/libexec/velox/velox-nmhost", "type": "stdio", "allowed_extensions": ["velox@velox.download"] } ``` - `name` is what the extension calls `browser.runtime.connectNative("com.velox.host")` with (`extension/src/background/transport/native.ts`'s `HOST_NAME`) — do not rename one without the other. - `allowed_extensions` must match `extension/manifest.json`'s `browser_specific_settings.gecko.id` exactly (`velox@velox.download`). A mismatch here is a silent failure: Firefox reports "no such native application" as if the manifest didn't exist at all, which reads exactly like a missing-file bug and is easy to chase in the wrong place. - `path` is `/usr/libexec/velox/velox-nmhost` — the `.deb`'s install layout (`docs/07-packaging.md`). **Every other packaging format needs a different `path`** — the binary doesn't live at that absolute path inside a Flatpak sandbox or an AppImage mount, so whatever installs the manifest for those formats must rewrite this field to wherever it actually put the binary, not ship this file verbatim. That substitution is the packaging step's job, not this template's. ## Where it has to be written, and why Per ADR 0003 (spike S1, run against the real snap Firefox on the target machine — not a guess about how confinement "should" work): | Location | Covers | Why | |---|---|---| | `~/.mozilla/native-messaging-hosts/com.velox.host.json` | **deb/tarball Firefox, and snap Firefox** | The one location snap Firefox 154 actually reads. Firefox's snap launches native-messaging hosts *outside* the sandbox with the user's real `$HOME` — so this is not "the deb location that happens to also work"; it is *the* snap location, full stop. `~/snap/firefox/common/.mozilla/native-messaging-hosts/` (the intuitive "inside the snap" path) is **not** read by Firefox 154 snap — confirmed empirically, not inferred. | | `/usr/lib/mozilla/native-messaging-hosts/com.velox.host.json` | **deb/tarball Firefox only** | System-wide, so it covers every user on the box for a real (non-snap) Firefox install — but confirmed **not** read by snap Firefox. Do not treat this path as "covers snap too"; that was the wrong assumption `docs/05` §4 corrected in the same commit as the ADR. | | `~/.var/app/org.mozilla.firefox/.mozilla/native-messaging-hosts/com.velox.host.json` | **Flatpak Firefox** | Flatpak's own sandboxed home. Untested on this machine (Firefox here is the snap, not flatpak) — carried over from `docs/05` §4's original four-location list, which this table otherwise supersedes. Verify before relying on it in a release checklist. | That is three real locations, not four — the fourth (`~/snap/firefox/common/.mozilla/native-messaging-hosts/`) was the pre-ADR guess the spike disproved. If `docs/agents/AGENT-DAEMON.md`'s build order still says "four locations" when you read this, it is stale; this table is the current source of truth alongside the ADR itself. ## What this means for `postinst` (PKG/QA's file, not this one) This directory ships the manifest template and documents the target paths; it does not install anything itself (`packaging/**` outside this one directory is PKG/QA's — see `CLAUDE.md`'s lane table — and `postinst` specifically is a `.deb`-packaging concern this lane doesn't own the file for). For whoever writes it: - **The two `~/`-relative locations are per-user.** `postinst` runs as root, once, at install time — it does not run once per user session. It needs either a real-user enumeration at install time (every UID with a home directory and no login shell of `/usr/sbin/nologin`-style exclusions, roughly what `deluser --remove-home` scripts already have to reason about) or a first-run hook that runs as the logged-in user (a systemd user unit's `ExecStartPre`, or the GUI's own first-run wizard) and writes its own manifest the first time it starts. `docs/adr/0003`'s own follow-up section flagged this as open; it still is. - **`/usr/lib/mozilla/native-messaging-hosts/` is the only one of the three that's a plain root-owned, install-time write** — no per-user enumeration needed for that one. - **Detect snap Firefox and say so.** `docs/07-packaging.md` already commits to this ("detects whether Firefox is a snap... prints... a one-line note that the extension will pair over loopback") — the detection matters here specifically because if Firefox turns out to be neither deb/tarball nor a snap this spike covers (a genuinely unknown or future packaging of Firefox), silently trusting `NativeTransport` to work is exactly the failure mode ADR 0003 exists to prevent. `WebSocketTransport` is the guaranteed fallback either way (ADR 0003's own decision) — nothing breaks if the manifest doesn't land correctly, it just means the extension pairs over loopback instead of the (opportunistic, not required) native path. - **`docs/07-packaging.md`'s own install layout line currently lists only the system-wide `/usr/lib/mozilla/...` path.** That line is correct as far as it goes (it *is* one of the three locations, and the only pure root-owned one) but reads as if it were the whole story for native messaging; it predates this file and the ADR. Worth a line pointing here so the two documents don't quietly disagree — PKG/QA's call, not edited here since `docs/07` is PKG/QA's own file. ## The binary `nmhost/` builds `velox-nmhost` — see that directory's own `src/main.cpp` for what it does (a byte-level pump, no protocol logic) and `docs/05-extension-spec.md` §4 for the two transports it sits behind. It is deliberately dependency-free (not linked against any `veloxd_*` library) so wherever a packaging format's sandbox puts it, it has nothing else to go looking for at runtime.