Packaging & trust
Trust levels, developer mode, signing a .cxt, updates, and Add-to-Connect deep links.
Every catalog extension has a trust level, decided by its signature — and any inconsistency refuses to load rather than "degrading to dev".
Trust levels
| Level | Meaning |
|---|---|
| first-party | Signature verifies and the signer is the embedded ARW root key. Unlocks first-party-only surfaces (e.g. the worker substrate). |
| signed | Signature verifies under some other key. If the manifest pins a key, the signer must equal it. |
| dev | Unsigned. Loads only when Developer mode is on. |
Any inconsistency — bad signature, tampered / extra / missing file, a key pin that
doesn't match the signer — refuses to load entirely. Verification runs at catalog scan
and again on every per-profile load.
Developer mode (unsigned, iterate fast)
- Extensions → Developer mode (on).
- Load unpacked… → pick your folder (loaded in place; edits are live).
- Reload re-reads the manifest + assets and restarts the instance (grants kept). A broken manifest surfaces as a clear failure.
- Remove fully unloads it.
With Developer mode off, only signed packages load, and running dev instances are torn down.
Packaging: .cxt
A .cxt is a ZIP of a signed extension tree. The signature covers a canonical
file-hash manifest (content, not archive bytes), so one signature validates a dev folder
and a .cxt identically.
Signing CLI
# Generate an Ed25519 signing pair (keep the .pem out of the repo):
node scripts/connect-sign.cjs keygen ./key.pem
# (Re)sign a tree — run after ANY file change (a stale signature refuses to load):
node scripts/connect-sign.cjs sign ./com.example.hello ./key.pem
# Pack a signed tree into a .cxt:
node scripts/connect-sign.cjs pack ./com.example.hello ./hello.cxt ./key.pemInstall via Extensions → Install from file…, or over a deep link (below).
Updates
Declare both key (the pinned signer = update anchor) and updateUrl in the manifest.
The updateUrl returns a small JSON update manifest:
{ "id": "com.example.hello", "version": "1.1.0",
"package": "https://cdn.example.com/hello-1.1.0.cxt",
"sha256": "<hex sha-256 of the .cxt bytes>" }(or { "extensions": [ …that shape… ] } so one URL serves many ids). When a newer version
is advertised, the browser downloads the .cxt, checks its bytes against sha256, then
installs it through the signed-package gate — which enforces the same id signed by the
same key (no silent key rotation). Grants and stored data are preserved — an update
is not a reinstall. Users trigger this from Extensions → Check for updates.
Add to Connect (deep links)
A store's "Add to Connect" button opens:
connect://install?src=<https url to the .cxt>&sha256=<hex of its bytes>The desktop downloads, integrity-checks, and verifies the package into the catalog, then opens the manager so the user completes the per-profile install + consent. The desktop re-verifies every package on install — the store is only a distribution layer, never the trust root.