ev - Local Encrypted Secret Manager
Project Overview
ev is a local encrypted secret manager designed for modern AI-native development workflows. It securely stores secrets outside of your project directory, encrypting them locally and only making them available when your application runs.
Key Features
- Local Encryption: Secrets are encrypted on your machine before storage
- No Cloud Dependency: Operates entirely locally without requiring a background service
- AI-Safe: Prevents AI coding agents from accessing sensitive data by keeping secrets out of the project tree
- Multi-Language Support: Works with Go, JavaScript, Python, Terraform, and other ecosystems
- 1Password Integration: Optional sync for encrypted off-site backup
- GitWall Cloud Sync: Optional self-hosted, end-to-end encrypted backup and multi-device sync
- Developer Experience: Seamless integration with
uv,go,npm, IDE run configurations, and AI tools
Problem Solved
Traditional secret management approaches (.env files, secrets.tfvars, etc.) expose sensitive data to:
- Version control systems
- AI coding assistants that scan project directories
- Accidental commits or leaks
ev solves this by:
- Storing secrets in an encrypted vault outside the project directory
- Only decrypting them at runtime
- Maintaining a minimal
.envaultmarker file in the project
Architecture & Components
File Structure
ev/
├── cmd/ # CLI command implementations
├── detector/ # Secret detection and scanning
├── vault/ # Core encryption and storage logic
├── web/ # Web interface components
├── main.go # Entry point
├── go.mod # Go module definition
└── ... # Supporting files
Core Components
-
Vault System (
vault/):- Encryption/decryption using Go's
x/cryptopackage - Local storage in
~/.envault/vault.json - Key management and rotation
- Encryption/decryption using Go's
-
CLI Interface (
cmd/):- Built with Cobra framework
- Commands for secret management, sync, and project setup
- Version management via build flags
-
Secret Detection (
detector/):- Scans project files for potential secrets
- Prevents accidental commits of sensitive data
-
Web Components (
web/):- Optional web interface for management
- JavaScript/HTML frontend components
-
Installation Scripts:
install.sh/install.ps1: Cross-platform installationsetup.sh/setup.ps1: Initial configuration
Data Flow
-
Project Initialization:
graph LR A[Project Directory] -->|creates| B[.envault marker] B -->|references| C[~/.envault/vault.json] -
Runtime Access:
sequenceDiagram participant App participant ev participant Vault App->>ev: Request secrets ev->>Vault: Decrypt with local key Vault-->>ev: Plaintext secrets ev-->>App: Inject environment
Getting Started
Prerequisites
- Go 1.25+ (for development)
- Node.js 18+ (for web components)
- Git
Installation
Homebrew (Recommended)
brew install envault/tap/ev
Manual Installation
# Linux/macOS
curl -fsSL https://raw.githubusercontent.com/envault/ev/main/install.sh | bash
# Windows (PowerShell)
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/envault/ev/main/install.ps1" -OutFile install.ps1
.\install.ps1
From Source
git clone https://github.com/envault/ev.git
cd ev
make install
Initial Setup
- Initialize a new vault:
ev init
- Create your first project:
ev project add my-project
- Add secrets to the project:
ev secret add my-project DB_PASSWORD=s3cr3t
ev secret add my-project API_KEY=12345-abcde
- Link a project directory:
cd ~/projects/my-app
ev link
Running Locally
Start the development server (for web interface):
make web
Run the CLI:
ev --help
Configuration
Environment Variables
| Variable | Description | Default |
|---|---|---|
EVAULT_DIR |
Vault storage directory | ~/.envault |
EVAULT_KEY |
Encryption key (not recommended) | - |
EVAULT_1PASSWORD |
Enable 1Password sync | false |
EVAULT_GITWALL |
GitWall sync endpoint | - |
Configuration Files
- Vault Configuration (
~/.envault/config.json):
{
"version": "1.0",
"encryption": {
"algorithm": "aes-256-gcm",
"key_rotation": "90d"
},
"sync": {
"1password": false,
"gitwall": {
"enabled": false,
"endpoint": ""
}
}
}
- Project Marker (
.envault):
project: my-project
version: 1
Command-Line Options
ev [command] [flags]
Global flags:
--config string: Path to config file--vault string: Path to vault directory--debug: Enable debug logging
API / Usage Reference
Core Commands
ev init
Initialize a new vault
ev init [flags]
Flags:
--force: Overwrite existing vault--key string: Provide encryption key
ev project
Project management commands
ev project [command]
Subcommands:
add <name>: Create new projectlist: List all projectsremove <name>: Delete projectrename <old> <new>: Rename project
ev secret
Secret management commands
ev secret [command] [project]
Subcommands:
add <project> <key=value>: Add secretget <project> <key>: Retrieve secretlist <project>: List all secretsremove <project> <key>: Delete secretexport <project>: Export secrets as environment variables
ev link
Link current directory to a project
ev link [project]
ev sync
Synchronization commands
ev sync [command]
Subcommands:
1password: Sync with 1Passwordgitwall: Sync with GitWallstatus: Show sync status
ev detect
Scan for secrets in project files
ev detect [path]
Flags:
--fix: Automatically remove detected secrets--json: Output as JSON
Programmatic Usage
Go API
package main
import (
"fmt"
"envault/vault"
)
func main() {
// Initialize vault
v, err := vault.Open("~/.envault")
if err != nil {
panic(err)
}
// Add secret
err = v.AddSecret("my-project", "API_KEY", "12345-abcde")
if err != nil {
panic(err)
}
// Retrieve secret
value, err := v.GetSecret("my-project", "API_KEY")
if err != nil {
panic(err)
}
fmt.Println(value)
}
JavaScript API
import { EvClient } from 'ev/web';
const client = new EvClient();
// Add secret
await client.addSecret('my-project', 'API_KEY', '12345-abcde');
// Get secret
const value = await client.getSecret('my-project', 'API_KEY');
console.log(value);
Integration Examples
Python Project
# app.py
import os
import subprocess
# Load secrets at runtime
subprocess.run(["ev", "secret", "export", "my-project"], check=True)
# Access secrets
db_password = os.getenv("DB_PASSWORD")
Go Project
package main
import (
"log"
"os"
"os/exec"
)
func main() {
// Load secrets
cmd := exec.Command("ev", "secret", "export", "my-project")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
// Access secrets
apiKey := os.Getenv("API_KEY")
}
npm Scripts
{
"scripts": {
"start": "ev secret export my-project && node app.js",
"dev": "ev secret export my-project && nodemon app.js"
}
}
Contributing
Development Setup
- Clone the repository:
git clone https://github.com/envault/ev.git
cd ev
- Install dependencies:
make deps
- Build the project:
make build
Code Style
-
Go:
- Follow Effective Go
- Use
gofmtfor formatting - Lint with
golangci-lint
-
JavaScript:
- Follow StandardJS
- Use Prettier for formatting
-
Shell:
- Follow ShellCheck guidelines
- Use
shfmtfor formatting
Testing
Run all tests:
make test
Run specific test suites:
# Go tests
make test-go
# JavaScript tests
make test-js
# Integration tests
make test-integration
Pull Request Process
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Release Process
- Update
VERSIONfile - Update
CHANGELOG.md - Create a tag:
git tag -a v1.2.3 -m "Release v1.2.3" git push origin v1.2.3 - Build release artifacts:
make release
Code of Conduct
This project follows the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code.