Install
# Install from a checkout
Prerequisites: Python 3.11+, pipx and age on PATH. The optional commit hook also
requires gitleaks 8.30.1 (built-in rules). No Python runtime dependencies for the CLI.
From the repository root, one command installs it:
pipx install .
For a Python-only isolated installation, from the checkout:
python3 -m venv tools/cli && tools/cli/bin/python -m pip install --no-deps .
The pipx command is tested using a clean home, cache and venv under tools/.
Use `envvault --help` after installation. Offline operation requires no API access.
## First encrypted file
umask 077
age-keygen -o team.key
age-keygen -y team.key > team.pub
envvault init --recipient "$(cat team.pub)" --owner platform
envvault encrypt .env -o app.age
envvault run -i team.key app.age -- python app.py
Never commit team.key or plaintext .env files. Share only app.age and public keys.
The config holds names and rotation metadata: review whether those names are sensitive.
## Commands
envvault add-recipient age1PUBLIC_RECIPIENT
envvault rotate app.age -i team.key --recipient age1RETAINED_RECIPIENT --days 90
envvault decrypt app.age -i team.key -o recovered.env
envvault diff staging.age production.age -i team.key
envvault inventory app.age -i team.key
envvault hook-install
`decrypt` requires an explicit, new output path and writes mode 0600. `run` writes
no plaintext file; the child still has access to values and can print them.
`diff` compares names only and cannot tell whether shared names have different values.
`add-recipient` affects future encryptions; rotate each existing ciphertext to apply it.
`rotate` re-encrypts to exactly the supplied recipients, replacing the ciphertext.
It preserves upstream credential dates. Old ciphertext can still be decrypted by old keys.
After rotating a credential at its provider, send the replacement on stdin:
envvault rotate app.age -i team.key --variable DATABASE_URL --owner platform --days 90
Supply the replacement through a secure pipe, not argv or shell history. The command
reads stdin to EOF. This records today's date for that variable. Reminder dates appear
in `inventory`; schedule that command in your own runner. New variables have unknown
rotation dates and are flagged until an actual upstream rotation is recorded.
The inventory also includes recipient_rotation with a due date after re-encryption.
Check both recipient_rotation.past_due and variables[].past_due in reminder jobs.
If your Git uses centrally managed hooks, hook-install refuses to replace the existing
hook. Ask the hook administrator to invoke `envvault check-staged` from the managed hook;
do not disable organization checks or override its global hooksPath.