"Are you the Keymaster?" — Zuul, Ghostbusters (1984)
A CLI tool for managing secrets across multiple environments, with pluggable backend storage.
Homebrew (macOS/Linux):
brew install farmisen/tap/zuul-secretsShell installer (macOS/Linux):
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/farmisen/zuul/releases/latest/download/zuul-secrets-installer.sh | shFrom source:
cargo install zuul-secretsPre-built binaries are available for macOS (Intel + Apple Silicon) and Linux (x86_64, ARM64, musl) on the Releases page.
- Multi-environment — Manage secrets across
dev,staging,production, and any custom environments - Pluggable backends — GCP Secret Manager for teams, encrypted local file for solo/offline use
- Export formats — Output secrets as dotenv, direnv, JSON, YAML, or shell exports
- Run with secrets — Inject secrets into any subprocess via
zuul run - Import — Bulk-import from
.env, JSON, or YAML files - Local overrides — Override backend values locally via
.zuul.local.toml(never leaves your machine) - Metadata — Attach key-value metadata (owner, rotate-by, description) to secrets
- Crash recovery — Batch operations are journaled;
zuul recoverresumes interrupted work
| Backend | Config type |
Best for | Docs |
|---|---|---|---|
| File | file |
Local dev, small projects, offline use | backend-file.md |
| GCP Secret Manager | gcp-secret-manager |
Teams, CI/CD, IAM-based access control | backend-gcp.md |
cargo install --path .
zuul init --backend file
# Choose: identity file (recommended) or passphrase
zuul env create dev
zuul secret set DATABASE_URL --env dev "postgres://localhost/mydb"
zuul run --env dev -- cargo runcargo install --path .
# Provision infrastructure
cd terraform
cp terraform.tfvars.example terraform.tfvars # edit with your values
terraform init && terraform apply
cd ..
# Initialize and authenticate
zuul init --project my-gcp-project-123
zuul auth
# Manage secrets (environments created by Terraform)
zuul secret set DATABASE_URL --env dev "postgres://localhost:5432/mydb"
zuul run --env dev -- cargo runCreated by zuul init. Committed to version control.
File backend:
[backend]
type = "file"
[defaults]
environment = "dev"GCP backend:
[backend]
type = "gcp-secret-manager"
project_id = "my-gcp-project-123"
[defaults]
environment = "dev"Local overrides for development. Added to .gitignore automatically.
# Per-developer backend overrides (e.g., different credential path)
[backend]
credentials = "~/.zuul/my-personal-sa.json"
# Secret value overrides for local development
[secrets]
DATABASE_URL = "postgres://localhost:5432/mydb_local"
REDIS_URL = "redis://localhost:6379"The [backend] section overrides fields from .zuul.toml — useful when team members store credentials at different paths. Supports: project_id, credentials, path, identity.
Secret overrides from [secrets] are not applied by default. Use --overrides with zuul export or zuul run to merge them.
Add this to your .envrc for automatic secret loading:
eval "$(zuul export --env dev --export-format direnv)"See .envrc.example for a ready-to-use template.
| Command | Description |
|---|---|
zuul init |
Initialize a new project |
zuul auth |
Set up backend authentication |
zuul env list|create|show|update|delete|copy|clear |
Manage environments |
zuul secret list|get|set|delete|info|copy |
Manage secrets |
zuul secret metadata list|set|delete |
Manage secret metadata |
zuul export |
Export secrets in various formats |
zuul run |
Run a command with secrets injected |
zuul import |
Bulk-import secrets from a file |
zuul diff |
Compare secrets between two environments |
zuul recover status|resume|abort |
Inspect or resume incomplete batch operations |
zuul deploy fly |
Deploy to Fly.io with secrets synced and injected |
zuul sync netlify |
Sync secrets to Netlify's environment variables |
zuul sync fly |
Sync secrets to Fly.io |
zuul audit |
Show who has access to secrets (GCP backend only) |
zuul completions <shell> |
Generate shell completions (bash, zsh, fish, etc.) |
Use zuul --help or zuul <command> --help for details.
Notable flags:
zuul secret list --with-metadata— include metadata key-value pairs in the outputzuul sync fly --stage— stage secrets without redeploying (runfly secrets deploylater)--format text|jsoncontrols the output mode (text tables or JSON).--export-formatand--import-formatcontrol the file serialization format (dotenv, json, yaml, etc.) — these are separate concerns.
Note: env create/update/delete work directly with the file backend. For GCP, environments are managed by Terraform — these commands return an error directing you to terraform apply.
Common (all backends):
| Variable | Description |
|---|---|
ZUUL_DEFAULT_ENV |
Override default environment name |
ZUUL_BACKEND |
Override backend type |
File backend:
| Variable | Description |
|---|---|
ZUUL_KEY_FILE |
Path to an age identity file (recommended) |
ZUUL_PASSPHRASE |
Passphrase for scrypt-based encryption (fallback) |
GCP backend:
| Variable | Description |
|---|---|
ZUUL_GCP_PROJECT |
Override GCP project ID |
ZUUL_GCP_CREDENTIALS |
GCP service account key: file path or inline JSON |
Resolution order (highest priority first): CLI flags → environment variables → .zuul.local.toml (secrets only) → .zuul.toml → built-in defaults.
# Build
cargo build
# Lint and format
cargo clippy -- -D warnings
cargo fmtUnit and file-backend tests run without any external dependencies:
cargo testGCP emulator tests run against a GCP Secret Manager emulator:
# Start the emulator
docker compose -f docker-compose.emulator.yml up -d
# Run the GCP integration suite
cargo test --test gcp_emulator -- --ignored
# Stop the emulator when done
docker compose -f docker-compose.emulator.yml downInstall cargo-release (one-time):
cargo install cargo-releasePublish a release:
# Patch release (0.1.0 → 0.1.1)
cargo release patch --execute
# Minor release (0.1.0 → 0.2.0)
cargo release minor --execute
# Specific version
cargo release 0.2.0 --executeThis bumps the version in Cargo.toml, commits, tags vX.Y.Z, and pushes. The release workflow then automatically:
- Builds binaries for macOS (Intel + Apple Silicon) and Linux (x86_64, ARM64, musl)
- Creates a GitHub Release with binaries and checksums
- Updates the Homebrew formula at
farmisen/homebrew-tap - Generates a shell installer script
