Secrets, but automatic.
Avar is a developer-first CLI that makes project secrets invisible, automatic, and shareable β without .env files, plaintext on disk, or a central server.
It does three things:
- Local encrypted vault β your secrets, encrypted at rest under your passphrase.
- Project-aware activation β
cdinto a project and the right secrets appear as environment variables. Leave and they disappear. - Multi-recipient bundles β commit an encrypted bundle to git; teammates with the right key decrypt it. No shared passphrase.
Clone a repo β open terminal β unlock once β secrets just work.
No plaintext on disk. No external service. No telemetry.
Two crypto layers at two storage levels:
| Layer | Format | Purpose |
|---|---|---|
| Vault (local) | AVR1 envelope: scrypt KDF + chacha20poly1305 AEAD |
Your local secret store, encrypted to your passphrase. |
| Bundle (team) | age multi-recipient envelope + Ed25519 signature |
Encrypted file in your repo. Each recipient unwraps with their own key; decrypt verifies the writer's signature. |
Trust is explicit. Untrusted projects and bundles fail loudly rather than silently leaking. Each user has their own X25519 + Ed25519 keypair, generated on first bundle command and encrypted at rest with the user's vault passphrase.
cargo install --git https://github.com/udaysinh-git/avarLatest commit on main. Requires Rust 1.85+ (edition 2024).
Tagged releases attach prebuilt binaries for Linux x86_64, macOS (Intel + Apple Silicon), and Windows x86_64. See the releases page.
# Linux / macOS β substitute TAG and TARGET for your release/platform.
TAG=v0.2.0
TARGET=x86_64-unknown-linux-gnu
curl -L "https://github.com/udaysinh-git/avar/releases/download/${TAG}/avar-${TAG}-${TARGET}.tar.gz" \
| tar xz
sudo mv avar /usr/local/bin/# Windows
$tag = "v0.2.0"
$target = "x86_64-pc-windows-msvc"
Invoke-WebRequest "https://github.com/udaysinh-git/avar/releases/download/$tag/avar-$tag-$target.zip" `
-OutFile avar.zip
Expand-Archive avar.zip -DestinationPath .
# Move avar.exe somewhere on PATH.Both build paths produce a single static binary. No background service, no daemon.
avar init # create vault + set passphrase
avar add PASSWORD # piped or prompted
avar project init PASSWORD # tell this project which secrets it uses
avar unlock # prints: export PASSWORD='...'
eval "$(avar unlock)" # or this, to actually set them in your shell
avar run -- npm start # or this, to inject into a child commandOn the project owner's machine:
avar init # if not done already
avar add PASSWORD # local vault entry
avar project init PASSWORD
avar bundle init # creates .avar/secrets.bundle, you are the only recipient
avar bundle add PASSWORD # pulls from vault, encrypts into bundleTeammate sends you their public key (from avar bundle share on their machine):
avar bundle share --add age1xyz...
git add .avar && git commit -m "share secrets with teammate"On the teammate's machine, after pulling:
avar bundle import # decrypts, shows you what's in it, prompts y/N
avar unlock # works β sources from the bundle, not your local vault# in ~/.bashrc or ~/.zshrc
eval "$(avar hook bash)"# in $PROFILE
Invoke-Expression (& avar hook pwsh | Out-String)After that, cding into any avar project loads its secrets, and cding out unsets them. Passphrase is prompted at most once per project transition.
Vault (local):
avar initβ create the vault and set the passphrase.avar add NAMEβ add a secret (value from stdin / prompt).avar get NAMEβ print a secret to stdout.avar list/avar remove NAME.
Project:
avar project init [NAMES...]β declare which vault secrets this project uses (writes.avar/project.toml).avar env list | add NAME [SECRETS...] | remove NAMEβ manage named environments.
Activation:
avar unlock [--shell bash|zsh|fish|pwsh] [--env NAME]β print shell-export lines for the project's secrets.avar run [--env NAME] -- <cmd> [args...]β run a command with secrets injected; values never appear in any stream.avar hook <bash|zsh|fish|pwsh>β emit the rc-file install snippet for auto-activation oncd.avar export <shell>/avar deactivateβ used by the hook to diff against / clear the previously-loaded project.
Bundle (team):
avar bundle init [--recipient AGE_KEY]...β create the bundle, you + extras as recipients.avar bundle add NAME/avar bundle remove NAMEβ copy a secret from your vault into the bundle, or drop it.avar bundle share [--add KEY | --remove KEY]β no args: print your public key. With flags: manage recipients.avar bundle import [--trust]β first-time explicit trust of a bundle someone shared with you.avar bundle inspect [PATH]β show recipients, creator, signature, secret names, sha256 β without recording trust or echoing values.avar bundle unlock [--shell] [--env]β bundle-mode unlock.
Identity (per-user X25519 + Ed25519 keypair, auto-generated on first bundle command):
avar identity show | exportβ print your public / private key (private goes to stderr with a warning).avar identity generateβ print a fresh keypair to stdout without touching disk; for minting CI / service identities.avar identity import [--force]β read an age secret key from stdin and store it as this machine's identity.avar identity rotate [--dry-run]β replace your keypair; re-encrypts and re-signs bundles you created, lists external bundles that need the owner's action.
Audit (tamper-evident local log):
avar audit log [--last N]/avar audit verifyβ read entries or walk the chain.avar audit prune --before <RFC3339>β archive old entries, re-chain the kept tail.avar audit export [--format csv|json]β emit for grep / jq.
Trust + diagnostics:
avar trust list/avar trust revoke <path>β manage the on-disk trust store.avar doctorβ read-only diagnostic dump (vault, identity, trust, audit chain, project context). Never prompts.
.avar/project.toml:
version = 1
# Simple mode
secrets = ["PASSWORD", "API_KEY"]
# OR multi-env (mutually exclusive with top-level secrets):
default_env = "dev"
[env.dev]
secrets = ["PASSWORD"]
[env.prod]
secrets = ["PASSWORD", "DATADOG_KEY"]
# When using a bundle (added automatically by `avar bundle init`):
bundle = ".avar/secrets.bundle"Env selection: --env flag β AVAR_ENV env var β default_env field. The shell hook respects AVAR_ENV and re-loads on env change.
Two independent trust gates, both stored in $AVAR_HOME/trusted_projects.toml:
- Project trust β keyed on
(canonical project root, sha256(project.toml)). Auto-recorded byproject init(typing names = consent). Prompts on first encounter or content change.--trustflag andAVAR_TRUST=yesenv var accept non-interactively. - Bundle trust β keyed on
(canonical project root, sha256(bundle file)). Never auto-prompts on the recipient side β onlybundle init(creator) andbundle import(recipient explicit consent) record bundle trust. A changed bundle bails with "runavar bundle import" rather than silently re-prompting.
For interactive use you don't need any of these.
AVAR_HOMEβ override the vault location (default is the platform's per-user config dir).AVAR_PASSPHRASEβ supply the passphrase non-interactively (CI / scripts).AVAR_IDENTITYβ supply anAGE-SECRET-KEY-1...private key directly. Bypasses on-disk identity entirely; identity-only bundle ops (init,share,import,unlock) need no vault at all. The CI path.AVAR_TRUSTβ accept project-trust prompts non-interactively (yes/y/true/1).AVAR_ENVβ pick an environment when the project has multiple.
- Modern authenticated encryption (scrypt + ChaCha20-Poly1305 for the vault; age for bundles).
- Each bundle carries an Ed25519 signature by the writer over its canonical bytes; decrypt verifies against the embedded creator pubkey. A creator change between trust events is surfaced to the recipient as
*** CREATOR CHANGED ***. - No plaintext persistence; values stay in process memory only.
- Session-only environment injection; values are cleared on
cdout. - Per-user X25519 + Ed25519 keypair; no passphrase shared between users.
- Explicit trust on first use for projects and bundles.
- Vault entries' AEAD tag detects tampering. Each encryption uses fresh salt + nonce.
- Append-only sha256-chained audit log;
avar audit verifywalks the chain. - Windows DACL hardening on the canary file (inheritance broken, current-user-only ACE); CI asserts this on every push.
Latest tag: v0.2.0. Phases 1 β 3 of the design doc are essentially complete: local vault, project activation, multi-env, shell hook (bash/zsh/fish/pwsh), signed multi-recipient bundles, identity rotate, CI / service-identity flow (AVAR_IDENTITY), tamper-evident audit log with prune + export, doctor + bundle inspect, explicit two-gate trust.
Next: TUI, pluggable sync backends.
This is pre-1.0. Format versions are pinned but may evolve. Issues and PRs welcome.
Apache License 2.0.
Built by WeLabs, focused on developer-first infrastructure.