Skip to contentMenu Download OpenVireo

Read, inject and rotate OpenVireo vault secrets from scripts, CI and servers, with a service account (OPENVIREO_SERVICE_ACCOUNT_TOKEN=ov_sa_…) or your own login. Vaults are downloaded and decrypted locally; writes use the same conditional PUT and merge/retry loop as Qt and the web app, so concurrent edits are merged, not lost. Runs on Node ≥ 20, or as one binary (Bun --compile, no Node needed).

Install

Install @openvireo/cli from GitHub Packages (see Install) and run it with Node ≥ 20:

npm install -g @openvireo/cli
ov version

Prebuilt single binaries aren’t published yet; build one to run ov without Node.

References

ov://<vault>/[<group>/…]<entry>/<field>

<vault> is a vault id or name, <entry> an entry UUID (32 hex digits) or a unique title, with the group path from the root group. Segments are percent-encoded (Team%20Infra). Fields are KeePass’s (username, password, url, notes, title, any case) or custom field names. Item commands take the reference without the field.

Commands

export OPENVIREO_SERVICE_ACCOUNT_TOKEN=ov_sa_…

ov read ov://Team%20Infra/GitHub/password                 # value + newline (-n: none, -o file: mode 0600)

# templates: bare references, or {{ ov://… }} when text follows the reference
echo 'dsn: postgres://app:{{ ov://Team%20Infra/Deploy/Database/password }}@db/app' | ov inject
ov inject -i config.yml.tpl -o config.yml                  # output file mode 0600

# run a command with references resolved in its environment; its stdout/stderr are masked
cat .env.tpl
#   DB_PASSWORD=ov://Team%20Infra/Deploy/Database/password
#   DB_USER="ov://Team%20Infra/Deploy/Database/username"
ov run --env-file .env.tpl -- ./migrate.sh                 # "echo $DB_PASSWORD" prints <concealed by openvireo>
GH_TOKEN=ov://Team%20Infra/GitHub/password ov run -- gh auth status   # variables already set work too

ov item get ov://Team%20Infra/GitHub [--reveal] [--json]
ov item list "Team Infra"
ov item create ov://Team%20Infra/Apps/Stripe username=billing url=https://stripe.com --generate
ov item edit ov://Team%20Infra/Apps/Stripe --stdin-field api_key < key.txt
ov rotate ov://Team%20Infra/Deploy/Database/password --generate [--length 40] [--charset letters,digits] [--print]
printf %s "$NEW" | ov rotate ov://Team%20Infra/CI/token --stdin

ov vault list
ov whoami
ov connect                                                # the REST server, see connect.md
  • ov run takes KEY=value lines (export, # comments, "…" with \n escapes, '…' literal). Masking replaces every resolved value, and every line (4+ characters) of a multi-line value, in the child’s output, also when a value is split across writes. Bytes that may be the start of a secret are held back until the next write, or for at most 100 ms. Masking pipes the child’s stdout/stderr (they are not TTYs); --no-masking gives it the terminal directly. The child never receives OPENVIREO_SERVICE_ACCOUNT_TOKEN, OPENVIREO_PASSWORD or OPENVIREO_SECRET_KEY. The exit code is the child’s.
  • item create fails if the entry exists; item edit fails if it doesn’t. Password and custom fields are stored protected. Every edit keeps the previous version in the entry’s history.
  • --generate makes 32 characters from letters, digits and !#$%&()*+,-./:;<=>?@[]^_{|}~, at least one of each chosen set (--charset takes letters, lower, upper, digits, symbols).
  • A vault granted as read refuses rotate and item create|edit before anything is uploaded: ov: this service account can only read vault "Team Infra", exit code 1. The sync server enforces the same with 403.
  • Errors print ov: <message> with exit code 1 (2 for usage errors), never a stack trace.

Human login

ov login --email [email protected] [--issuer https://accounts.openvireo.com]
# Master password, then the Secret Key (K1-…) the first time on this machine, then a TOTP code if enabled
ov read ov://Private/Bank/password                       # asks for the master password every time
ov logout

The session (refresh token, device id, trusted Secret Key and the encrypted vault base copies) lives in $OPENVIREO_CONFIG_DIR, else $XDG_CONFIG_HOME/openvireo, else ~/.config/openvireo, in session.json with mode 0600. The master password is never stored. OPENVIREO_PASSWORD, OPENVIREO_SECRET_KEY and OPENVIREO_ISSUER are read from the environment for non-interactive use; prefer a service account for automation. OPENVIREO_SERVICE_ACCOUNT_TOKEN (or OPENVIREO_SERVICE_ACCOUNT_TOKEN_FILE) always takes precedence over a login.

Single binary

npm run build:binary -w @openvireo/cli     # builds the SDK and connect, then bun build --compile … src/bin.ts --outfile dist/ov
./packages/cli/dist/ov version             # ov 0.2.0
npm run smoke -w @openvireo/cli            # runs dist/ov against the in-memory servers over HTTP
# cross-compile: add --target=bun-linux-x64 | bun-linux-arm64 | bun-darwin-arm64 | bun-windows-x64

The binary is ~60 MB (the Bun runtime) and includes the SDK’s OPAQUE WASM module, so login works without Node. npm run build also produces dist/bin.js for Node ≥ 20 (node dist/bin.js).

The SDK docs cover OpenVireo SDK, develop (86e6cd2), last updated 26 October 2026. Found a mistake? Edit this page on GitHub.