Skip to content

How-To Guides

Quick solutions for common tasks. Each section is a self-contained guide.


dotsecenv works seamlessly alongside .env files. Use .env for non-sensitive config and .secenv for secrets.

Terminal window
# .env: non-sensitive configuration
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=myapp
LOG_LEVEL=debug
# .secenv: encrypted secrets from vault
DATABASE_PASSWORD={dotsecenv}
API_KEY={dotsecenv/prod::API_KEY}

With the shell plugin installed, both files load automatically when you cd into the directory:

  1. .env loads first (plain values)
  2. .secenv loads second (decrypted secrets)

Variables from .secenv can override .env if names match.


See the Migrate from .env tutorial. It walks the full sequence: identify which values are secret, store each in the vault, write a .secenv file, drop the plaintext .env, and commit only the encrypted vault.


Build a .secenv from the secrets already in your vault instead of writing it by hand.

Terminal window
dotsecenv init secenv

Opens one tab per vault. Use / to switch tabs, / to move, space to select, and enter to reach the Apply tab and confirm.

Terminal window
dotsecenv init secenv --all

Adds every reference not already present. Use -v to restrict to one vault:

Terminal window
dotsecenv init secenv -v 2 --all

It writes references, never values, and leaves existing keys untouched. See init secenv for the full key map.


Store a new encrypted secret in your vault.

Terminal window
echo "my-secret-value" | dotsecenv secret store SECRET_NAME
Terminal window
dotsecenv secret store SECRET_NAME
# Type or paste the value
# Press Ctrl+D when done
Terminal window
cat ~/.ssh/private_key | dotsecenv secret store SSH_PRIVATE_KEY
Terminal window
echo "prod-password" | dotsecenv secret store prod::DATABASE_PASSWORD
echo "dev-password" | dotsecenv secret store dev::DATABASE_PASSWORD
Terminal window
echo "value" | dotsecenv secret store -v ./project/vault PROJECT_SECRET

Get a decrypted secret value.

Terminal window
dotsecenv secret get DATABASE_PASSWORD
# Output: my-secret-value
Terminal window
dotsecenv secret get DATABASE_PASSWORD --json
# {"added_at":"2026-04-12T10:22:01Z","value":"my-secret-value","vault":"~/.config/dotsecenv/vault"}
Terminal window
dotsecenv secret get DATABASE_PASSWORD --all
# Lists all historical values

--all with --json additionally returns available_to and signed_by per version, which is the supported audit interface — see Audit Trail.

Terminal window
dotsecenv secret get DATABASE_PASSWORD --all --json
# [
# {
# "added_at": "2026-04-12T10:22:01Z",
# "value": "my-secret-value",
# "vault": "~/.config/dotsecenv/vault",
# "available_to": ["ALICE_FP", "BOB_FP"],
# "signed_by": "ALICE_FP"
# }
# ]
Terminal window
dotsecenv secret get DATABASE_PASSWORD --last
Terminal window
dotsecenv secret get -v 2 DATABASE_PASSWORD # Vault index (1-based)
dotsecenv secret get -v ./path/to/vault DATABASE_PASSWORD

See the Share a Secret tutorial. The short form is dotsecenv secret share NAME THEIR_FINGERPRINT --all; the tutorial covers the public-key exchange, the access-list semantics, and the team-onboarding follow-up. To share every secret with a new teammate in one pass, use the wildcard form: dotsecenv secret share "*" THEIR_FINGERPRINT --all.


See the Revoke Access tutorial for the full sequence including the rotate-after-revoke caveat (the revoked recipient can still decrypt the previous value; rotating at the source is what neutralizes it). The short form is dotsecenv secret revoke NAME THEIR_FINGERPRINT --all. To strip a leaving teammate’s key entirely from every vault, see the Offboard a Departing Team Member runbook.


Query who could decrypt a secret, who signed each version, and when each change happened.

Terminal window
# Current authorization snapshot per secret
dotsecenv vault describe --json
# Full version history with signed_by and available_to per value
dotsecenv secret get DATABASE_PASSWORD --all --json
# Real-world authorship and commit timeline
git log -p -- path/to/vault

For example queries (filter by signer, diff access changes, query past commits) and a discussion of what append-only can and cannot prove, see Audit Trail.


See the dedicated runbook: Rotate a Compromised GPG Key. It covers the full revoke → share → rotate-at-source → verify sequence and the append-only caveats.

For a planned departure rather than a key compromise, see Offboard a Departing Team Member instead.


Check for issues with your config and vault files.

Terminal window
dotsecenv validate

Output:

✓ Config file: valid
✓ Vault header: valid
✓ Identity entries: 2 valid
✓ Secret entries: 5 valid
✓ All signatures verified
Terminal window
dotsecenv validate --fix

This can fix:

  • Regenerate corrupted header indexes
  • Remove orphaned entries
  • Update outdated format versions
Terminal window
dotsecenv validate -v ./project/vault

View identities and secrets in your vaults.

Terminal window
dotsecenv vault describe

Output:

Vault 1 (~/.config/dotsecenv/vault):
Identities:
- Alice <alice@example.com> (E60A1740...)
- Bob <bob@example.com> (ABC12345...)
Secrets:
- DATABASE_PASSWORD
- API_KEY
- prod::API_KEY
Terminal window
dotsecenv vault describe --json
Terminal window
dotsecenv vault describe | grep "prod::"

Work with secrets from different vaults.

~/.config/dotsecenv/config
vault:
- name: personal
path: ~/.config/dotsecenv/vault
- name: work
path: ~/work/secrets/vault
Terminal window
dotsecenv secret get -v personal DATABASE_PASSWORD
dotsecenv secret get -v work CORP_API_KEY
Terminal window
dotsecenv secret get -v 1 DATABASE_PASSWORD # personal (1-based)
dotsecenv secret get -v 2 CORP_API_KEY # work

Enable tab completion for dotsecenv commands.

Terminal window
# Add to ~/.bashrc
eval "$(dotsecenv completion bash)"
# Or install system-wide
dotsecenv completion bash | sudo tee /etc/bash_completion.d/dotsecenv

Reload your shell to activate:

Terminal window
source ~/.bashrc # or ~/.zshrc

Export all secrets for a shell session or script.

Terminal window
curl -fsSL https://raw.githubusercontent.com/dotsecenv/plugin/main/install.sh | bash
/path/to/directory/.secenv
# the secret(s) will be auto-loaded on cd
cd /path/to/directory
# and your app can use them
./my-app
Terminal window
export DATABASE_PASSWORD=$(dotsecenv secret get DATABASE_PASSWORD)
export API_KEY=$(dotsecenv secret get API_KEY)

Run health checks on vaults and the GPG environment, and fix any issues.

Terminal window
dotsecenv vault doctor

Output:

Health checks:
[✓] gpg-agent is available
[✓] ~/.config/dotsecenv/vault: format v2 (latest)
[✓] ~/.config/dotsecenv/vault: 0.0% fragmentation
Status: healthy
All vaults are up to date.

The doctor command performs these checks:

  • GPG agent availability: verifies that gpg-agent is running
  • Vault format version: checks whether vaults need upgrading
  • Vault fragmentation: checks whether defragmentation is needed

After displaying health check results, doctor offers to fix any issues found (upgrade outdated vaults, defragment fragmented vaults).

Use --fix to automatically apply all fixes without interactive confirmation:

Terminal window
dotsecenv vault doctor --fix

This is useful in scripts or when you already know fixes are safe to apply.

Terminal window
dotsecenv vault doctor --json

See the CI/CD Secrets tutorial for the end-to-end first-time setup (CI-only identity creation, sealed-secret import, vault decryption, masked-env injection). For the published dotsecenv/dotsecenv GitHub Action’s inputs, outputs, and provenance verification, see the GitHub Action guide. For running multiple environments side-by-side in one workflow, see Multi-environment Vaults.


ProblemSolution
”Not logged in”dotsecenv login FINGERPRINT
”Secret not found”Check vault: dotsecenv vault describe
”Cannot decrypt”Verify you’re in available_to
”GPG error”Check key: gpg --list-secret-keys
”Config not found”Run: dotsecenv init config
”Vault not found”Run: dotsecenv init vault
”Permission denied” on vaultCheck file permissions: ls -la /path/to/vault
Config error running as rootUse: sudo dotsecenv init config
Vault path not in configAdd path to config or use restrict_to_configured_vaults: false