envoy-cli 0.5.0

A Git-like CLI for managing encrypted environment files
envoy-cli-0.5.0 is not a library.

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:

curl -fsSL https://raw.githubusercontent.com/denizlg24/envoy/master/install.sh | bash

Windows (PowerShell):

iwr -useb https://raw.githubusercontent.com/denizlg24/envoy/master/install.ps1 | iex

From Source

Requirements

  • Rust (stable)
  • Cargo
cargo install envoy-cli

Or build locally:

cargo build --release


Authentication

Envoy uses GitHub OAuth (device flow).

envy login

This stores an API token in:

$HOME/.envoy/config.toml

Logout at any time:

envy logout


Getting Started

1. Initialize a project

envy init

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 add
envy add --input .env.testing

envy encrypt remains available for backwards-compatible per-file passphrases.

3. Commit changes

envy commit -m "Add production secrets"

  • Creates an encrypted commit object
  • Links to the current manifest state
  • Updates local HEAD

4. Push to remote

envy push

  • Uploads encrypted blobs and commits
  • Updates remote HEAD

5. Pull and restore secrets

envy pull

  • Downloads encrypted blobs and commits
  • Decrypts them locally
  • Restores files to their original paths

6. Check status

envy status

  • Shows current manifest state
  • Displays uncommitted changes
  • Fetches remote to show sync status

7. Inspect changes

envy diff              # working tree versus staged files
envy diff --cached     # staged files versus HEAD

Envoy shows variable names but redacts values by default. Use --show-secrets only when plaintext terminal output is acceptable.

8. Remove a tracked file

envy rm --input .env.testing

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:

envy access grant .env.production USER_ID
envy access revoke .env.production USER_ID
envy access list .env.production
envy access unrestrict .env.production

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

Init demo

Encrypt a file

Encrypt demo

Pull and restore secrets

Pull demo


Configuration

Project config (tracked)

.envoy/config.toml



version = 1

project_id = "..."

name = "..."



default_remote = "origin"



[remotes]

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.

printf '%s\n' \
  'input=.env.production' \
  'passphrase=project-passphrase' |
  envy add

Managed files need only the project passphrase:

printf '%s\n' 'passphrase=project-passphrase' | envy pull

For legacy files created with envy encrypt, map their passphrases explicitly:

printf '%s\n' \
  'passphrase=project-passphrase' \
  'file:.env=development-passphrase' \
  'file:.env.production=production-passphrase' |
  envy pull

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