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.