ohd is the Open Headers Server control binary: it writes the service
unit, drives the service manager, and runs the offline admin verbs
against the daemon’s data directory. Configuration persists in
daemon.json — see the configuration reference.
The client command line is oh.
Commands
| Command | What it does |
|---|---|
ohd install | Write the user service unit (launchd/systemd) and persist the given config flags into daemon.json — the config file every ohd command and the daemon itself read; re-run with new flags to reconfigure (then apply with: ohd restart) |
ohd start | Start the installed service |
ohd stop | Stop the installed service |
ohd restart | Restart the installed service — how a changed configuration (or a swapped binary) takes effect; start is a no-op while the service runs |
ohd run | Run the daemon in the foreground (what the service unit execs; Ctrl-C / SIGTERM shuts it down cleanly) |
ohd status | Probe the daemon’s /healthz; --verbose reads /metrics (peers, throughput, audit counts — needs a paired token via --token or OH_DAEMON_TOKEN); also notes when a newer ohd release is available |
ohd upgrade | Download and install the newest release of this binary, then restart the installed service into it (skip the restart with --no-restart); unattended upgrades are the opt-in updates.autoUpdate setting |
ohd show-token | Mint a client auth token against the daemon’s data dir (first-boot bootstrap; requires the daemon to be stopped) |
ohd config set <key> <true|false> | Set a daemon setting offline (requires the daemon to be stopped) — settings only; bind and network options persist through the install flags instead |
ohd config get <key> | — |
ohd config list | Read daemon settings |
ohd user add <name> [--email <address>] [--individual-license <key>] | Admit a user to the daemon’s directory (requires the daemon to be stopped; the daemon must have booted once); at the seat limit an individual-seat key matching --email admits past it |
ohd user list | Read the user directory (grants included) |
ohd user deactivate <id-or-email> | Deactivate a user + revoke their tokens (daemon stopped) |
ohd user grant <id-or-email> <workspaceId> <owner|editor|viewer> | Grant a workspace role (daemon stopped; editors write, viewers read, no grant = no access) |
ohd user revoke-grant <id-or-email> <workspaceId> | Drop a user’s grant on one workspace (daemon stopped) |
ohd user set-password <id-or-email> [--clear] | Set a user’s password for the local password login (daemon stopped; echo-off prompt on a terminal, or OH_DAEMON_USER_PASSWORD / OH_DAEMON_USER_PASSWORD_FILE for scripts — never a flag); --clear removes it |
ohd license status | Show the installed license (licensee, seats, expiry, grace) |
ohd license install <file> | Verify + install a license key file; a running daemon picks it up live — no restart |
ohd license remove | Remove the installed license (revert to the free tier; existing users and data are unaffected) |
ohd vault rotate | Re-encrypt the vault under a new passphrase (daemon stopped; current passphrase from OH_DAEMON_VAULT_PASSPHRASE or OH_DAEMON_VAULT_PASSPHRASE_FILE, new one from OH_DAEMON_VAULT_NEW_PASSPHRASE or OH_DAEMON_VAULT_NEW_PASSPHRASE_FILE — env/file only, never a flag) |
ohd audit list | Read the audit log, newest first (works while the daemon runs; default --limit 50) |
ohd audit export | Emit matching audit rows as JSONL, oldest first |
ohd backup [dest] | Snapshot the data dir’s state (storage.json, oracle.db, blobs/) into a fresh directory with a checksummed manifest (daemon stopped; dest defaults to ./openheaders-daemon-backup-<timestamp>) |
ohd restore <dir> | Verify a backup’s checksums and replace the data dir’s state with it (daemon stopped; refuses over existing state without --force) |
Settings keys
ohd config set <key> <true|false> — booleans, default off. Bind and
network options are not settings; they persist through ohd install
flags instead.
| Key | What it enables |
|---|---|
mcp.enabled | Serve the MCP surface at /mcp (everything below requires it). |
mcp.allowObserve | MCP read tools: list workspaces, rules, requests, variables, activity. |
mcp.allowWrite | MCP write tools: toggle rules, switch environments, set variables. |
mcp.allowExecute | MCP execute tools: send requests, run workflows (real network egress). |
mcp.allowSecrets | Let MCP tools read secret variable values instead of masked names. |
updates.autoUpdate | Unattended ohd upgrade when a newer release ships. |
Options
Accepted byinstall, status, show-token, and config (the
config flags are shared by every command that reads the data dir).
| Option | What it does |
|---|---|
--config <path> | daemon.json location |
--data-dir <path> | Data directory (storage.json, oracle.db, blobs/) |
--bind-address <addr> | 127.0.0.1 (loopback) or 0.0.0.0 (LAN) |
--bind-port <port> | Sync/HTTP port (default 8137) |
--log-level <level> | error | warn | info | debug (default info) |
--trusted-proxy | A reverse proxy fronts the daemon; take the peer address from X-Forwarded-For (never set without one) |
--allowed-host <name> | Hostname the daemon answers as (repeatable) — e.g. the reverse proxy’s domain; IPs/localhost always work |
--allow-insecure-lan | Accept serving cleartext HTTP/WS on 0.0.0.0 without a TLS proxy (tokens ride unencrypted; trusted LANs only) |
--no-trusted-proxy | install only: clear a --trusted-proxy persisted by an earlier install |
--no-allow-insecure-lan | install only: clear an --allow-insecure-lan persisted by an earlier install |
--web-root <path> | Directory with the built web app to serve at / (default: the web/ dir shipped beside the daemon) |
--proxy-mode <mode> | How the daemon’s own egress reaches the network: env (default — honor HTTP_PROXY / HTTPS_PROXY / NO_PROXY, curl precedence), manual, or off |
--proxy-url <value> | manual mode: the proxy to traverse (host:port implies http://) |
--proxy-credential-ref <name> | manual mode: vault entry holding user:password for the proxy (never the value itself) |
--proxy-bypass <list> | manual mode: NO_PROXY-syntax bypass list (host suffixes, host:port, IPv4 CIDR, *) |
--verbose | status only: read the token-gated /metrics route |
--token <secret> | status only: paired token for /metrics (or set the OH_DAEMON_TOKEN environment variable) |
--label <text> | show-token only: label for the minted token |
--user <id-or-email> | show-token only: bind the token to a directory user (omit for a token that acts as the daemon operator) |
--email <address> | user add only: contact identity for the new user |
--individual-license <key> | user add only: individual-seat key redeemed when the daemon is at its seat limit (must match --email) |
--clear | user set-password only: remove the password |
--force | restore only: replace existing state files in the data dir |
Audit filter options
Accepted byaudit list and audit export.
| Option | What it does |
|---|---|
--actor <id-or-email> | Only rows for one directory user |
--capability <name> | e.g. workspace.write, daemon.admin |
--decision <allow|deny> | Only allows or only denies |
--workspace <id> | Only rows scoped to one workspace |
--since <when> | ISO date/time or relative (30m, 24h, 7d) |
--until <when> | Upper bound, same forms (exclusive) |
--limit <n> | Row cap (list defaults to 50; export unbounded) |
See also
- Environment variables — every
OH_*variable the daemon side reads. - Install & service lifecycle — the commands in context.
- Troubleshooting — the error messages, verbatim.