Envoy
Envoy is a secure, Git-like CLI for managing encrypted environment files across machines and teams.
It lets you encrypt once, sync safely, and restore automatically — without ever committing secrets to Git.
Why Envoy?
Managing .env files across devices is painful:
- You can’t commit them
- Copying them manually is error-prone
- Sharing them securely is hard
- CI environments need controlled access
Envoy solves this by treating secrets like versioned artifacts, not source code.
Core Concepts
Envoy is built around a few simple ideas:
- Secrets are encrypted locally (never plaintext on the server)
- One project passphrase restores managed files
- Each managed file gets a unique derived encryption key
- Encrypted blobs are content-addressed (SHA-256)
- Commits track manifest history (like Git)
- File access can be restricted to selected project members
- Git tracks intent, not data
- Cache is disposable
- Remotes behave like Git remotes
If you understand Git, Envoy will feel familiar.
Installation
Quick Install
macOS/Linux:
|
Windows (PowerShell):
iwr -useb https://raw.githubusercontent.com/denizlg24/envoy/master/install.ps1 | iex
From Source
Requirements
- Rust (stable)
- Cargo
Or build locally:
Authentication
Envoy uses GitHub OAuth (device flow).
This stores an API token in:
Logout at any time:
Getting Started
1. Initialize a project
This creates the .envoy/ directory and sets up the default remote (origin).
2. Stage files
add encrypts and stages a file (default .env) with the project passphrase.
Run it again after editing, just like git add.
envy encrypt remains available for backwards-compatible per-file passphrases.
3. Commit changes
- Creates an encrypted commit object
- Links to the current manifest state
- Updates local HEAD
4. Push to remote
- Uploads encrypted blobs and commits
- Updates remote HEAD
5. Pull and restore secrets
- Downloads encrypted blobs and commits
- Decrypts them locally
- Restores files to their original paths
6. Check status
- Shows current manifest state
- Displays uncommitted changes
- Fetches remote to show sync status
7. Inspect changes
Envoy shows variable names but redacts values by default. Use
--show-secrets only when plaintext terminal output is acceptable.
8. Remove a tracked file
This stages the deletion and deletes the working-tree file. Add --cached to
stop tracking while keeping the local file. Pull applies committed deletions,
but refuses to delete a locally modified managed file.
9. Restrict a file to selected members
Use the internal user IDs shown by envy member list:
The project owner publishes access changes with the next commit and push.
Quick demos
The following animated demos show common Envoy workflows.
Initialize a project

Encrypt a file

Pull and restore secrets

Configuration
Project config (tracked)
.envoy/config.toml
= 1
= "..."
= "..."
= "origin"
[]
= "https://envoy-cli.vercel.app/api"
Local state (not tracked)
.envoy/HEAD # Current commit hash
.envoy/refs/remotes/origin/HEAD # Remote HEAD
.envoy/latest # Current manifest blob hash
.envoy/cache/ # Encrypted blobs and commits
$HOME/.envoy/sessions.json # Encrypted, expiring project-key sessions
Commands
| Command | Description |
|---|---|
envy init |
Initialize a new project |
envy add |
Encrypt and stage a file with the project passphrase |
envy encrypt |
Legacy per-file passphrase encryption |
envy rm / envy remove |
Stage a deletion and delete the working file |
envy diff [--cached] |
Show redacted working or staged changes |
envy commit -m "msg" |
Create a commit |
envy log |
View commit history |
envy status |
Show current state |
envy push |
Push commits to remote |
envy pull |
Pull and restore secrets |
envy access ... |
Manage per-file member access |
envy member ... |
Manage project members |
envy login |
Authenticate with GitHub |
envy logout |
Clear authentication |
Non-interactive automation
Every command input can be supplied as an argument or as a newline-delimited
key=value record on stdin. Arguments take precedence over piped values, and
values may contain = characters.
|
Managed files need only the project passphrase:
|
For legacy files created with envy encrypt, map their passphrases explicitly:
|
Use file:*=shared-passphrase when every file uses the same passphrase. The
equivalent arguments are --file-passphrase "FILE=PASSPHRASE" (repeatable) and
--file-passphrase-all PASSPHRASE.
Prefer stdin for secrets because command-line values may be visible in shell
history and process listings. See skills/use-envoy/SKILL.md
for the complete agent-oriented input matrix.
For isolated tests, set ENVOY_HOME to a temporary directory and
ENVOY_NO_UPDATE_CHECK=1.
Security Model
- Encryption happens client-side only
- Keys are derived using Argon2id (memory-hard)
- Managed file keys are derived independently with HKDF-SHA-256 and a random salt
- Data is encrypted using XChaCha20-Poly1305 (AEAD)
- Blobs are content-addressed via SHA-256
- Commits are encrypted and linked by parent hash
- Server never sees plaintext or keys
- Change detection uses plaintext hashes inside the encrypted manifest
- Legacy manifest v1 and per-file passphrase blobs remain readable
Envoy is designed so the server is untrusted by default.
For detailed cryptographic analysis, see IMPLEMENTATION_SECURITY.md.
License
MIT