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 runtakesKEY=valuelines (export,#comments,"…"with\nescapes,'…'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-maskinggives it the terminal directly. The child never receivesOPENVIREO_SERVICE_ACCOUNT_TOKEN,OPENVIREO_PASSWORDorOPENVIREO_SECRET_KEY. The exit code is the child’s.item createfails if the entry exists;item editfails if it doesn’t. Password and custom fields are stored protected. Every edit keeps the previous version in the entry’s history.--generatemakes 32 characters from letters, digits and!#$%&()*+,-./:;<=>?@[]^_{|}~, at least one of each chosen set (--charsettakesletters,lower,upper,digits,symbols).- A vault granted as
readrefusesrotateanditem create|editbefore 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.