ov agent
import { Aside } from ‘@astrojs/starlight/components’;
ov agent is a long-running daemon that holds your KEK in memory after a one-time authentication, then serves secret injection requests over a Unix socket. It has two clients today: the MCP bridge (ov mcp serve connects to the agent for all crypto operations) and ov run, which dials the same socket to run commands with per-request secrets and zero password prompts once the agent is unlocked (see ov run for the full agent-first flow, its divergences from the local path, and the Ctrl-C caveat). If the agent isn’t running when a client starts (or, for ov run, isn’t reachable at all), MCP tool calls fail with a plain-text ov agent is not running error while ov run silently falls back to its own password prompt / --machine-key path; if a running agent’s session locks or expires, both clients see SESSION_LOCKED (see Troubleshooting for both, including when the MCP client needs a restart).
On a workstation, ov agent start with no flags prompts for your master password once and keeps the session unlocked — it runs in the foreground, so keep the terminal open. On Linux servers and CI runners, pair it with a machine key so ov run needs no prompt. Note that the MCP bridge can only authenticate to an interactively started agent today — a machine-key agent derives its socket key from the KEK and writes no key file for the bridge to read.
How it works
Section titled “How it works”ov agent start --machine-key /etc/ov/machine.kek ↓daemon starts, loads KEK, listens on Unix socket ↓ov run --machine-key /etc/ov/machine.kek --secrets DATABASE_URL -- ./migrate ↓run finds the socket automatically, sends a signed request →agent decrypts → subprocess runs on the daemon sideThe agent authenticates requests via HMAC-SHA256 derived from the machine key. Only a client that holds the same machine key can send valid requests. The socket itself is protected by 0700 directory + 0600 permissions.
Plaintext secret values never cross the socket — the agent runs the subprocess itself and returns only the exit code.
Each request declares its own (app, env) pair and the daemon resolves it per request (with a short-lived cache); --app/--env are only the defaults for requests that don’t declare one. If a request names an environment that doesn’t exist in its app, the daemon refuses with the ENV_NOT_FOUND wire code. The startup pair is validated once at start and is not re-validated per request.
Version gate for ov run: the daemon reports a version string (currently ov-agent/2) on ov agent status. ov run checks this before dispatching a request — it requires at least ov-agent/2 (the version where per-request env routing shipped) and falls back to its local password-prompt path against anything older, rather than risk silently sending a per-request env to a daemon that would ignore it and serve its startup env instead. Restart the agent after upgrading ov to pick up the new version.
Prerequisites
Section titled “Prerequisites”A machine key file is required to start the agent:
ov auth derive-machine-key --out /etc/ov/machine.kekchmod 600 /etc/ov/machine.kekSee Machine key setup for details.
Commands
Section titled “Commands”| Command | Description |
|---|---|
ov agent start | Start the agent daemon |
ov agent stop | Stop the running agent |
ov agent status | Show agent status |
ov agent install | Install a systemd unit file |
ov agent start
Section titled “ov agent start”ov agent start --machine-key /etc/ov/machine.kek --app my-saasStarts the daemon in the foreground. Use --foreground with systemd Type=simple.
| Flag | Description |
|---|---|
--machine-key PATH | Path to machine key file (required for HMAC socket auth) |
--app NAME | Default app slug for all secret ops; clients may override per request — as of v0.12.0 (OV-319) every MCP tool (not just vault_run) sends its own resolved app per call |
--env NAME | Default environment slug for all secret ops; clients may override per request (resolved via flags → .ov.yaml → config → production) — as of v0.12.0 (OV-319) every MCP tool sends its own resolved env per call, including the three write tools, which additionally require declared expected_app/expected_env under OV_STRICT_CONTEXT (default on) |
--socket PATH | Unix socket path (default: $XDG_RUNTIME_DIR/ov-agent/ov-agent.sock) |
--pid-file PATH | Path to write PID file |
--foreground | Run in foreground (required for systemd Type=simple) |
ov agent stop
Section titled “ov agent stop”ov agent stopov agent stop --pid-file /run/ov-agent/ov-agent.pidSends SIGTERM to the agent and returns immediately. SIGTERM cancels the daemon’s own context, which propagates into any in-flight subprocess and kills it abruptly — the daemon does not wait for running commands to finish before exiting. To kill a single orphaned command while keeping the daemon (and its unlocked session) alive, see the Ctrl-C caution in ov run.
ov agent status
Section titled “ov agent status”ov agent statusov agent status --machine-key /etc/ov/machine.kekQueries the agent socket and prints uptime and version. If the socket is unreachable, falls back to checking the PID file.
Pass --machine-key if the agent was started with one — without it, the signed request will be rejected and status falls back to the PID file check.
ov agent install
Section titled “ov agent install”ov agent install --machine-key /etc/ov/machine.kek --app my-saas --env productionov agent install --machine-key /etc/ov/machine.kek --app my-saas --env production --enableWrites a systemd unit file and prints the commands to enable and start it. Pass --enable to run systemctl daemon-reload && systemctl enable --now ov-agent automatically.
--app and --env are required — they are routing flags baked into the unit’s ExecStart so the agent isn’t coupled to the service account’s config-file state. They do not scope the key.
| Flag | Description |
|---|---|
--machine-key PATH | Path to machine key file (required) |
--app SLUG | App slug baked into the unit’s ExecStart (required) |
--env SLUG | Env slug baked into the unit’s ExecStart (required) |
--socket PATH | Unix socket path |
--unit-name NAME | systemd unit name (default: ov-agent) |
--user NAME | systemd User= field (default: $SUDO_USER if present, else current user; cannot be root) |
--enable | Run systemctl to enable and start immediately |
systemd setup
Section titled “systemd setup”The recommended production setup:
# 1. Create the machine keyov auth derive-machine-key --out /etc/ov/machine.kekchmod 600 /etc/ov/machine.kek
# 2. Install the systemd unitov agent install \ --machine-key /etc/ov/machine.kek \ --app my-saas --env production \ --enableThe generated unit file uses Type=simple and restarts on failure. It runs as the current user.
Security model
Section titled “Security model”- Socket directory:
0700(only the owning user can access it) - Socket file:
0600 - HMAC-SHA256 per-request authentication when started with
--machine-key - Replay window: ±30 seconds (timestamp-based; no stateful nonce store)
- Plaintext values never cross the socket — the agent injects them directly into subprocess environments
- Per-request
(app, env)routing: the daemon serves the environment each request declares, never silently substituting the start-time default; a request naming a nonexistent environment fails closed withENV_NOT_FOUND. Environment selection is routing, not authorization — every env is reachable with the one unlocked key (an operator env allowlist is tracked as OV-320)
Known limitations:
- No server-side nonce store: a captured signed request can be replayed within the 30-second validity window
- Interactive sessions (no
--machine-key) have no socket authentication beyond filesystem permissions
Related
Section titled “Related”- Machine key setup — generating and managing machine keys
- ov run — uses a running agent automatically (zero prompts); falls back to its own no-daemon path when one isn’t reachable
- CI/CD integration — using OpaqueVault in automated pipelines