Skip to content

Quick start

This walks you from an empty machine to a secret that your tools can use but never see. It assumes you’ve installed kovra.

Every command box has an OS selector in its header. Choose macOS or Windows once and every box on the page follows — your choice is remembered next time. macOS on Apple Silicon is the reference platform; Windows is on the roadmap, so its boxes preview the intended experience.

zsh
~/my-app % kovra init
Initialized vault at ~/.vaults (OS keyring).

This creates the vault registry and a per-vault master key, custodied in the OS keychain (the macOS Keychain or Windows Credential Manager). The master key encrypts every entry at rest; you never handle it directly.

Secrets are addressed by a coordinate of the form secret:<env>/<component>/<key>. kovra reads the value from a hidden prompt — it never appears in argv or your shell history:

zsh
~/my-app % kovra add secret:dev/db/password
Added dev/db/password (Medium).

(Scripting? Pipe the value in with kovra add secret:dev/db/password --stdin.) With no --sensitivity flag a secret is born medium; you can set a tier and a description explicitly:

zsh
~/my-app % kovra add secret:dev/app/api-key --description "App API key"
Added dev/app/api-key (Medium).

List what’s stored — metadata only, never values:

zsh
~/my-app % kovra list
┌────────┬─────────────────┬─────────────┬─────────┬─────────────┐
│ ORIGIN ┆ COORDINATE ┆ SENSITIVITY ┆ MODE ┆ FINGERPRINT │
╞════════╪═════════════════╪═════════════╪═════════╪═════════════╡
│ global ┆ dev/app/api-key ┆ medium ┆ literal ┆ c8a476b5 │
├╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ global ┆ dev/db/password ┆ medium ┆ literal ┆ 73c128b4 │
└────────┴─────────────────┴─────────────┴─────────┴─────────────┘

The fingerprint is a short, truncated hash — enough to confirm “same value as before”, never enough to reconstruct it. Filter with kovra list --env dev or --component app.

If you ever need a value back at a terminal, kovra show reveals exactly one coordinate. An ordinary secret prints straight away:

zsh
~/my-app % kovra show secret:dev/db/password
(revealing dev/db/password to stdout — ephemeral, not stored)
dev-db-pw-•••••

A high or prod secret first asks for a bioProve (Touch ID on macOS, Windows Hello on Windows); see step 3. The most protected secrets (inject-only) are never revealed at all — they can only be injected.

Tools shouldn’t read the vault directly — they get values through injection. You describe the mapping once in a committable .env.refs file that holds addresses, not values:

#.env.refs — safe to commit; contains no secret values.
project = my-app
# Vault-backed, parameterized by --env (${ENV} is substituted at run time).
DATABASE_URL=secret:${ENV}/db/password
API_KEY=secret:${ENV}/app/api-key
# Passthrough from the environment, with a fallback if unset.
LOG_LEVEL=${env:LOG_LEVEL | info}
# A plain literal (not a secret).
PORT=8080

Then run any command with the resolved values injected straight into the child process — nothing is written to disk, argv, or shell history:

zsh
~/my-app % kovra run --env dev -- your-app
app started · DATABASE_URL=14 chars · API_KEY set=yes · PORT=8080

With --env dev, ${ENV} resolves to dev, so DATABASE_URL is read from secret:dev/db/password. The values land in your app’s environment and nowhere else.

Switch the environment to prod and the same command is held to a higher bar — a prod secret is born high, and a high/prod injection is governed by two independent guards: it must target an allowlisted executable, and it pauses for an bioProve. Run it against an un-reviewed program and kovra refuses, by design:

zsh
~/my-app % kovra run --env prod -- your-app
Error: `your-app` is not on the executor allowlist; high/prod injection refused

Allowlist the reviewed executable with --allow and bioProve (one confirmation covers every secret in the run):

zsh
~/my-app % kovra run --env prod --allow./deploy --./deploy
# Touch ID prompt — approve to inject prod/db/password, prod/app/api-key
deploying with DATABASE_URL=12 chars, API_KEY set=yes

Not sure what your repo needs? Let kovra propose an .env.refs by scanning your source for env-var references (it reads variable names only — never a value):

zsh
~/my-app % kovra scaffold --out .env.refs
Wrote 2 proposed coordinate(s) to .env.refs — review before use.

Onboard the current repo so an AI agent can use your secrets without seeing the sensitive ones:

zsh
~/my-app % kovra setup
Vault ready; project `my-app`.
Updated .mcp.json (register the kovra MCP server).
Updated CLAUDE.md (insert/update the kovra conventions block).
Setup complete. Review CLAUDE.md and .mcp.json, then reload your agent to pick up the MCP server.

This registers the kovra MCP server in ./.mcp.json and adds a conventions block to ./CLAUDE.md. From then on, Claude Code sees scoped metadata — that a secret exists, its sensitivity, its coordinate — and can run commands through the wrapper, but the plaintext of your high / prod / inject-only secrets never enters the model’s context.

Preview the changes without writing anything with kovra setup --dry-run.

You now have the full loop: store → inject → delegate to an agent, with the sensitive plaintext never leaving the vault. From here:

  • Overview — the concepts map: coordinates, sensitivity tiers, agent scope, and the .env.refs contract.
  • How it works — the everyday flows end to end, at a high level.
  • Secrets in the age of AI Agents — kovra’s whitepaper: the problem, the tensions, the solution, and an honest account of kovra’s risks and limitations.