Wire transparency — every outbound call, byte for byte

Published: July 19, 2026

Outbound connections from the apps are limited to the documented OpenHeaders endpoints below, plus targets the operator configures themselves (IdP issuer for SSO, Git remotes, an audit/SIEM collector, and whatever requests the user’s own rules and workflows make). This document is the published specification of every phone-home payload; if a request is not listed here, the app does not make it. The app is fully functional with all of these unreachable or disabled — see the per-endpoint off switches.

The only usage data that ever leaves is the anonymous telemetry channel of section 4: a typed allowlist of feature-usage counts, structurally incapable of carrying URLs, headers, traffic, or identity, default-on for the desktop app, extension, and CLI with a one-switch opt-out, and hard-off for the daemon, the served web app, and the MCP server. The license system itself remains telemetry-free: license endpoints and telemetry never share identifiers, payloads, or deployments.

The browser extension’s only OpenHeaders-bound call is that telemetry channel (section 4); browser store distribution owns its updates.

1. License refresh

Self-serve subscription renewal. Node hosts only (desktop main process and the daemon — never the extension). The agent only ever delivers files: the response is verified offline against the compiled-in Ed25519 trust ring before anything persists; no online validation path exists.

{
  "licenseKey": "oh-license.<base64url payload>.<base64url signature>",
  "appVersion": "2026.7.10",
  "platform": "darwin"
}

2. Update check

Anonymous check, staging by default, and a restart that is never unprompted: an available update may download in the background (default on, one switch to off), but a running app is only ever restarted by an explicit “Update & Restart” click or a quit that happens anyway. The oh CLI additionally self-updates between invocations on self-managed binary installs (default on, oh autoupdate off to stop) — it swaps its own binary so the next run launches the new version, restarting nothing. Who checks: desktop packaged builds on macOS/Windows and Linux AppImage, the oh CLI (daily cached), and the ohd daemon only when you run ohd status or opt into its default-off unattended mode. Dev builds, deb/rpm installs, container images, and npm/brew installs make no update requests — their owning channel updates them.

3. Severity manifest

A small static severity manifest published to the update feed on each release — { latest, tag, severity, minimumSafeVersion } per app — so a security release can escalate loudly (red badge, entry banner). Severity is authored by a human before each release, never derived from anything about your install.

4. Anonymous telemetry

Anonymous usage counting — which features get used, nothing more. The event vocabulary is a typed allowlist compiled into the app: every payload property is a closed union, boolean, or number; free-form strings are banned by a guard test, so URLs, hostnames, header names or values, rule contents, request/response data, and file paths are inexpressible. The in-app inspector (Settings → General → View telemetry events) shows every event of the current session byte for byte, sent or suppressed.

{
  "schemaVersion": 2,
  "sessionId": "c0ffee00c0ffee00c0ffee00c0ffee00",
  "installId": "feedface00feedface00feedface0000",
  "sinceInstall": "2-7",
  "sentAt": 1760000000000,
  "events": [
    { "name": "first_run", "channel": "chrome-store" },
    { "name": "session_start", "host": "extension",
      "appVersion": { "year": 2026, "month": 7, "patch": 2 },
      "platform": "mac", "browser": "firefox", "locale": "en",
      "rules": "1-5", "workspaces": "0" },
    { "name": "feature_used", "feature": "workflow-editor" },
    { "name": "rule_created", "ruleType": "header" },
    { "name": "import_run", "source": "postman", "ok": true },
    { "name": "workflow_run", "ok": true },
    { "name": "error_beacon", "code": "ws-connect-failed" }
  ]
}

Everything else

Anything else leaving the process is operator-configured, not OpenHeaders-bound: the OIDC issuer you set, the Git remotes you sync, the SIEM collector you point audit streaming at, and the HTTP requests your own rules, sources, and workflows define.